@@ -32,12 +32,6 @@ import (
3232 "k8s.io/apimachinery/pkg/api/meta"
3333 "k8s.io/apimachinery/pkg/runtime"
3434 kerrors "k8s.io/apimachinery/pkg/util/errors"
35- "k8s.io/apiserver/pkg/authentication/authenticatorfactory"
36- "k8s.io/apiserver/pkg/authorization/authorizer"
37- "k8s.io/apiserver/pkg/authorization/authorizerfactory"
38- "k8s.io/apiserver/pkg/server/options"
39- authenticationv1 "k8s.io/client-go/kubernetes/typed/authentication/v1"
40- authorizationv1 "k8s.io/client-go/kubernetes/typed/authorization/v1"
4135 "k8s.io/client-go/rest"
4236 "k8s.io/client-go/tools/leaderelection"
4337 "k8s.io/client-go/tools/leaderelection/resourcelock"
@@ -93,19 +87,14 @@ type controllerManager struct {
9387 // metricsListener is used to serve prometheus metrics
9488 metricsListener net.Listener
9589
96- // metricsSecureServing enables secure metrics serving.
97- // This means metrics will be served via https and with authentication and authorization.
98- metricsSecureServing bool
90+ // metricsFilter is a func that is added before the metrics handler on the metrics server.
91+ // This can be e.g. used to enforce authentication and authorization on the metrics
92+ // endpoint.
93+ metricsFilter metrics.Filter
9994
10095 // metricsExtraHandlers contains extra handlers to register on http server that serves metrics.
10196 metricsExtraHandlers map [string ]http.Handler
10297
103- // metricsAuthenticationClient is the client used to authenticate requests to the metrics endpoint.
104- metricsAuthenticationClient authenticationv1.AuthenticationV1Interface
105-
106- // metricsAuthorizationClient is the client used to authorize requests to the metrics endpoint.
107- metricsAuthorizationClient authorizationv1.AuthorizationV1Interface
108-
10998 // healthProbeListener is used to serve liveness probe
11099 healthProbeListener net.Listener
111100
@@ -322,17 +311,24 @@ func (cm *controllerManager) addMetricsServer() error {
322311
323312 log := cm .logger .WithValues ("path" , defaultMetricsEndpoint )
324313
325- if cm .metricsSecureServing {
314+ if cm .metricsFilter != nil {
326315 var err error
327- handler , err = withAuthenticationAndAuthorization ( log , cm .metricsAuthenticationClient , cm . metricsAuthorizationClient , handler )
316+ handler , err = cm .metricsFilter ( log , handler )
328317 if err != nil {
329- return fmt .Errorf ("failed to add metrics server: %w" , err )
318+ return fmt .Errorf ("failed to add metrics server: failed to add metrics filter %w" , err )
330319 }
331320 }
332-
333321 // TODO(JoelSpeed): Use existing Kubernetes machinery for serving metrics
334322 mux .Handle (defaultMetricsEndpoint , handler )
323+
335324 for path , extraHandler := range cm .metricsExtraHandlers {
325+ if cm .metricsFilter != nil {
326+ var err error
327+ extraHandler , err = cm .metricsFilter (log , extraHandler )
328+ if err != nil {
329+ return fmt .Errorf ("failed to add metrics server: failed to add metrics filter to extra handler %w" , err )
330+ }
331+ }
336332 mux .Handle (path , extraHandler )
337333 }
338334
@@ -344,74 +340,6 @@ func (cm *controllerManager) addMetricsServer() error {
344340 })
345341}
346342
347- func withAuthenticationAndAuthorization (log logr.Logger , authenticationClient authenticationv1.AuthenticationV1Interface , authorizationClient authorizationv1.AuthorizationV1Interface , handler http.Handler ) (http.Handler , error ) {
348- authenticatorConfig := authenticatorfactory.DelegatingAuthenticatorConfig {
349- Anonymous : false , // Require authentication.
350- CacheTTL : 1 * time .Minute ,
351- TokenAccessReviewClient : authenticationClient ,
352- TokenAccessReviewTimeout : 10 * time .Second ,
353- WebhookRetryBackoff : options .DefaultAuthWebhookRetryBackoff (),
354- }
355- delegatingAuthenticator , _ , err := authenticatorConfig .New ()
356- if err != nil {
357- return nil , fmt .Errorf ("failed to create authenticator: %w" , err )
358- }
359-
360- authorizerConfig := authorizerfactory.DelegatingAuthorizerConfig {
361- SubjectAccessReviewClient : authorizationClient ,
362- AllowCacheTTL : 5 * time .Minute ,
363- DenyCacheTTL : 30 * time .Second ,
364- WebhookRetryBackoff : options .DefaultAuthWebhookRetryBackoff (),
365- }
366- delegatingAuthorizer , err := authorizerConfig .New ()
367- if err != nil {
368- return nil , fmt .Errorf ("failed to create authorizer: %w" , err )
369- }
370-
371- return http .HandlerFunc (func (w http.ResponseWriter , req * http.Request ) {
372- if req .Method != http .MethodGet {
373- http .Error (w , "Method Not Allowed" , http .StatusMethodNotAllowed )
374- return
375- }
376-
377- ctx := req .Context ()
378-
379- res , ok , err := delegatingAuthenticator .AuthenticateRequest (req )
380- if err != nil {
381- log .Error (err , "Authentication failed" , err )
382- http .Error (w , "Authentication failed" , http .StatusInternalServerError )
383- return
384- }
385- if ! ok {
386- log .V (4 ).Info ("Authentication failed" )
387- http .Error (w , "Unauthorized" , http .StatusUnauthorized )
388- return
389- }
390-
391- attributes := authorizer.AttributesRecord {
392- User : res .User ,
393- Verb : "get" ,
394- Path : req .URL .Path ,
395- }
396-
397- authorized , reason , err := delegatingAuthorizer .Authorize (ctx , attributes )
398- if err != nil {
399- msg := fmt .Sprintf ("Authorization for user %s failed" , attributes .User .GetName ())
400- log .Error (err , msg )
401- http .Error (w , msg , http .StatusInternalServerError )
402- return
403- }
404- if authorized != authorizer .DecisionAllow {
405- msg := fmt .Sprintf ("Authorization denied for user %s" , attributes .User .GetName ())
406- log .V (4 ).Info (fmt .Sprintf ("%s: %s" , msg , reason ))
407- http .Error (w , msg , http .StatusForbidden )
408- return
409- }
410-
411- handler .ServeHTTP (w , req )
412- }), nil
413- }
414-
415343func (cm * controllerManager ) serveHealthProbes () {
416344 mux := http .NewServeMux ()
417345 server := httpserver .New (mux )
0 commit comments