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  }