@@ -27,13 +27,15 @@ import (
27
27
"encoding/binary"
28
28
"fmt"
29
29
"io"
30
+ "path"
30
31
"regexp"
31
32
"strings"
32
33
"testing"
33
34
"time"
34
35
35
36
"github.com/gogo/protobuf/proto"
36
37
"github.com/google/go-cmp/cmp"
38
+ "github.com/google/go-cmp/cmp/cmpopts"
37
39
clientv3 "go.etcd.io/etcd/client/v3"
38
40
39
41
corev1 "k8s.io/api/core/v1"
@@ -1308,3 +1310,175 @@ resources:
1308
1310
}
1309
1311
1310
1312
func randomBool () bool { return utilrand .Int ()% 2 == 1 }
1313
+
1314
+ // TestKMSv2ProviderLegacyData confirms that legacy data recorded from the earliest released commit can still be read.
1315
+ func TestKMSv2ProviderLegacyData (t * testing.T ) {
1316
+ t .Run ("regular gcm" , func (t * testing.T ) {
1317
+ defer featuregatetesting .SetFeatureGateDuringTest (t , utilfeature .DefaultFeatureGate , features .KMSv2KDF , false )()
1318
+ testKMSv2ProviderLegacyData (t )
1319
+ })
1320
+
1321
+ t .Run ("extended nonce gcm" , func (t * testing.T ) {
1322
+ defer featuregatetesting .SetFeatureGateDuringTest (t , utilfeature .DefaultFeatureGate , features .KMSv2KDF , true )()
1323
+ testKMSv2ProviderLegacyData (t )
1324
+ })
1325
+ }
1326
+
1327
+ func testKMSv2ProviderLegacyData (t * testing.T ) {
1328
+ defer featuregatetesting .SetFeatureGateDuringTest (t , utilfeature .DefaultFeatureGate , features .KMSv2 , true )()
1329
+
1330
+ encryptionConfig := `
1331
+ kind: EncryptionConfiguration
1332
+ apiVersion: apiserver.config.k8s.io/v1
1333
+ resources:
1334
+ - resources:
1335
+ - secrets
1336
+ providers:
1337
+ - kms:
1338
+ apiVersion: v2
1339
+ name: kms-provider
1340
+ endpoint: unix:///@kms-provider.sock
1341
+ `
1342
+
1343
+ _ = kmsv2mock .NewBase64Plugin (t , "@kms-provider.sock" )
1344
+
1345
+ // the value.Context.AuthenticatedData during read is the etcd storage path of the associated resource
1346
+ // thus we need to manually construct the storage config so that we can have a static path
1347
+ const legacyDataEtcdPrefix = "43da1478-5e9c-4ef3-a92a-2b19d540c8a5"
1348
+
1349
+ storageConfig := storagebackend .NewDefaultConfig (path .Join (legacyDataEtcdPrefix , "registry" ), nil )
1350
+ storageConfig .Transport .ServerList = []string {framework .GetEtcdURL ()}
1351
+
1352
+ test , err := newTransformTest (t , encryptionConfig , false , "" , storageConfig )
1353
+ if err != nil {
1354
+ t .Fatalf ("failed to start KUBE API Server with encryptionConfig\n %s, error: %v" , encryptionConfig , err )
1355
+ }
1356
+ defer test .cleanUp ()
1357
+
1358
+ const legacyDataNamespace = "kms-v2-legacy-data"
1359
+
1360
+ if _ , err := test .createNamespace (legacyDataNamespace ); err != nil {
1361
+ t .Fatal (err )
1362
+ }
1363
+
1364
+ // commit: 1b4df30b3cdfeaba6024e81e559a6cd09a089d65
1365
+ // tag: v1.27.0
1366
+ const dekSourceAESGCMKeyName = "dek-source-aes-gcm-key"
1367
+ const dekSourceAESGCMKeyData = "k8s:enc:kms:v2:kms-provider:\n \x8a \x03 \xb0 ƙ\xdc \x01 ʚ;\x00 \x00 \x00 \x00 \x8c \x80 \v \xf0 \x1d Ko{0\v \xb5 \xd5 Ń\x1a \xb5 \x0e \xcf \xd7 Ve\xed 邸\xdf E\xed Mk\xcf !\x15 \xc0 \v \t \x82 Wh \x9e \x8f \x1b \\ 9\b \xa4 \x80 \x02 m\xf4 P\x14 z\xee \xf7 \x8c \x1a \x84 n5\xfd G\x83 v#\x0e \xd4 \f \x83 YwH\xe1 \x1c \xbf \x12 \xc6 \x1b \xba \x8b r\b \x82 z\xf8 \xdb `\xa7 ]P\xb1 \xe6 !Lb\x8d \xb8 I\x1a EL\xa0 \xae +\xbe \x15 R\x8e \x9b \x06 4\xf6 P\xb6 ;\x9f \xa6 \x8d \x96 \xb2 \x01 \xa1 \x8e \xe4 a\xdf /\x90 u\xde 6\x9a \xc2 ͻb\x88 +\x16 \x98 =\xe9 \x03 \xdd \xd7 HvC\n \xe5 \x8c v\x05 ~\n \xab X_N\x9a \x84 wp\xa8 \x13 \x0f \x82 Y9x\xed \x89 \x15 \xb9 \xe1 ꦐ\xc6 `R\n 0\x04 \xf2 \xa6 ѥ\x85 \n k\xf4 \xcf \xe4 ul\x1c *[A\x12 \xa0 \xd9 \xf2 \xb5 !\x82 \xe4 \x00 \xa4 L'&\xf5 pln\" \xe0 =\f [\xe1 \xb0 U97\x11 |\xda Nk\xc3 =\xc2 \xf2 \x85 <7\x1e \x01 \xb8 \xa9 \xf4 \x89 \xdb ~\xe1 \x8c \xe1 \x1f \x05 B@WʼS\n 聛LY\x86 $\xf6 \x01 ݝ\xcd \x1d \xe9 \x02 ]\xf4 i\xda \xfa \xc2 \x0e Ur\xc5 Dʽdb\x13 \xbe \xfe \x1c \xc5 \xe1 \x84 \xcc \xdf &\x93 j\x1e K\x04 \xba \x06 \x16 \x85 \x0e \x1f \xca \b \x90 \x06 \x11 K\x9d [\r V\xe8 E\xd5 (\x91 \f n\xd4 \x10 \x9c H\x1c ܝX\x94 ȁ5\x1b \x8c \xbb z\xf9 Ho{\x1d \x11 2\x90 F\xe7 \xd8 h\xa8 \xa1 \xf6 \x8c \x8c vʲ1\xf9 #\x82 \xa3 \xbe 7ed\xd9 \x14 \xf3 \x06 \xff \xb7 ߫i\x12 \x01 1\x1a ,gafIvwT0ASoKdZ/D1L2SlH73LUMj5qa3hroljfS51wc=\" 2\n \x1b local-kek.kms.kubernetes.io\x12 \x13 encrypted-local-kek"
1368
+ dekSourceAESGCMKeyPath := test .getETCDPathForResource (test .storageConfig .Prefix , "" , "secrets" , dekSourceAESGCMKeyName , legacyDataNamespace )
1369
+ if _ , err := test .writeRawRecordToETCD (dekSourceAESGCMKeyPath , []byte (dekSourceAESGCMKeyData )); err != nil {
1370
+ t .Fatal (err )
1371
+ }
1372
+
1373
+ expectedDEKSourceAESGCMKeyObject := & kmstypes.EncryptedObject {
1374
+ EncryptedData : []byte ("\xb0 ƙ\xdc \x01 ʚ;\x00 \x00 \x00 \x00 \x8c \x80 \v \xf0 \x1d Ko{0\v \xb5 \xd5 Ń\x1a \xb5 \x0e \xcf \xd7 Ve\xed 邸\xdf E\xed Mk\xcf !\x15 \xc0 \v \t \x82 Wh \x9e \x8f \x1b \\ 9\b \xa4 \x80 \x02 m\xf4 P\x14 z\xee \xf7 \x8c \x1a \x84 n5\xfd G\x83 v#\x0e \xd4 \f \x83 YwH\xe1 \x1c \xbf \x12 \xc6 \x1b \xba \x8b r\b \x82 z\xf8 \xdb `\xa7 ]P\xb1 \xe6 !Lb\x8d \xb8 I\x1a EL\xa0 \xae +\xbe \x15 R\x8e \x9b \x06 4\xf6 P\xb6 ;\x9f \xa6 \x8d \x96 \xb2 \x01 \xa1 \x8e \xe4 a\xdf /\x90 u\xde 6\x9a \xc2 ͻb\x88 +\x16 \x98 =\xe9 \x03 \xdd \xd7 HvC\n \xe5 \x8c v\x05 ~\n \xab X_N\x9a \x84 wp\xa8 \x13 \x0f \x82 Y9x\xed \x89 \x15 \xb9 \xe1 ꦐ\xc6 `R\n 0\x04 \xf2 \xa6 ѥ\x85 \n k\xf4 \xcf \xe4 ul\x1c *[A\x12 \xa0 \xd9 \xf2 \xb5 !\x82 \xe4 \x00 \xa4 L'&\xf5 pln\" \xe0 =\f [\xe1 \xb0 U97\x11 |\xda Nk\xc3 =\xc2 \xf2 \x85 <7\x1e \x01 \xb8 \xa9 \xf4 \x89 \xdb ~\xe1 \x8c \xe1 \x1f \x05 B@WʼS\n 聛LY\x86 $\xf6 \x01 ݝ\xcd \x1d \xe9 \x02 ]\xf4 i\xda \xfa \xc2 \x0e Ur\xc5 Dʽdb\x13 \xbe \xfe \x1c \xc5 \xe1 \x84 \xcc \xdf &\x93 j\x1e K\x04 \xba \x06 \x16 \x85 \x0e \x1f \xca \b \x90 \x06 \x11 K\x9d [\r V\xe8 E\xd5 (\x91 \f n\xd4 \x10 \x9c H\x1c ܝX\x94 ȁ5\x1b \x8c \xbb z\xf9 Ho{\x1d \x11 2\x90 F\xe7 \xd8 h\xa8 \xa1 \xf6 \x8c \x8c vʲ1\xf9 #\x82 \xa3 \xbe 7ed\xd9 \x14 \xf3 \x06 \xff \xb7 ߫i" ),
1375
+ KeyID : "1" ,
1376
+ EncryptedDEKSource : []byte ("gafIvwT0ASoKdZ/D1L2SlH73LUMj5qa3hroljfS51wc=" ),
1377
+ Annotations : map [string ][]byte {"local-kek.kms.kubernetes.io" : []byte ("encrypted-local-kek" )},
1378
+ EncryptedDEKSourceType : kmstypes .EncryptedDEKSourceType_AES_GCM_KEY ,
1379
+ }
1380
+ legacyDEKSourceAESGCMKeyObject := & kmstypes.EncryptedObject {}
1381
+ if err := proto .Unmarshal ([]byte (strings .TrimPrefix (dekSourceAESGCMKeyData , "k8s:enc:kms:v2:kms-provider:" )), legacyDEKSourceAESGCMKeyObject ); err != nil {
1382
+ t .Fatal (err )
1383
+ }
1384
+ if err := kmsv2 .ValidateEncryptedObject (legacyDEKSourceAESGCMKeyObject ); err != nil {
1385
+ t .Fatal (err )
1386
+ }
1387
+ if diff := cmp .Diff (expectedDEKSourceAESGCMKeyObject , legacyDEKSourceAESGCMKeyObject ); len (diff ) > 0 {
1388
+ t .Errorf ("kms v2 legacy encrypted object diff (-want, +got):\n %s" , diff )
1389
+ }
1390
+
1391
+ // commit: 855e7c48de7388eb330da0f8d9d2394ee818fb8d
1392
+ // tag: v1.28.0
1393
+ const dekSourceHKDFSHA256XNonceAESGCMSeedName = "dek-source-hkdf-sha256-xnonce-aes-gcm-seed"
1394
+ const dekSourceHKDFSHA256XNonceAESGCMSeedData = "k8s:enc:kms:v2:kms-provider:\n \xd1 \x03 \x12 \x0f \x87 \xae \xa2 \xa2 \xf5 J\x11 \x06 о\x8a \x81 \xb6 \x15 \xdf 4H\xa3 \xb7 i\x93 ^)\xe5 i\xe2 \x7f \xfd o\xee \" \x17 0\xb7 \n \xa0 \v \xec \xe0 \xfa \t #\t Ɩ\xf6 ǧw\x01 \xb9 \xab \xb3 \xf4 \xdf \xec \x9e J\x95 $&Z=\x8a wAc\xa5 \xb2 ;\t \xd5 \xf9 \x05 \xc1 E)\x8b \xb8 \x14 \xc9 \xda \x14 {I\r V?\xe5 :\xf0 BM\x9b \xad \xaa Hn>W/Q\xa3 \xf5 \xba \xe7 ˚\n \xe7 \" \xa7 \\ p\x8c \xba 2\xf2 \xb0 x<Ą\x88 \x9a \xf1 \xb5 :d=z\xe3 \xc3 &\x03 \x99 m\x96 \xe7 \\ \xe3 \xa3 \xd7 i\xb2 \f \x84 g\xf9 4\xd2 \f \xd6 ~\xed \xac \xf8 \x1b \xc6 (,[\xd1 \xff \xba \x89 ȇD\x02 ):wTM12\xb5 \xfd l\xd2 \xf2 \x85 \x12 0\xd3 \xd9 aak\xce \xdd I֥\x0f k2\xf6 I\xd0 \xf9 \xc2 \xda \v ŗ\xd7 \u05fb \x83 \xd6 \xf7 \x1a \xbf \x13 iH\x8f \xe4 \xb3 #\xf3 \xdf \xc8 $y\r L(F\\ Xt\x86 \xbb \xe5 K\x88 =\x92 \xe9 \x04 \xf7 0\x1e \t >\xac ;\x9e \xe6 \xf0 +ۙ4\x1d \x1a V9Մ-g\xf3 \xc7 Z\x00 \xf7 3\x0e \xe7 \xa6 \xcf \xc4 \xfc \xe0 \xb2 \x1f \xa0 \xbb \x1a \x81 \xb3 \xe4 צ\x7f \xc6 \b \x94 ͉\xad @\xac \x81 \x01 5\x0f \xe8 A\xe9 B\xfb 2\x81 o\x9c ?*\f \x8c \x15 \xa8 )\" \xe8 \xff \x8d 8\xd5 !O\x17 \xc5 ㍀\x83 \xd3 ´\xca 1;\xf7 \xb0 \xf4 \x90 x\xa6 \x01 \x95 \x85 \xc0 \xaf \xf6 \x82 Qk\xab \xc1 \x82 <D\x93 \xcf \r \xdb \xdf \x1c \x94 \x17 Q\xfa S\xe6 \xcb \xd4 Xƿ\x80 \x1d \xc4 \x1c \x9d P74\x82 JK\v y\xe9 )\xbc hY\xbe \xcc |\xe4 \x97 \xdd <;3\x90 J\a \xee #\xb2 y\xe3 \t `\xef \xef \x1f \" k\x8b \x96 \xa0 \x98 \xd9 \xff s\xde &\xb7 \xa6 \x0e \xf1 \x7f 2ͅb\xe3 \xda 5\" c\\ K\xe2 1\xa2 \xec `\x1b \xe5 R\xe6 j\b @\x18 7\xe1 \xdb \x04 \xf6 bNO\x0e \x12 \x01 1\x1a ,/+WnKXQEM/AhXICYRNBeGk+WSuB+7OBuSYJTbP66Zyc=\" 2\n \x1b local-kek.kms.kubernetes.io\x12 \x13 encrypted-local-kek(\x01 "
1395
+ dekSourceHKDFSHA256XNonceAESGCMSeedPath := test .getETCDPathForResource (test .storageConfig .Prefix , "" , "secrets" , dekSourceHKDFSHA256XNonceAESGCMSeedName , legacyDataNamespace )
1396
+ if _ , err := test .writeRawRecordToETCD (dekSourceHKDFSHA256XNonceAESGCMSeedPath , []byte (dekSourceHKDFSHA256XNonceAESGCMSeedData )); err != nil {
1397
+ t .Fatal (err )
1398
+ }
1399
+
1400
+ expectedDEKSourceHKDFSHA256XNonceAESGCMSeedObject := & kmstypes.EncryptedObject {
1401
+ EncryptedData : []byte ("\x12 \x0f \x87 \xae \xa2 \xa2 \xf5 J\x11 \x06 о\x8a \x81 \xb6 \x15 \xdf 4H\xa3 \xb7 i\x93 ^)\xe5 i\xe2 \x7f \xfd o\xee \" \x17 0\xb7 \n \xa0 \v \xec \xe0 \xfa \t #\t Ɩ\xf6 ǧw\x01 \xb9 \xab \xb3 \xf4 \xdf \xec \x9e J\x95 $&Z=\x8a wAc\xa5 \xb2 ;\t \xd5 \xf9 \x05 \xc1 E)\x8b \xb8 \x14 \xc9 \xda \x14 {I\r V?\xe5 :\xf0 BM\x9b \xad \xaa Hn>W/Q\xa3 \xf5 \xba \xe7 ˚\n \xe7 \" \xa7 \\ p\x8c \xba 2\xf2 \xb0 x<Ą\x88 \x9a \xf1 \xb5 :d=z\xe3 \xc3 &\x03 \x99 m\x96 \xe7 \\ \xe3 \xa3 \xd7 i\xb2 \f \x84 g\xf9 4\xd2 \f \xd6 ~\xed \xac \xf8 \x1b \xc6 (,[\xd1 \xff \xba \x89 ȇD\x02 ):wTM12\xb5 \xfd l\xd2 \xf2 \x85 \x12 0\xd3 \xd9 aak\xce \xdd I֥\x0f k2\xf6 I\xd0 \xf9 \xc2 \xda \v ŗ\xd7 \u05fb \x83 \xd6 \xf7 \x1a \xbf \x13 iH\x8f \xe4 \xb3 #\xf3 \xdf \xc8 $y\r L(F\\ Xt\x86 \xbb \xe5 K\x88 =\x92 \xe9 \x04 \xf7 0\x1e \t >\xac ;\x9e \xe6 \xf0 +ۙ4\x1d \x1a V9Մ-g\xf3 \xc7 Z\x00 \xf7 3\x0e \xe7 \xa6 \xcf \xc4 \xfc \xe0 \xb2 \x1f \xa0 \xbb \x1a \x81 \xb3 \xe4 צ\x7f \xc6 \b \x94 ͉\xad @\xac \x81 \x01 5\x0f \xe8 A\xe9 B\xfb 2\x81 o\x9c ?*\f \x8c \x15 \xa8 )\" \xe8 \xff \x8d 8\xd5 !O\x17 \xc5 ㍀\x83 \xd3 ´\xca 1;\xf7 \xb0 \xf4 \x90 x\xa6 \x01 \x95 \x85 \xc0 \xaf \xf6 \x82 Qk\xab \xc1 \x82 <D\x93 \xcf \r \xdb \xdf \x1c \x94 \x17 Q\xfa S\xe6 \xcb \xd4 Xƿ\x80 \x1d \xc4 \x1c \x9d P74\x82 JK\v y\xe9 )\xbc hY\xbe \xcc |\xe4 \x97 \xdd <;3\x90 J\a \xee #\xb2 y\xe3 \t `\xef \xef \x1f \" k\x8b \x96 \xa0 \x98 \xd9 \xff s\xde &\xb7 \xa6 \x0e \xf1 \x7f 2ͅb\xe3 \xda 5\" c\\ K\xe2 1\xa2 \xec `\x1b \xe5 R\xe6 j\b @\x18 7\xe1 \xdb \x04 \xf6 bNO\x0e " ),
1402
+ KeyID : "1" ,
1403
+ EncryptedDEKSource : []byte ("/+WnKXQEM/AhXICYRNBeGk+WSuB+7OBuSYJTbP66Zyc=" ),
1404
+ Annotations : map [string ][]byte {"local-kek.kms.kubernetes.io" : []byte ("encrypted-local-kek" )},
1405
+ EncryptedDEKSourceType : kmstypes .EncryptedDEKSourceType_HKDF_SHA256_XNONCE_AES_GCM_SEED ,
1406
+ }
1407
+ legacyDEKSourceHKDFSHA256XNonceAESGCMSeedObject := & kmstypes.EncryptedObject {}
1408
+ if err := proto .Unmarshal ([]byte (strings .TrimPrefix (dekSourceHKDFSHA256XNonceAESGCMSeedData , "k8s:enc:kms:v2:kms-provider:" )), legacyDEKSourceHKDFSHA256XNonceAESGCMSeedObject ); err != nil {
1409
+ t .Fatal (err )
1410
+ }
1411
+ if err := kmsv2 .ValidateEncryptedObject (legacyDEKSourceHKDFSHA256XNonceAESGCMSeedObject ); err != nil {
1412
+ t .Fatal (err )
1413
+ }
1414
+ if diff := cmp .Diff (expectedDEKSourceHKDFSHA256XNonceAESGCMSeedObject , legacyDEKSourceHKDFSHA256XNonceAESGCMSeedObject ); len (diff ) > 0 {
1415
+ t .Errorf ("kms v2 legacy encrypted object diff (-want, +got):\n %s" , diff )
1416
+ }
1417
+
1418
+ ctx := testContext (t )
1419
+
1420
+ legacySecrets , err := test .restClient .CoreV1 ().Secrets (legacyDataNamespace ).List (ctx , metav1.ListOptions {})
1421
+ if err != nil {
1422
+ t .Fatal (err )
1423
+ }
1424
+
1425
+ dekSourceAESGCMKeyTime := metav1 .NewTime (time .Date (2023 , 9 , 1 , 11 , 56 , 49 , 0 , time .FixedZone ("EDT" , - 4 * 60 * 60 )))
1426
+ dekSourceHKDFSHA256XNonceAESGCMSeedTime := metav1 .NewTime (time .Date (2023 , 9 , 1 , 10 , 23 , 13 , 0 , time .FixedZone ("EDT" , - 4 * 60 * 60 )))
1427
+
1428
+ expectedLegacySecrets := & corev1.SecretList {
1429
+ Items : []corev1.Secret {
1430
+ {
1431
+ ObjectMeta : metav1.ObjectMeta {
1432
+ Name : dekSourceAESGCMKeyName ,
1433
+ Namespace : legacyDataNamespace ,
1434
+ UID : "1f4a8f7b-01b4-49d1-b898-751eb56937f1" ,
1435
+ CreationTimestamp : dekSourceAESGCMKeyTime ,
1436
+ ManagedFields : []metav1.ManagedFieldsEntry {
1437
+ {
1438
+ Manager : "___TestKMSv2Provider_in_k8s_io_kubernetes_test_integration_controlplane_transformation.test" ,
1439
+ Operation : "Update" ,
1440
+ APIVersion : "v1" ,
1441
+ Time : & dekSourceAESGCMKeyTime ,
1442
+ FieldsType : "FieldsV1" ,
1443
+ FieldsV1 : & metav1.FieldsV1 {Raw : []byte (`{"f:data":{".":{},"f:api_key":{}},"f:type":{}}` )},
1444
+ },
1445
+ },
1446
+ },
1447
+ Data : map [string ][]byte {
1448
+ secretKey : []byte (secretVal ),
1449
+ },
1450
+ Type : corev1 .SecretTypeOpaque ,
1451
+ },
1452
+ {
1453
+ ObjectMeta : metav1.ObjectMeta {
1454
+ Name : dekSourceHKDFSHA256XNonceAESGCMSeedName ,
1455
+ Namespace : legacyDataNamespace ,
1456
+ UID : "87c514b4-9c26-4041-ad0d-0d07dca557ed" ,
1457
+ CreationTimestamp : dekSourceHKDFSHA256XNonceAESGCMSeedTime ,
1458
+ ManagedFields : []metav1.ManagedFieldsEntry {
1459
+ {
1460
+ Manager : "___TestKMSv2Provider_extended_nonce_gcm_in_k8s_io_kubernetes_test_integration_controlplane_transformation.test" ,
1461
+ Operation : "Update" ,
1462
+ APIVersion : "v1" ,
1463
+ Time : & dekSourceHKDFSHA256XNonceAESGCMSeedTime ,
1464
+ FieldsType : "FieldsV1" ,
1465
+ FieldsV1 : & metav1.FieldsV1 {Raw : []byte (`{"f:data":{".":{},"f:api_key":{}},"f:type":{}}` )},
1466
+ },
1467
+ },
1468
+ },
1469
+ Data : map [string ][]byte {
1470
+ secretKey : []byte (secretVal ),
1471
+ },
1472
+ Type : corev1 .SecretTypeOpaque ,
1473
+ },
1474
+ },
1475
+ }
1476
+
1477
+ if diff := cmp .Diff (expectedLegacySecrets , legacySecrets ,
1478
+ // resource version is set after decoding based on etcd state - it is not stored in the etcd value
1479
+ cmpopts .IgnoreFields (corev1.Secret {}, "ResourceVersion" ),
1480
+ cmpopts .IgnoreFields (metav1.ListMeta {}, "ResourceVersion" ),
1481
+ ); len (diff ) > 0 {
1482
+ t .Errorf ("kms v2 legacy secret data diff (-want, +got):\n %s" , diff )
1483
+ }
1484
+ }
0 commit comments