1 package filters
2
3 import (
4 "fmt"
5 "net/http"
6 "strings"
7 "time"
8
9 "github.com/go-logr/logr"
10 "k8s.io/apimachinery/pkg/util/wait"
11 "k8s.io/apiserver/pkg/authentication/authenticatorfactory"
12 "k8s.io/apiserver/pkg/authorization/authorizer"
13 "k8s.io/apiserver/pkg/authorization/authorizerfactory"
14 authenticationv1 "k8s.io/client-go/kubernetes/typed/authentication/v1"
15 authorizationv1 "k8s.io/client-go/kubernetes/typed/authorization/v1"
16 "k8s.io/client-go/rest"
17
18 metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server"
19 )
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 func WithAuthenticationAndAuthorization(config *rest.Config, httpClient *http.Client) (metricsserver.Filter, error) {
36 authenticationV1Client, err := authenticationv1.NewForConfigAndClient(config, httpClient)
37 if err != nil {
38 return nil, err
39 }
40 authorizationV1Client, err := authorizationv1.NewForConfigAndClient(config, httpClient)
41 if err != nil {
42 return nil, err
43 }
44
45 authenticatorConfig := authenticatorfactory.DelegatingAuthenticatorConfig{
46 Anonymous: false,
47 CacheTTL: 1 * time.Minute,
48 TokenAccessReviewClient: authenticationV1Client,
49 TokenAccessReviewTimeout: 10 * time.Second,
50
51
52 WebhookRetryBackoff: &wait.Backoff{
53 Duration: 500 * time.Millisecond,
54 Factor: 1.5,
55 Jitter: 0.2,
56 Steps: 5,
57 },
58 }
59 delegatingAuthenticator, _, err := authenticatorConfig.New()
60 if err != nil {
61 return nil, fmt.Errorf("failed to create authenticator: %w", err)
62 }
63
64 authorizerConfig := authorizerfactory.DelegatingAuthorizerConfig{
65 SubjectAccessReviewClient: authorizationV1Client,
66 AllowCacheTTL: 5 * time.Minute,
67 DenyCacheTTL: 30 * time.Second,
68
69
70 WebhookRetryBackoff: &wait.Backoff{
71 Duration: 500 * time.Millisecond,
72 Factor: 1.5,
73 Jitter: 0.2,
74 Steps: 5,
75 },
76 }
77 delegatingAuthorizer, err := authorizerConfig.New()
78 if err != nil {
79 return nil, fmt.Errorf("failed to create authorizer: %w", err)
80 }
81
82 return func(log logr.Logger, handler http.Handler) (http.Handler, error) {
83 return http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
84 ctx := req.Context()
85
86 res, ok, err := delegatingAuthenticator.AuthenticateRequest(req)
87 if err != nil {
88 log.Error(err, "Authentication failed")
89 http.Error(w, "Authentication failed", http.StatusInternalServerError)
90 return
91 }
92 if !ok {
93 log.V(4).Info("Authentication failed")
94 http.Error(w, "Unauthorized", http.StatusUnauthorized)
95 return
96 }
97
98 attributes := authorizer.AttributesRecord{
99 User: res.User,
100 Verb: strings.ToLower(req.Method),
101 Path: req.URL.Path,
102 }
103
104 authorized, reason, err := delegatingAuthorizer.Authorize(ctx, attributes)
105 if err != nil {
106 msg := fmt.Sprintf("Authorization for user %s failed", attributes.User.GetName())
107 log.Error(err, msg)
108 http.Error(w, msg, http.StatusInternalServerError)
109 return
110 }
111 if authorized != authorizer.DecisionAllow {
112 msg := fmt.Sprintf("Authorization denied for user %s", attributes.User.GetName())
113 log.V(4).Info(fmt.Sprintf("%s: %s", msg, reason))
114 http.Error(w, msg, http.StatusForbidden)
115 return
116 }
117
118 handler.ServeHTTP(w, req)
119 }), nil
120 }, nil
121 }
122
View as plain text