@@ -21,12 +21,17 @@ import (
21
21
"strings"
22
22
"time"
23
23
24
+ "k8s.io/apiserver/pkg/apis/apiserver/load"
25
+ genericfeatures "k8s.io/apiserver/pkg/features"
26
+ utilfeature "k8s.io/apiserver/pkg/util/feature"
27
+
24
28
"github.com/spf13/pflag"
25
29
26
30
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27
31
"k8s.io/apimachinery/pkg/util/sets"
28
32
"k8s.io/apimachinery/pkg/util/wait"
29
33
authzconfig "k8s.io/apiserver/pkg/apis/apiserver"
34
+ "k8s.io/apiserver/pkg/apis/apiserver/validation"
30
35
genericoptions "k8s.io/apiserver/pkg/server/options"
31
36
versionedinformers "k8s.io/client-go/informers"
32
37
@@ -35,9 +40,19 @@ import (
35
40
)
36
41
37
42
const (
38
- defaultWebhookName = "default"
43
+ defaultWebhookName = "default"
44
+ authorizationModeFlag = "authorization-mode"
45
+ authorizationWebhookConfigFileFlag = "authorization-webhook-config-file"
46
+ authorizationWebhookVersionFlag = "authorization-webhook-version"
47
+ authorizationWebhookAuthorizedTTLFlag = "authorization-webhook-cache-authorized-ttl"
48
+ authorizationWebhookUnauthorizedTTLFlag = "authorization-webhook-cache-unauthorized-ttl"
49
+ authorizationPolicyFileFlag = "authorization-policy-file"
50
+ authorizationConfigFlag = "authorization-config"
39
51
)
40
52
53
+ // RepeatableAuthorizerTypes is the list of Authorizer that can be repeated in the Authorization Config
54
+ var repeatableAuthorizerTypes = []string {authzmodes .ModeWebhook }
55
+
41
56
// BuiltInAuthorizationOptions contains all build-in authorization options for API Server
42
57
type BuiltInAuthorizationOptions struct {
43
58
Modes []string
@@ -50,6 +65,16 @@ type BuiltInAuthorizationOptions struct {
50
65
// This allows us to configure the sleep time at each iteration and the maximum number of retries allowed
51
66
// before we fail the webhook call in order to limit the fan out that ensues when the system is degraded.
52
67
WebhookRetryBackoff * wait.Backoff
68
+
69
+ // AuthorizationConfigurationFile is mutually exclusive with all of:
70
+ // - Modes
71
+ // - WebhookConfigFile
72
+ // - WebHookVersion
73
+ // - WebhookCacheAuthorizedTTL
74
+ // - WebhookCacheUnauthorizedTTL
75
+ AuthorizationConfigurationFile string
76
+
77
+ AreLegacyFlagsSet func () bool
53
78
}
54
79
55
80
// NewBuiltInAuthorizationOptions create a BuiltInAuthorizationOptions with default value
@@ -69,6 +94,54 @@ func (o *BuiltInAuthorizationOptions) Validate() []error {
69
94
return nil
70
95
}
71
96
var allErrors []error
97
+
98
+ // if --authorization-config is set, check if
99
+ // - the feature flag is set
100
+ // - legacyFlags are not set
101
+ // - the config file can be loaded
102
+ // - the config file represents a valid configuration
103
+ if o .AuthorizationConfigurationFile != "" {
104
+ if ! utilfeature .DefaultFeatureGate .Enabled (genericfeatures .StructuredAuthorizationConfiguration ) {
105
+ return append (allErrors , fmt .Errorf ("--%s cannot be used without enabling StructuredAuthorizationConfiguration feature flag" , authorizationConfigFlag ))
106
+ }
107
+
108
+ // error out if legacy flags are defined
109
+ if o .AreLegacyFlagsSet != nil && o .AreLegacyFlagsSet () {
110
+ return append (allErrors , fmt .Errorf ("--%s can not be specified when --%s or --authorization-webhook-* flags are defined" , authorizationConfigFlag , authorizationModeFlag ))
111
+ }
112
+
113
+ // load the file and check for errors
114
+ config , err := load .LoadFromFile (o .AuthorizationConfigurationFile )
115
+ if err != nil {
116
+ return append (allErrors , fmt .Errorf ("failed to load AuthorizationConfiguration from file: %v" , err ))
117
+ }
118
+
119
+ // validate the file and return any error
120
+ if errors := validation .ValidateAuthorizationConfiguration (nil , config ,
121
+ sets .NewString (authzmodes .AuthorizationModeChoices ... ),
122
+ sets .NewString (repeatableAuthorizerTypes ... ),
123
+ ); len (errors ) != 0 {
124
+ allErrors = append (allErrors , errors .ToAggregate ().Errors ()... )
125
+ }
126
+
127
+ // test to check if the authorizer names passed conform to the authorizers for type!=Webhook
128
+ // this test is only for kube-apiserver and hence checked here
129
+ // it preserves compatibility with o.buildAuthorizationConfiguration
130
+ for _ , authorizer := range config .Authorizers {
131
+ if string (authorizer .Type ) == authzmodes .ModeWebhook {
132
+ continue
133
+ }
134
+
135
+ expectedName := getNameForAuthorizerMode (string (authorizer .Type ))
136
+ if expectedName != authorizer .Name {
137
+ allErrors = append (allErrors , fmt .Errorf ("expected name %s for authorizer %s instead of %s" , expectedName , authorizer .Type , authorizer .Name ))
138
+ }
139
+ }
140
+
141
+ return allErrors
142
+ }
143
+
144
+ // validate the legacy flags using the legacy mode if --authorization-config is not passed
72
145
if len (o .Modes ) == 0 {
73
146
allErrors = append (allErrors , fmt .Errorf ("at least one authorization-mode must be passed" ))
74
147
}
@@ -111,27 +184,47 @@ func (o *BuiltInAuthorizationOptions) AddFlags(fs *pflag.FlagSet) {
111
184
return
112
185
}
113
186
114
- fs .StringSliceVar (& o .Modes , "authorization-mode" , o .Modes , "" +
187
+ fs .StringSliceVar (& o .Modes , authorizationModeFlag , o .Modes , "" +
115
188
"Ordered list of plug-ins to do authorization on secure port. Comma-delimited list of: " +
116
189
strings .Join (authzmodes .AuthorizationModeChoices , "," )+ "." )
117
190
118
- fs .StringVar (& o .PolicyFile , "authorization-policy-file" , o .PolicyFile , "" +
191
+ fs .StringVar (& o .PolicyFile , authorizationPolicyFileFlag , o .PolicyFile , "" +
119
192
"File with authorization policy in json line by line format, used with --authorization-mode=ABAC, on the secure port." )
120
193
121
- fs .StringVar (& o .WebhookConfigFile , "authorization-webhook-config-file" , o .WebhookConfigFile , "" +
194
+ fs .StringVar (& o .WebhookConfigFile , authorizationWebhookConfigFileFlag , o .WebhookConfigFile , "" +
122
195
"File with webhook configuration in kubeconfig format, used with --authorization-mode=Webhook. " +
123
196
"The API server will query the remote service to determine access on the API server's secure port." )
124
197
125
- fs .StringVar (& o .WebhookVersion , "authorization-webhook-version" , o .WebhookVersion , "" +
198
+ fs .StringVar (& o .WebhookVersion , authorizationWebhookVersionFlag , o .WebhookVersion , "" +
126
199
"The API version of the authorization.k8s.io SubjectAccessReview to send to and expect from the webhook." )
127
200
128
- fs .DurationVar (& o .WebhookCacheAuthorizedTTL , "authorization-webhook-cache-authorized-ttl" ,
201
+ fs .DurationVar (& o .WebhookCacheAuthorizedTTL , authorizationWebhookAuthorizedTTLFlag ,
129
202
o .WebhookCacheAuthorizedTTL ,
130
203
"The duration to cache 'authorized' responses from the webhook authorizer." )
131
204
132
205
fs .DurationVar (& o .WebhookCacheUnauthorizedTTL ,
133
- "authorization-webhook-cache-unauthorized-ttl" , o .WebhookCacheUnauthorizedTTL ,
206
+ authorizationWebhookUnauthorizedTTLFlag , o .WebhookCacheUnauthorizedTTL ,
134
207
"The duration to cache 'unauthorized' responses from the webhook authorizer." )
208
+
209
+ fs .StringVar (& o .AuthorizationConfigurationFile , authorizationConfigFlag , o .AuthorizationConfigurationFile , "" +
210
+ "File with Authorization Configuration to configure the authorizer chain." +
211
+ "Note: This feature is in Alpha since v1.29." +
212
+ "--feature-gate=StructuredAuthorizationConfiguration=true feature flag needs to be set to true for enabling the functionality." +
213
+ "This feature is mutually exclusive with the other --authorization-mode and --authorization-webhook-* flags." )
214
+
215
+ // preserves compatibility with any method set during initialization
216
+ oldAreLegacyFlagsSet := o .AreLegacyFlagsSet
217
+ o .AreLegacyFlagsSet = func () bool {
218
+ if oldAreLegacyFlagsSet != nil && oldAreLegacyFlagsSet () {
219
+ return true
220
+ }
221
+
222
+ return fs .Changed (authorizationModeFlag ) ||
223
+ fs .Changed (authorizationWebhookConfigFileFlag ) ||
224
+ fs .Changed (authorizationWebhookVersionFlag ) ||
225
+ fs .Changed (authorizationWebhookAuthorizedTTLFlag ) ||
226
+ fs .Changed (authorizationWebhookUnauthorizedTTLFlag )
227
+ }
135
228
}
136
229
137
230
// ToAuthorizationConfig convert BuiltInAuthorizationOptions to authorizer.Config
@@ -140,17 +233,52 @@ func (o *BuiltInAuthorizationOptions) ToAuthorizationConfig(versionedInformerFac
140
233
return nil , nil
141
234
}
142
235
143
- authzConfiguration , err := o .buildAuthorizationConfiguration ()
144
- if err != nil {
145
- return nil , fmt .Errorf ("failed to build authorization config: %s" , err )
236
+ var authorizationConfiguration * authzconfig.AuthorizationConfiguration
237
+ var err error
238
+
239
+ // if --authorization-config is set, check if
240
+ // - the feature flag is set
241
+ // - legacyFlags are not set
242
+ // - the config file can be loaded
243
+ // - the config file represents a valid configuration
244
+ // else,
245
+ // - build the AuthorizationConfig from the legacy flags
246
+ if o .AuthorizationConfigurationFile != "" {
247
+ if ! utilfeature .DefaultFeatureGate .Enabled (genericfeatures .StructuredAuthorizationConfiguration ) {
248
+ return nil , fmt .Errorf ("--%s cannot be used without enabling StructuredAuthorizationConfiguration feature flag" , authorizationConfigFlag )
249
+ }
250
+
251
+ // error out if legacy flags are defined
252
+ if o .AreLegacyFlagsSet != nil && o .AreLegacyFlagsSet () {
253
+ return nil , fmt .Errorf ("--%s can not be specified when --%s or --authorization-webhook-* flags are defined" , authorizationConfigFlag , authorizationModeFlag )
254
+ }
255
+
256
+ // load the file and check for errors
257
+ authorizationConfiguration , err = load .LoadFromFile (o .AuthorizationConfigurationFile )
258
+ if err != nil {
259
+ return nil , fmt .Errorf ("failed to load AuthorizationConfiguration from file: %v" , err )
260
+ }
261
+
262
+ // validate the file and return any error
263
+ if errors := validation .ValidateAuthorizationConfiguration (nil , authorizationConfiguration ,
264
+ sets .NewString (authzmodes .AuthorizationModeChoices ... ),
265
+ sets .NewString (repeatableAuthorizerTypes ... ),
266
+ ); len (errors ) != 0 {
267
+ return nil , fmt .Errorf (errors .ToAggregate ().Error ())
268
+ }
269
+ } else {
270
+ authorizationConfiguration , err = o .buildAuthorizationConfiguration ()
271
+ if err != nil {
272
+ return nil , fmt .Errorf ("failed to build authorization config: %s" , err )
273
+ }
146
274
}
147
275
148
276
return & authorizer.Config {
149
277
PolicyFile : o .PolicyFile ,
150
278
VersionedInformerFactory : versionedInformerFactory ,
151
279
WebhookRetryBackoff : o .WebhookRetryBackoff ,
152
280
153
- AuthorizationConfiguration : authzConfiguration ,
281
+ AuthorizationConfiguration : authorizationConfiguration ,
154
282
}, nil
155
283
}
156
284
0 commit comments