@@ -19,6 +19,8 @@ package auth
19
19
import (
20
20
"fmt"
21
21
"path"
22
+ "regexp"
23
+ "strings"
22
24
"time"
23
25
24
26
authenticationv1 "k8s.io/api/authentication/v1"
@@ -38,6 +40,7 @@ import (
38
40
)
39
41
40
42
var mountImage = imageutils .GetE2EImage (imageutils .Mounttest )
43
+ var inClusterClientImage = imageutils .GetE2EImage (imageutils .InClusterClient )
41
44
42
45
var _ = SIGDescribe ("ServiceAccounts" , func () {
43
46
f := framework .NewDefaultFramework ("svcaccounts" )
@@ -410,4 +413,138 @@ var _ = SIGDescribe("ServiceAccounts", func() {
410
413
}
411
414
}
412
415
})
416
+
417
+ ginkgo .It ("should support InClusterConfig with token rotation [Slow] [Feature:TokenRequestProjection]" , func () {
418
+ cfg , err := framework .LoadConfig ()
419
+ framework .ExpectNoError (err )
420
+
421
+ if _ , err := f .ClientSet .CoreV1 ().ConfigMaps (f .Namespace .Name ).Create (& v1.ConfigMap {
422
+ ObjectMeta : metav1.ObjectMeta {
423
+ Name : "kube-root-ca.crt" ,
424
+ },
425
+ Data : map [string ]string {
426
+ "ca.crt" : string (cfg .TLSClientConfig .CAData ),
427
+ },
428
+ }); err != nil && ! apierrors .IsAlreadyExists (err ) {
429
+ framework .Failf ("Unexpected err creating kube-ca-crt: %v" , err )
430
+ }
431
+
432
+ tenMin := int64 (10 * 60 )
433
+ pod := & v1.Pod {
434
+ ObjectMeta : metav1.ObjectMeta {Name : "inclusterclient" },
435
+ Spec : v1.PodSpec {
436
+ Containers : []v1.Container {{
437
+ Name : "inclusterclient" ,
438
+ Image : inClusterClientImage ,
439
+ VolumeMounts : []v1.VolumeMount {{
440
+ MountPath : "/var/run/secrets/kubernetes.io/serviceaccount" ,
441
+ Name : "kube-api-access-e2e" ,
442
+ ReadOnly : true ,
443
+ }},
444
+ }},
445
+ RestartPolicy : v1 .RestartPolicyNever ,
446
+ ServiceAccountName : "default" ,
447
+ Volumes : []v1.Volume {{
448
+ Name : "kube-api-access-e2e" ,
449
+ VolumeSource : v1.VolumeSource {
450
+ Projected : & v1.ProjectedVolumeSource {
451
+ Sources : []v1.VolumeProjection {
452
+ {
453
+ ServiceAccountToken : & v1.ServiceAccountTokenProjection {
454
+ Path : "token" ,
455
+ ExpirationSeconds : & tenMin ,
456
+ },
457
+ },
458
+ {
459
+ ConfigMap : & v1.ConfigMapProjection {
460
+ LocalObjectReference : v1.LocalObjectReference {
461
+ Name : "kube-root-ca.crt" ,
462
+ },
463
+ Items : []v1.KeyToPath {
464
+ {
465
+ Key : "ca.crt" ,
466
+ Path : "ca.crt" ,
467
+ },
468
+ },
469
+ },
470
+ },
471
+ {
472
+ DownwardAPI : & v1.DownwardAPIProjection {
473
+ Items : []v1.DownwardAPIVolumeFile {
474
+ {
475
+ Path : "namespace" ,
476
+ FieldRef : & v1.ObjectFieldSelector {
477
+ APIVersion : "v1" ,
478
+ FieldPath : "metadata.namespace" ,
479
+ },
480
+ },
481
+ },
482
+ },
483
+ },
484
+ },
485
+ },
486
+ },
487
+ }},
488
+ },
489
+ }
490
+ pod , err = f .ClientSet .CoreV1 ().Pods (f .Namespace .Name ).Create (pod )
491
+ framework .ExpectNoError (err )
492
+
493
+ framework .Logf ("created pod" )
494
+ if ! framework .CheckPodsRunningReady (f .ClientSet , f .Namespace .Name , []string {pod .Name }, time .Minute ) {
495
+ framework .Failf ("pod %q in ns %q never became ready" , pod .Name , f .Namespace .Name )
496
+ }
497
+
498
+ framework .Logf ("pod is ready" )
499
+
500
+ var logs string
501
+ if err := wait .Poll (1 * time .Minute , 20 * time .Minute , func () (done bool , err error ) {
502
+ framework .Logf ("polling logs" )
503
+ logs , err = framework .GetPodLogs (f .ClientSet , f .Namespace .Name , "inclusterclient" , "inclusterclient" )
504
+ if err != nil {
505
+ framework .Logf ("Error pulling logs: %v" , err )
506
+ return false , nil
507
+ }
508
+ tokenCount , err := parseInClusterClientLogs (logs )
509
+ if err != nil {
510
+ return false , fmt .Errorf ("inclusterclient reported an error: %v" , err )
511
+ }
512
+ if tokenCount < 2 {
513
+ framework .Logf ("Retrying. Still waiting to see more unique tokens: got=%d, want=2" , tokenCount )
514
+ return false , nil
515
+ }
516
+ return true , nil
517
+ }); err != nil {
518
+ framework .Failf ("Unexpected error: %v\n %s" , err , logs )
519
+ }
520
+ })
413
521
})
522
+
523
+ var reportLogsParser = regexp .MustCompile ("([a-zA-Z0-9-_]*)=([a-zA-Z0-9-_]*)$" )
524
+
525
+ func parseInClusterClientLogs (logs string ) (int , error ) {
526
+ seenTokens := map [string ]struct {}{}
527
+
528
+ lines := strings .Split (logs , "\n " )
529
+ for _ , line := range lines {
530
+ parts := reportLogsParser .FindStringSubmatch (line )
531
+ if len (parts ) != 3 {
532
+ continue
533
+ }
534
+
535
+ key , value := parts [1 ], parts [2 ]
536
+ switch key {
537
+ case "authz_header" :
538
+ if value == "<empty>" {
539
+ return 0 , fmt .Errorf ("saw empty Authorization header" )
540
+ }
541
+ seenTokens [value ] = struct {}{}
542
+ case "status" :
543
+ if value == "failed" {
544
+ return 0 , fmt .Errorf ("saw status=failed" )
545
+ }
546
+ }
547
+ }
548
+
549
+ return len (seenTokens ), nil
550
+ }
0 commit comments