@@ -30,6 +30,7 @@ import (
30
30
"testing"
31
31
"time"
32
32
33
+ clientv3 "go.etcd.io/etcd/client/v3"
33
34
rbacv1 "k8s.io/api/rbac/v1"
34
35
apierrors "k8s.io/apimachinery/pkg/api/errors"
35
36
"k8s.io/apimachinery/pkg/api/meta"
@@ -47,6 +48,7 @@ import (
47
48
"k8s.io/client-go/tools/cache"
48
49
featuregatetesting "k8s.io/component-base/featuregate/testing"
49
50
"k8s.io/kubernetes/test/integration/authutil"
51
+ "k8s.io/kubernetes/test/integration/framework"
50
52
"k8s.io/utils/ptr"
51
53
)
52
54
@@ -431,19 +433,26 @@ func TestListCorruptObjects(t *testing.T) {
431
433
// secrets that are created before encryption breaks
432
434
secrets []string
433
435
// whether encryption broke after the config change
434
- encryptionBrokenFn func (t * testing.T , got apierrors.APIStatus ) bool
436
+ encryptionBrokenFn func (t * testing.T , got apierrors.APIStatus )
435
437
// what we expect for LIST on the corrupt objects after encryption has broken
436
438
listAfter verifier
437
439
}{
438
440
{
439
441
secrets : secrets ,
440
442
featureEnabled : true ,
441
- encryptionBrokenFn : func (t * testing.T , got apierrors.APIStatus ) bool {
442
- // the new encryption config does not have the old key, so reading of resources
443
- // created before the encryption change will fail with 'no matching prefix found'
444
- return got .Status ().Reason == metav1 .StatusReasonInternalError &&
445
- strings .Contains (got .Status ().Message , "Internal error occurred: StorageError: corrupt object" ) &&
446
- strings .Contains (got .Status ().Message , "data from the storage is not transformable revision=0: no matching prefix found" )
443
+ encryptionBrokenFn : func (t * testing.T , got apierrors.APIStatus ) {
444
+ status := got .Status ()
445
+ if status .Reason != metav1 .StatusReasonInternalError {
446
+ t .Errorf ("Invalid reason, got: %q, want: %q" , status .Reason , metav1 .StatusReasonInternalError )
447
+ }
448
+ corruptObjectMsg := "Internal error occurred: StorageError: corrupt object"
449
+ if ! strings .Contains (status .Message , corruptObjectMsg ) {
450
+ t .Errorf ("Message should include %q, but got: %q" , corruptObjectMsg , status .Message )
451
+ }
452
+ messageAuthenticationFailedMsg := "data from the storage is not transformable revision=0: cipher: message authentication failed"
453
+ if ! strings .Contains (status .Message , messageAuthenticationFailedMsg ) {
454
+ t .Errorf ("Message should include %q, but got: %q" , messageAuthenticationFailedMsg , status .Message )
455
+ }
447
456
},
448
457
listAfter : wantAPIStatusError {
449
458
reason : metav1 .StatusReasonStoreReadError ,
@@ -482,11 +491,15 @@ func TestListCorruptObjects(t *testing.T) {
482
491
{
483
492
secrets : secrets ,
484
493
featureEnabled : false ,
485
- encryptionBrokenFn : func (t * testing.T , got apierrors.APIStatus ) bool {
486
- // the new encryption config does not have the old key, so reading of resources
487
- // created before the encryption change will fail with 'no matching prefix found'
488
- return got .Status ().Reason == metav1 .StatusReasonInternalError &&
489
- strings .Contains (got .Status ().Message , "Internal error occurred: no matching prefix found" )
494
+ encryptionBrokenFn : func (t * testing.T , got apierrors.APIStatus ) {
495
+ status := got .Status ()
496
+ if status .Reason != metav1 .StatusReasonInternalError {
497
+ t .Errorf ("Invalid reason, got: %q, want: %q" , status .Reason , metav1 .StatusReasonInternalError )
498
+ }
499
+ noMatchingPrefixFoundMsg := "Internal error occurred: cipher: message authentication failed"
500
+ if ! strings .Contains (status .Message , noMatchingPrefixFoundMsg ) {
501
+ t .Errorf ("Message should include %q, but got: %q" , noMatchingPrefixFoundMsg , status .Message )
502
+ }
490
503
},
491
504
listAfter : wantAPIStatusError {
492
505
reason : metav1 .StatusReasonInternalError ,
@@ -497,12 +510,13 @@ func TestListCorruptObjects(t *testing.T) {
497
510
for _ , tc := range tests {
498
511
t .Run (fmt .Sprintf ("%s/%t" , string (genericfeatures .AllowUnsafeMalformedObjectDeletion ), tc .featureEnabled ), func (t * testing.T ) {
499
512
featuregatetesting .SetFeatureGateDuringTest (t , utilfeature .DefaultFeatureGate , genericfeatures .AllowUnsafeMalformedObjectDeletion , tc .featureEnabled )
500
-
501
- test , err := newTransformTest (t , transformTestConfig {transformerConfigYAML : aesGCMConfigYAML , reload : true })
513
+ storageConfig := framework . SharedEtcd ()
514
+ test , err := newTransformTest (t , transformTestConfig {transformerConfigYAML : aesGCMConfigYAML , reload : true , storageConfig : storageConfig })
502
515
if err != nil {
503
516
t .Fatalf ("failed to setup test for envelop %s, error was %v" , aesGCMPrefix , err )
504
517
}
505
518
defer test .cleanUp ()
519
+ ctx := context .Background ()
506
520
507
521
// a) create a number of secrets in the test namespace
508
522
for _ , name := range tc .secrets {
@@ -523,64 +537,45 @@ func TestListCorruptObjects(t *testing.T) {
523
537
524
538
// c) override the config and break decryption of the old resources,
525
539
// the secret created in step a will be undecryptable
526
- encryptionConf := filepath .Join (test .configDir , encryptionConfigFileName )
527
- body , _ := ioutil .ReadFile (encryptionConf )
528
- t .Logf ("file before write: %s" , body )
529
- // we replace the existing key with a new key from a different provider
530
- if err := os .WriteFile (encryptionConf , []byte (aesCBCConfigYAML ), 0o644 ); err != nil {
531
- t .Fatalf ("failed to write encryption config that's going to make decryption fail" )
540
+ client , err := clientv3 .New (clientv3.Config {Endpoints : storageConfig .Transport .ServerList })
541
+ if err != nil {
542
+ t .Fatal (err )
532
543
}
533
- body , _ = ioutil .ReadFile (encryptionConf )
534
- t .Logf ("file after write: %s" , body )
535
-
536
- // d) wait for the breaking changes to take effect
537
- testCtx , cancel := context .WithCancel (context .Background ())
538
- defer cancel ()
539
- // TODO: dynamic encryption config reload takes about 1m, so can't use
540
- // wait.ForeverTestTimeout just yet, investigate and reduce the reload time.
541
- err = wait .PollUntilContextTimeout (testCtx , 1 * time .Second , 2 * time .Minute , true , func (ctx context.Context ) (done bool , err error ) {
542
- _ , err = test .restClient .CoreV1 ().Secrets (testNamespace ).Get (ctx , tc .secrets [0 ], metav1.GetOptions {})
543
-
544
+ defer func () {
545
+ err := client .Close ()
544
546
if err != nil {
545
- t .Logf ("get returned error: %#v message: %s" , err , err .Error ())
546
- }
547
-
548
- var got apierrors.APIStatus
549
- if ! errors .As (err , & got ) {
550
- return false , nil
551
- }
552
- if done := tc .encryptionBrokenFn (t , got ); done {
553
- return true , nil
547
+ t .Fatal (err )
554
548
}
555
- return false , nil
556
- } )
549
+ }()
550
+ resp , err := client . Get ( ctx , "/" + storageConfig . Prefix + "/secrets/" , clientv3 . WithPrefix () )
557
551
if err != nil {
558
- t .Fatalf ("encryption never broke: %v" , err )
552
+ t .Fatal (err )
553
+ }
554
+ if len (resp .Kvs ) != len (tc .secrets ) {
555
+ t .Fatalf ("Expected %d number of keys, got: %d" , len (tc .secrets ), len (resp .Kvs ))
556
+ }
557
+ for _ , kv := range resp .Kvs {
558
+ // Remove last byte
559
+ _ , err = client .Put (ctx , string (kv .Key ), string (kv .Value )[:len (kv .Value )- 1 ])
560
+ if err != nil {
561
+ t .Fatal (err )
562
+ }
559
563
}
560
564
561
- // TODO: ConsistentListFromCache feature returns the list of objects
562
- // from cache even though these objects are not readable from the
563
- // store after encryption has broken; to work around this issue, let's
564
- // create a new secret and retrieve it from the store to get a more
565
- // recent ResourceVersion and invoke the list with:
566
- // ResourceVersionMatch: Exact
567
- newSecretName := "new-a"
568
- _ , err = test .createSecret (newSecretName , testNamespace )
565
+ _ , err = test .restClient .CoreV1 ().Secrets (testNamespace ).Get (ctx , tc .secrets [0 ], metav1.GetOptions {})
569
566
if err != nil {
570
- t .Fatalf ( "expected no error while creating the new secret, but got : %d " , err )
567
+ t .Logf ( "get returned error: %#v message : %s " , err , err . Error () )
571
568
}
572
- newSecret , err := test .restClient .CoreV1 ().Secrets (testNamespace ).Get (context .Background (), newSecretName , metav1.GetOptions {})
573
- if err != nil {
574
- t .Fatalf ("expected no error getting the new secret, but got: %d" , err )
569
+
570
+ var got apierrors.APIStatus
571
+ if ! errors .As (err , & got ) {
572
+ t .Fatalf ("encryption never broke: %v" , err )
575
573
}
574
+ tc .encryptionBrokenFn (t , got )
576
575
577
576
// e) list should return expected error
578
- _ , err = test .restClient .CoreV1 ().Secrets (testNamespace ).List (context .Background (), metav1.ListOptions {
579
- ResourceVersion : newSecret .ResourceVersion ,
580
- ResourceVersionMatch : metav1 .ResourceVersionMatchExact ,
581
- })
577
+ _ , err = test .restClient .CoreV1 ().Secrets (testNamespace ).List (ctx , metav1.ListOptions {})
582
578
tc .listAfter .verify (t , err )
583
-
584
579
})
585
580
}
586
581
}
0 commit comments