k8s.io/apiserver@v0.31.1/pkg/endpoints/filters/metrics.go (about) 1 /* 2 Copyright 2020 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package filters 18 19 import ( 20 "context" 21 "strings" 22 "time" 23 24 "k8s.io/apiserver/pkg/authorization/authorizer" 25 26 "k8s.io/apiserver/pkg/authentication/authenticator" 27 "k8s.io/component-base/metrics" 28 "k8s.io/component-base/metrics/legacyregistry" 29 ) 30 31 /* 32 * By default, all the following metrics are defined as falling under 33 * ALPHA stability level https://github.com/kubernetes/enhancements/blob/master/keps/sig-instrumentation/1209-metrics-stability/kubernetes-control-plane-metrics-stability.md#stability-classes) 34 * 35 * Promoting the stability level of the metric is a responsibility of the component owner, since it 36 * involves explicitly acknowledging support for the metric across multiple releases, in accordance with 37 * the metric stability policy. 38 */ 39 const ( 40 successLabel = "success" 41 failureLabel = "failure" 42 errorLabel = "error" 43 44 allowedLabel = "allowed" 45 deniedLabel = "denied" 46 noOpinionLabel = "no-opinion" 47 ) 48 49 var ( 50 authenticatedUserCounter = metrics.NewCounterVec( 51 &metrics.CounterOpts{ 52 Name: "authenticated_user_requests", 53 Help: "Counter of authenticated requests broken out by username.", 54 StabilityLevel: metrics.ALPHA, 55 }, 56 []string{"username"}, 57 ) 58 59 authenticatedAttemptsCounter = metrics.NewCounterVec( 60 &metrics.CounterOpts{ 61 Name: "authentication_attempts", 62 Help: "Counter of authenticated attempts.", 63 StabilityLevel: metrics.ALPHA, 64 }, 65 []string{"result"}, 66 ) 67 68 authenticationLatency = metrics.NewHistogramVec( 69 &metrics.HistogramOpts{ 70 Name: "authentication_duration_seconds", 71 Help: "Authentication duration in seconds broken out by result.", 72 Buckets: metrics.ExponentialBuckets(0.001, 2, 15), 73 StabilityLevel: metrics.ALPHA, 74 }, 75 []string{"result"}, 76 ) 77 78 authorizationAttemptsCounter = metrics.NewCounterVec( 79 &metrics.CounterOpts{ 80 Name: "authorization_attempts_total", 81 Help: "Counter of authorization attempts broken down by result. It can be either 'allowed', 'denied', 'no-opinion' or 'error'.", 82 StabilityLevel: metrics.ALPHA, 83 }, 84 []string{"result"}, 85 ) 86 87 authorizationLatency = metrics.NewHistogramVec( 88 &metrics.HistogramOpts{ 89 Name: "authorization_duration_seconds", 90 Help: "Authorization duration in seconds broken out by result.", 91 Buckets: metrics.ExponentialBuckets(0.001, 2, 15), 92 StabilityLevel: metrics.ALPHA, 93 }, 94 []string{"result"}, 95 ) 96 ) 97 98 func init() { 99 legacyregistry.MustRegister(authenticatedUserCounter) 100 legacyregistry.MustRegister(authenticatedAttemptsCounter) 101 legacyregistry.MustRegister(authenticationLatency) 102 legacyregistry.MustRegister(authorizationAttemptsCounter) 103 legacyregistry.MustRegister(authorizationLatency) 104 } 105 106 func recordAuthorizationMetrics(ctx context.Context, authorized authorizer.Decision, err error, authStart time.Time, authFinish time.Time) { 107 var resultLabel string 108 109 switch { 110 case authorized == authorizer.DecisionAllow: 111 resultLabel = allowedLabel 112 case err != nil: 113 resultLabel = errorLabel 114 case authorized == authorizer.DecisionDeny: 115 resultLabel = deniedLabel 116 case authorized == authorizer.DecisionNoOpinion: 117 resultLabel = noOpinionLabel 118 } 119 120 authorizationAttemptsCounter.WithContext(ctx).WithLabelValues(resultLabel).Inc() 121 authorizationLatency.WithContext(ctx).WithLabelValues(resultLabel).Observe(authFinish.Sub(authStart).Seconds()) 122 } 123 124 func recordAuthenticationMetrics(ctx context.Context, resp *authenticator.Response, ok bool, err error, apiAudiences authenticator.Audiences, authStart time.Time, authFinish time.Time) { 125 var resultLabel string 126 127 switch { 128 case err != nil || (resp != nil && !audiencesAreAcceptable(apiAudiences, resp.Audiences)): 129 resultLabel = errorLabel 130 case !ok: 131 resultLabel = failureLabel 132 default: 133 resultLabel = successLabel 134 authenticatedUserCounter.WithContext(ctx).WithLabelValues(compressUsername(resp.User.GetName())).Inc() 135 } 136 137 authenticatedAttemptsCounter.WithContext(ctx).WithLabelValues(resultLabel).Inc() 138 authenticationLatency.WithContext(ctx).WithLabelValues(resultLabel).Observe(authFinish.Sub(authStart).Seconds()) 139 } 140 141 // compressUsername maps all possible usernames onto a small set of categories 142 // of usernames. This is done both to limit the cardinality of the 143 // authorized_user_requests metric, and to avoid pushing actual usernames in the 144 // metric. 145 func compressUsername(username string) string { 146 switch { 147 // Known internal identities. 148 case username == "admin" || 149 username == "client" || 150 username == "kube_proxy" || 151 username == "kubelet" || 152 username == "system:serviceaccount:kube-system:default": 153 return username 154 // Probably an email address. 155 case strings.Contains(username, "@"): 156 return "email_id" 157 // Anything else (custom service accounts, custom external identities, etc.) 158 default: 159 return "other" 160 } 161 }