blob: a845921f098bf0dac3474d0e76a7cf0970119ed5 [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001/*
2Copyright 2016 The Kubernetes Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8 http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package options
18
19import (
20 "time"
21
22 "github.com/spf13/pflag"
23
24 "k8s.io/apiserver/pkg/authorization/authorizerfactory"
25 "k8s.io/apiserver/pkg/server"
26 authorizationclient "k8s.io/client-go/kubernetes/typed/authorization/v1beta1"
27 "k8s.io/client-go/rest"
28 "k8s.io/client-go/tools/clientcmd"
29)
30
31// DelegatingAuthorizationOptions provides an easy way for composing API servers to delegate their authorization to
32// the root kube API server.
33// WARNING: never assume that every authenticated incoming request already does authorization.
34// The aggregator in the kube API server does this today, but this behaviour is not
35// guaranteed in the future.
36type DelegatingAuthorizationOptions struct {
37 // RemoteKubeConfigFile is the file to use to connect to a "normal" kube API server which hosts the
38 // SubjectAccessReview.authorization.k8s.io endpoint for checking tokens.
39 RemoteKubeConfigFile string
40
41 // AllowCacheTTL is the length of time that a successful authorization response will be cached
42 AllowCacheTTL time.Duration
43
44 // DenyCacheTTL is the length of time that an unsuccessful authorization response will be cached.
45 // You generally want more responsive, "deny, try again" flows.
46 DenyCacheTTL time.Duration
47}
48
49func NewDelegatingAuthorizationOptions() *DelegatingAuthorizationOptions {
50 return &DelegatingAuthorizationOptions{
51 // very low for responsiveness, but high enough to handle storms
52 AllowCacheTTL: 10 * time.Second,
53 DenyCacheTTL: 10 * time.Second,
54 }
55}
56
57func (s *DelegatingAuthorizationOptions) Validate() []error {
58 allErrors := []error{}
59 return allErrors
60}
61
62func (s *DelegatingAuthorizationOptions) AddFlags(fs *pflag.FlagSet) {
63 if s == nil {
64 return
65 }
66
67 fs.StringVar(&s.RemoteKubeConfigFile, "authorization-kubeconfig", s.RemoteKubeConfigFile, ""+
68 "kubeconfig file pointing at the 'core' kubernetes server with enough rights to create "+
69 " subjectaccessreviews.authorization.k8s.io.")
70
71 fs.DurationVar(&s.AllowCacheTTL, "authorization-webhook-cache-authorized-ttl",
72 s.AllowCacheTTL,
73 "The duration to cache 'authorized' responses from the webhook authorizer.")
74
75 fs.DurationVar(&s.DenyCacheTTL,
76 "authorization-webhook-cache-unauthorized-ttl", s.DenyCacheTTL,
77 "The duration to cache 'unauthorized' responses from the webhook authorizer.")
78}
79
80func (s *DelegatingAuthorizationOptions) ApplyTo(c *server.AuthorizationInfo) error {
81 if s == nil {
82 c.Authorizer = authorizerfactory.NewAlwaysAllowAuthorizer()
83 return nil
84 }
85
86 cfg, err := s.ToAuthorizationConfig()
87 if err != nil {
88 return err
89 }
90 authorizer, err := cfg.New()
91 if err != nil {
92 return err
93 }
94
95 c.Authorizer = authorizer
96 return nil
97}
98
99func (s *DelegatingAuthorizationOptions) ToAuthorizationConfig() (authorizerfactory.DelegatingAuthorizerConfig, error) {
100 sarClient, err := s.newSubjectAccessReview()
101 if err != nil {
102 return authorizerfactory.DelegatingAuthorizerConfig{}, err
103 }
104
105 ret := authorizerfactory.DelegatingAuthorizerConfig{
106 SubjectAccessReviewClient: sarClient,
107 AllowCacheTTL: s.AllowCacheTTL,
108 DenyCacheTTL: s.DenyCacheTTL,
109 }
110 return ret, nil
111}
112
113func (s *DelegatingAuthorizationOptions) newSubjectAccessReview() (authorizationclient.SubjectAccessReviewInterface, error) {
114 var clientConfig *rest.Config
115 var err error
116 if len(s.RemoteKubeConfigFile) > 0 {
117 loadingRules := &clientcmd.ClientConfigLoadingRules{ExplicitPath: s.RemoteKubeConfigFile}
118 loader := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
119
120 clientConfig, err = loader.ClientConfig()
121
122 } else {
123 // without the remote kubeconfig file, try to use the in-cluster config. Most addon API servers will
124 // use this path
125 clientConfig, err = rest.InClusterConfig()
126 }
127 if err != nil {
128 return nil, err
129 }
130
131 // set high qps/burst limits since this will effectively limit API server responsiveness
132 clientConfig.QPS = 200
133 clientConfig.Burst = 400
134
135 client, err := authorizationclient.NewForConfig(clientConfig)
136 if err != nil {
137 return nil, err
138 }
139
140 return client.SubjectAccessReviews(), nil
141}