3
3
## Table Of Contents
4
4
5
5
<!-- toc -->
6
-
7
6
- [ Summary] ( #summary )
8
7
- [ Background] ( #background )
9
8
- [ Motivation] ( #motivation )
10
9
- [ Design Details] ( #design-details )
11
- - [ Token attenuations] ( #token-attenuations )
12
- - [ Audience binding] ( #audience-binding )
13
- - [ Time binding] ( #time-binding )
14
- - [ Object binding] ( #object-binding )
15
- - [ API Changes] ( #api-changes )
16
- - [ Add <code >tokenrequests.authentication.k8s.io</code >] ( #add- )
17
- - [ Modify <code >tokenreviews.authentication.k8s.io</code >] ( #modify- )
18
- - [ Example Flow] ( #example-flow )
19
- - [ Service Account Authenticator Modification] ( #service-account-authenticator-modification )
20
- - [ ACLs for TokenRequest] ( #acls-for-tokenrequest )
10
+ - [ TokenRequest] ( #tokenrequest )
11
+ - [ Token Attenuations] ( #token-attenuations )
12
+ - [ Audience binding] ( #audience-binding )
13
+ - [ Time Binding] ( #time-binding )
14
+ - [ Object Binding] ( #object-binding )
15
+ - [ API Changes] ( #api-changes )
16
+ - [ Add <code >tokenrequests.authentication.k8s.io</code >] ( #add- )
17
+ - [ Modify <code >tokenreviews.authentication.k8s.io</code >] ( #modify- )
18
+ - [ Example Flow] ( #example-flow )
19
+ - [ Service Account Authenticator Modification] ( #service-account-authenticator-modification )
20
+ - [ ACLs for TokenRequest] ( #acls-for-tokenrequest )
21
+ - [ TokenRequestProjection] ( #tokenrequestprojection )
22
+ - [ API Change] ( #api-change )
23
+ - [ File Permission] ( #file-permission )
24
+ - [ Proposed Heuristics] ( #proposed-heuristics )
25
+ - [ Alternatives Considered] ( #alternatives-considered )
21
26
- [ ServiceAccount Admission Controller Migration] ( #serviceaccount-admission-controller-migration )
22
27
- [ Prerequisites] ( #prerequisites )
23
- - [ Safe rollout of time -bound token ] ( #safe-rollout-of-time-bound-token )
28
+ - [ Safe Rollout of Time -bound Token ] ( #safe-rollout-of-time-bound-token )
24
29
- [ Test Plan] ( #test-plan )
25
30
- [ TokenRequest/TokenRequestProjection] ( #tokenrequesttokenrequestprojection )
26
31
- [ RootCAConfigMap] ( #rootcaconfigmap )
40
45
- [ Dependencies] ( #dependencies )
41
46
- [ Scalability] ( #scalability )
42
47
- [ Troubleshooting] ( #troubleshooting )
43
- <!-- /toc -->
48
+ <!-- /toc -->
44
49
45
50
## Summary
46
51
47
52
This KEP describes an API that would allow workloads running on Kubernetes to
48
- request JSON Web Tokens that are audience, time and eventually key bound.
53
+ request JSON Web Tokens that are audience, time and eventually key bound. In
54
+ addition, this KEP introduces a new mechanism of distribution with support for
55
+ bound service account tokens and explores how to migrate from the existing
56
+ mechanism backwards compatibly.
49
57
50
58
## Background
51
59
@@ -74,14 +82,16 @@ requirements.
74
82
75
83
## Design Details
76
84
85
+ ### TokenRequest
86
+
77
87
Infrastructure to support on demand token requests will be implemented in the
78
88
core apiserver. Once this API exists, a client of the apiserver will request an
79
89
attenuated token for its own use. The API will enforce required attenuations,
80
90
e.g. audience and time binding.
81
91
82
- ### Token attenuations
92
+ #### Token Attenuations
83
93
84
- #### Audience binding
94
+ ##### Audience binding
85
95
86
96
Tokens issued from this API will be audience bound. Audience of requested tokens
87
97
will be bound by the ` aud ` claim. The ` aud ` claim is an array of strings
@@ -90,7 +100,7 @@ recipient of a token is responsible for verifying that it identifies as one of
90
100
the values in the audience claim, and should otherwise reject the token. The
91
101
TokenReview API will support this validation.
92
102
93
- #### Time binding
103
+ ##### Time Binding
94
104
95
105
Tokens issued from this API will be time bound. Time validity of these tokens
96
106
will be claimed in the following fields:
@@ -108,7 +118,7 @@ for expiring tokens. During the migration off of the old service account tokens,
108
118
clients of this API may request tokens that are valid for many years. These
109
119
tokens will be drop in replacements for the current service account tokens.
110
120
111
- #### Object binding
121
+ ##### Object Binding
112
122
113
123
Tokens issued from this API may be bound to a Kubernetes object in the same
114
124
namespace as the service account. The name, group, version, kind and uid of the
@@ -123,9 +133,9 @@ kinds that will be supported are:
123
133
124
134
The TokenRequest API will validate this binding.
125
135
126
- ### API Changes
136
+ #### API Changes
127
137
128
- #### Add ` tokenrequests.authentication.k8s.io `
138
+ ##### Add ` tokenrequests.authentication.k8s.io `
129
139
130
140
We will add an imperative API (a la TokenReview) to the ` authentication.k8s.io `
131
141
API group:
@@ -180,7 +190,7 @@ This API will be exposed as a subresource under a serviceaccount object. A
180
190
requestor for a token for a specific service account will ` POST ` a
181
191
` TokenRequest ` to the ` /token ` subresource of that serviceaccount object.
182
192
183
- #### Modify ` tokenreviews.authentication.k8s.io `
193
+ ##### Modify ` tokenreviews.authentication.k8s.io `
184
194
185
195
The TokenReview API will be extended to support passing an additional audience
186
196
field which the service account authenticator will validate.
@@ -194,7 +204,7 @@ type TokenReviewSpec struct {
194
204
}
195
205
```
196
206
197
- #### Example Flow
207
+ ##### Example Flow
198
208
199
209
```
200
210
> POST /apis/v1/namespaces/default/serviceaccounts/default/token
@@ -259,18 +269,147 @@ The token payload will be:
259
269
}
260
270
```
261
271
262
- ### Service Account Authenticator Modification
272
+ #### Service Account Authenticator Modification
263
273
264
274
The service account token authenticator will be extended to support validation
265
275
of time and audience binding claims.
266
276
267
- ### ACLs for TokenRequest
277
+ #### ACLs for TokenRequest
268
278
269
279
The NodeAuthorizer will allow the kubelet to use its credentials to request a
270
280
service account token on behalf of pods running on that node. The
271
281
NodeRestriction admission controller will require that these tokens are pod
272
282
bound.
273
283
284
+ ### TokenRequestProjection
285
+
286
+ A ServiceAccountToken volume projection that maintains a service account token
287
+ requested by the node from the TokenRequest API.
288
+
289
+ #### API Change
290
+
291
+ A new volume projection will be implemented with an API that closely matches the
292
+ TokenRequest API.
293
+
294
+ ``` go
295
+ type ProjectedVolumeSource struct {
296
+ Sources []VolumeProjection
297
+ DefaultMode *int32
298
+ }
299
+
300
+ type VolumeProjection struct {
301
+ Secret *SecretProjection
302
+ DownwardAPI *DownwardAPIProjection
303
+ ConfigMap *ConfigMapProjection
304
+ ServiceAccountToken *ServiceAccountTokenProjection
305
+ }
306
+
307
+ // ServiceAccountTokenProjection represents a projected service account token
308
+ // volume. This projection can be used to insert a service account token into
309
+ // the pods runtime filesystem for use against APIs (Kubernetes API Server or
310
+ // otherwise).
311
+ type ServiceAccountTokenProjection struct {
312
+ // Audience is the intended audience of the token. A recipient of a token
313
+ // must identify itself with an identifier specified in the audience of the
314
+ // token, and otherwise should reject the token. The audience defaults to the
315
+ // identifier of the apiserver.
316
+ Audience string
317
+ // ExpirationSeconds is the requested duration of validity of the service
318
+ // account token. As the token approaches expiration, the kubelet volume
319
+ // plugin will proactively rotate the service account token. The kubelet will
320
+ // start trying to rotate the token if the token is older than 80 percent of
321
+ // its time to live or if the token is older than 24 hours.Defaults to 1 hour
322
+ // and must be at least 10 minutes.
323
+ ExpirationSeconds int64
324
+ // Path is the relative path of the file to project the token into.
325
+ Path string
326
+ }
327
+ ```
328
+
329
+ A volume plugin implemented in the kubelet will project a service account token
330
+ sourced from the TokenRequest API into volumes created from
331
+ ProjectedVolumeSources. As the token approaches expiration, the kubelet volume
332
+ plugin will proactively rotate the service account token. The kubelet will start
333
+ trying to rotate the token if the token is older than 80 percent of its time to
334
+ live or if the token is older than 24 hours.
335
+
336
+ To replace the current service account token secrets, we also need to inject the
337
+ clusters CA certificate bundle. We will deploy it as a configmap per-namespace
338
+ and reference it using a ConfigMapProjection.
339
+
340
+ A projected volume source that is equivalent to the current service account
341
+ secret:
342
+
343
+ ``` yaml
344
+ - name : kube-api-access-xxxxx
345
+ projected :
346
+ defaultMode : 420 # 0644
347
+ sources :
348
+ - serviceAccountToken :
349
+ expirationSeconds : 3600
350
+ path : token
351
+ - configMap :
352
+ items :
353
+ - key : ca.crt
354
+ path : ca.crt
355
+ name : kube-root-ca.crt
356
+ - downwardAPI :
357
+ items :
358
+ - fieldRef :
359
+ apiVersion : v1
360
+ fieldPath : metadata.namespace
361
+ path : namespace
362
+ ` ` `
363
+
364
+ #### File Permission
365
+
366
+ The secret projections are currently written with world readable (0644,
367
+ effectively 444) file permissions. Given that file permissions are one of the
368
+ oldest and most hardened isolation mechanisms on unix, this is not ideal.
369
+ We would like to opportunistically restrict permissions for projected service
370
+ account tokens as long we can show that they won’t break users if we are to
371
+ migrate away from secrets to distribute service account credentials.
372
+
373
+ ##### Proposed Heuristics
374
+
375
+ - _Case 1_: The pod has an fsGroup set. We can set the file permission on the
376
+ token file to 0600 and let the fsGroup mechanism work as designed. It will
377
+ set the permissions to 0640, chown the token file to the fsGroup and start
378
+ the containers with a supplemental group that grants them access to the
379
+ token file. This works today.
380
+ - _Case 2_: The pod’s containers declare the same runAsUser for all containers
381
+ (ephemeral containers are excluded) in the pod. We chown the token file to
382
+ the pod’s runAsUser to grant the containers access to the token. All
383
+ containers must have UID either specified in container security context or
384
+ inherited from pod security context. Preferred UIDs in container images are
385
+ ignored.
386
+ - _Fallback_: We set the file permissions to world readable (0644) to match
387
+ the behavior of secrets.
388
+
389
+ This gives users that run as non-root greater isolation between users without
390
+ breaking existing applications. We also may consider adding more cases in the
391
+ future as long as we can ensure that they won’t break users.
392
+
393
+ ##### Alternatives Considered
394
+
395
+ - We can create a volume for each UserID and set the owner to be that UserID
396
+ with mode 0400. If user doesn't specify runAsUser, fetching UserID in image
397
+ requires a re-design of kubelet regarding volume mounts and image pulling.
398
+ This has significant implementation complexity because:
399
+ - We would have to reorder container creation to introspect images (that
400
+ might declare USER or GROUP directives) to pass this information to the
401
+ projected volume mounter.
402
+ - Further, images are mutable so these directives may change over the
403
+ lifetime of the pod.
404
+ - Volumes are shared between all pods that mount them today. Mapping a
405
+ single logical volume in a pod spec to distinct mount points is likely a
406
+ significant architectural change.
407
+ - We pick a random group and set fsGroup on all pods in the service account
408
+ admission controller. It’s unclear how we would do this without conflicting
409
+ with usage of groups and potentially compromising security.
410
+ - We set token files to be world readable always. Problems with this are
411
+ discussed above.
412
+
274
413
### ServiceAccount Admission Controller Migration
275
414
276
415
#### Prerequisites
@@ -324,7 +463,7 @@ If anything goes wrong, please file a bug and CC @kubernetes/sig-auth-bugs. More
324
463
contact information
325
464
[here](https://github.com/kubernetes/community/tree/master/sig-auth#contact).
326
465
327
- #### Safe rollout of time -bound token
466
+ # ### Safe Rollout of Time -bound Token
328
467
329
468
Legacy service account tokens distributed via secrets are not time-bound. Many
330
469
client libraries have come to depend on this behavior. After time-bound service
@@ -439,7 +578,8 @@ are properly reloading tokens by:
439
578
https://github.com/kubernetes/kubernetes/issues/68164
440
579
- [x] Pods running as non root may not access the service account token.
441
580
- Fixed in https://github.com/kubernetes/kubernetes/pull/89193
442
- - [ ] Dynamic clientbuilder does not invalidate token.
581
+ - [x] Dynamic clientbuilder does not invalidate token.
582
+ - Fixed in https://github.com/kubernetes/kubernetes/pull/99324
443
583
444
584
* [x] Tests passing
445
585
@@ -452,9 +592,10 @@ are properly reloading tokens by:
452
592
453
593
# #### Beta -> GA Graduation
454
594
455
- - [ ] Allow kube-apiserver to recognize multiple issuers to enable non
595
+ - [x ] Allow kube-apiserver to recognize multiple issuers to enable non
456
596
disruptive issuer change.
457
- - [ ] New ` ServiceAccount ` admission controller work as intended in Beta
597
+ - Fixed in https://github.com/kubernetes/kubernetes/pull/101155
598
+ - [x] New `ServiceAccount` admission controller work as intended in Beta
458
599
for >= 1 minor release without significant issues.
459
600
460
601
# # Production Readiness Review Questionnaire
0 commit comments