diff --git a/pkg/auth/handlers/handlers.go b/pkg/auth/handlers/handlers.go index ac316763ab9c8..d005752f16a7c 100644 --- a/pkg/auth/handlers/handlers.go +++ b/pkg/auth/handlers/handlers.go @@ -18,12 +18,29 @@ package handlers import ( "net/http" + "strings" "github.com/golang/glog" + "github.com/prometheus/client_golang/prometheus" + "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/auth/authenticator" ) +var ( + authenticatedUserCounter = prometheus.NewCounterVec( + prometheus.CounterOpts{ + Name: "authenticated_user_requests", + Help: "Counter of authenticated requests broken out by username.", + }, + []string{"username"}, + ) +) + +func init() { + prometheus.MustRegister(authenticatedUserCounter) +} + // NewRequestAuthenticator creates an http handler that tries to authenticate the given request as a user, and then // stores any such user found onto the provided context for the request. If authentication fails or returns an error // the failed handler is used. On success, handler is invoked to serve the request. @@ -44,6 +61,8 @@ func NewRequestAuthenticator(mapper api.RequestContextMapper, auth authenticator mapper.Update(req, api.WithUser(ctx, user)) } + authenticatedUserCounter.WithLabelValues(compressUsername(user.GetName())).Inc() + handler.ServeHTTP(w, req) }), ) @@ -66,3 +85,25 @@ func unauthorizedBasicAuth(w http.ResponseWriter, req *http.Request) { func unauthorized(w http.ResponseWriter, req *http.Request) { http.Error(w, "Unauthorized", http.StatusUnauthorized) } + +// compressUsername maps all possible usernames onto a small set of categories +// of usernames. This is done both to limit the cardinality of the +// authorized_user_requests metric, and to avoid pushing actual usernames in the +// metric. +func compressUsername(username string) string { + switch { + // Known internal identities. + case username == "admin" || + username == "client" || + username == "kube_proxy" || + username == "kubelet" || + username == "system:serviceaccount:kube-system:default": + return username + // Probably an email address. + case strings.Contains(username, "@"): + return "email_id" + // Anything else (custom service accounts, custom external identities, etc.) + default: + return "other" + } +} diff --git a/pkg/metrics/api_server_metrics.go b/pkg/metrics/api_server_metrics.go index 952572ae697a3..81521bbc1016c 100644 --- a/pkg/metrics/api_server_metrics.go +++ b/pkg/metrics/api_server_metrics.go @@ -30,6 +30,7 @@ var KnownApiServerMetrics = map[string][]string{ "apiserver_request_latencies_summary": {"verb", "resource", "quantile"}, "apiserver_request_latencies_summary_count": {"verb", "resource"}, "apiserver_request_latencies_summary_sum": {"verb", "resource"}, + "authenticated_user_requests": {"username"}, "etcd_helper_cache_entry_count": {}, "etcd_helper_cache_hit_count": {}, "etcd_helper_cache_miss_count": {},