blob: ba53fc609e03e3fd548ca208ee546a6ba3be4b96 [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001/*
2Copyright 2014 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package filters
18
19import (
20 "errors"
21 "net/http"
22 "strings"
23
24 "github.com/golang/glog"
25 "github.com/prometheus/client_golang/prometheus"
26
27 apierrors "k8s.io/apimachinery/pkg/api/errors"
28 "k8s.io/apimachinery/pkg/runtime"
29 "k8s.io/apimachinery/pkg/runtime/schema"
30 "k8s.io/apiserver/pkg/authentication/authenticator"
31 "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters"
32 genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
33)
34
35var (
36 authenticatedUserCounter = prometheus.NewCounterVec(
37 prometheus.CounterOpts{
38 Name: "authenticated_user_requests",
39 Help: "Counter of authenticated requests broken out by username.",
40 },
41 []string{"username"},
42 )
43)
44
45func init() {
46 prometheus.MustRegister(authenticatedUserCounter)
47}
48
49// WithAuthentication creates an http handler that tries to authenticate the given request as a user, and then
50// stores any such user found onto the provided context for the request. If authentication fails or returns an error
51// the failed handler is used. On success, "Authorization" header is removed from the request and handler
52// is invoked to serve the request.
53func WithAuthentication(handler http.Handler, auth authenticator.Request, failed http.Handler) http.Handler {
54 if auth == nil {
55 glog.Warningf("Authentication is disabled")
56 return handler
57 }
58 return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
59 user, ok, err := auth.AuthenticateRequest(req)
60 if err != nil || !ok {
61 if err != nil {
62 glog.Errorf("Unable to authenticate the request due to an error: %v", err)
63 }
64 failed.ServeHTTP(w, req)
65 return
66 }
67
68 // authorization header is not required anymore in case of a successful authentication.
69 req.Header.Del("Authorization")
70
71 req = req.WithContext(genericapirequest.WithUser(req.Context(), user))
72
73 authenticatedUserCounter.WithLabelValues(compressUsername(user.GetName())).Inc()
74
75 handler.ServeHTTP(w, req)
76 })
77}
78
79func Unauthorized(s runtime.NegotiatedSerializer, supportsBasicAuth bool) http.Handler {
80 return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
81 if supportsBasicAuth {
82 w.Header().Set("WWW-Authenticate", `Basic realm="kubernetes-master"`)
83 }
84 ctx := req.Context()
85 requestInfo, found := genericapirequest.RequestInfoFrom(ctx)
86 if !found {
87 responsewriters.InternalError(w, req, errors.New("no RequestInfo found in the context"))
88 return
89 }
90
91 gv := schema.GroupVersion{Group: requestInfo.APIGroup, Version: requestInfo.APIVersion}
92 responsewriters.ErrorNegotiated(apierrors.NewUnauthorized("Unauthorized"), s, gv, w, req)
93 })
94}
95
96// compressUsername maps all possible usernames onto a small set of categories
97// of usernames. This is done both to limit the cardinality of the
98// authorized_user_requests metric, and to avoid pushing actual usernames in the
99// metric.
100func compressUsername(username string) string {
101 switch {
102 // Known internal identities.
103 case username == "admin" ||
104 username == "client" ||
105 username == "kube_proxy" ||
106 username == "kubelet" ||
107 username == "system:serviceaccount:kube-system:default":
108 return username
109 // Probably an email address.
110 case strings.Contains(username, "@"):
111 return "email_id"
112 // Anything else (custom service accounts, custom external identities, etc.)
113 default:
114 return "other"
115 }
116}