@@ -199,9 +199,18 @@ func (c *keyController) checkAndCreateKeys(ctx context.Context, syncContext fact
199199 // fills up the state with all resources and set identity write key if write key secrets
200200 // are missing.
201201
202+ var providerCfg kmsProviderConfig = noopKMSProviderConfig {}
203+ if currentMode == state .KMS {
204+ var err error
205+ providerCfg , err = newKMSProviderConfig (apiEncryptionConfiguration .KMS )
206+ if err != nil {
207+ return err
208+ }
209+ }
210+
202211 var commonReason * string
203212 for gr , grKeys := range desiredEncryptionState {
204- latestKeyID , internalReason , needed := needsNewKey (grKeys , currentMode , externalReason , encryptedGRs )
213+ latestKeyID , internalReason , needed := needsNewKey (grKeys , currentMode , externalReason , encryptedGRs , providerCfg )
205214 if ! needed {
206215 continue
207216 }
@@ -228,7 +237,7 @@ func (c *keyController) checkAndCreateKeys(ctx context.Context, syncContext fact
228237
229238 sort .Sort (sort .StringSlice (reasons ))
230239 internalReason := strings .Join (reasons , ", " )
231- keySecret , err := c .generateKeySecret (ctx , newKeyID , currentMode , apiEncryptionConfiguration , internalReason , externalReason )
240+ keySecret , err := c .generateKeySecret (ctx , newKeyID , currentMode , apiEncryptionConfiguration , providerCfg , internalReason , externalReason )
232241 if err != nil {
233242 return fmt .Errorf ("failed to create key: %v" , err )
234243 }
@@ -265,7 +274,7 @@ func (c *keyController) validateExistingSecret(ctx context.Context, keySecret *c
265274 return nil // we made this key earlier
266275}
267276
268- func (c * keyController ) generateKeySecret (ctx context.Context , keyID uint64 , currentMode state.Mode , apiServerEncryption configv1.APIServerEncryption , internalReason , externalReason string ) (* corev1.Secret , error ) {
277+ func (c * keyController ) generateKeySecret (ctx context.Context , keyID uint64 , currentMode state.Mode , apiServerEncryption configv1.APIServerEncryption , providerCfg kmsProviderConfig , internalReason , externalReason string ) (* corev1.Secret , error ) {
269278 bs := crypto .ModeToNewKeyFunc [currentMode ]()
270279 ks := state.KeyState {
271280 Key : apiserverv1.Key {
@@ -287,11 +296,6 @@ func (c *keyController) generateKeySecret(ctx context.Context, keyID uint64, cur
287296 Plugin : apiServerEncryption .KMS ,
288297 }
289298
290- providerCfg , err := newKMSProviderConfig (apiServerEncryption .KMS )
291- if err != nil {
292- return nil , err
293- }
294-
295299 if secretName , expectedKeys , err := providerCfg .referencedSecretName (); err != nil {
296300 return nil , err
297301 } else if len (secretName ) > 0 {
@@ -363,7 +367,7 @@ func (c *keyController) getCurrentModeReasonAndEncryptionConfig(ctx context.Cont
363367
364368// needsNewKey checks whether a new key must be created for the given resource. If true, it also returns the latest
365369// used key ID and a reason string.
366- func needsNewKey (grKeys state.GroupResourceState , currentMode state.Mode , externalReason string , encryptedGRs []schema.GroupResource ) (uint64 , string , bool ) {
370+ func needsNewKey (grKeys state.GroupResourceState , currentMode state.Mode , externalReason string , encryptedGRs []schema.GroupResource , providerCfg kmsProviderConfig ) (uint64 , string , bool ) {
367371 // we always need to have some encryption keys unless we are turned off
368372 if len (grKeys .ReadKeys ) == 0 {
369373 return 0 , "key-does-not-exist" , currentMode != state .Identity
@@ -408,13 +412,20 @@ func needsNewKey(grKeys state.GroupResourceState, currentMode state.Mode, extern
408412
409413 if currentMode == state .KMS {
410414 // We are here because Encryption Mode is not changed
415+ // However, we need to create a new key if migration-triggering fields
416+ // in the KMS provider configuration have changed.
417+ if latestKey .KMS == nil {
418+ // A KMS-mode key without KMS state indicates a corrupted key secret.
419+ // Do not create a new key on corrupted data.
420+ klog .Warningf ("KMS-mode key %q has nil KMS state, possibly corrupted key secret; skipping new key creation" , latestKey .Key .Name )
421+ return 0 , "" , false
422+ }
423+ if providerCfg .migrationRequired (latestKey .KMS .Plugin ) {
424+ return latestKeyID , "kms-provider-changed" , true
425+ }
411426
412- // For now in Tech Preview v1, we don't support configurational changes. Therefore,
413- // it is pointless comparing the secrets.
414-
415- // For KMS mode, we don't do time-based rotation. Therefore, we shortcut here
416- // KMS keys are rotated externally by the KMS system.
417- // Moreover, we don't trigger new key when external reason is changed.
427+ // For KMS mode, we don't do time-based rotation. KMS keys are rotated
428+ // externally by the KMS provider. Moreover, we don't trigger new key when external reason is changed.
418429 // Because it would lead to duplicate providers which is not allowed.
419430 return 0 , "" , false
420431 }
@@ -440,8 +451,19 @@ type kmsProviderConfig interface {
440451 // config and the specific data keys to carry from that configmap. Only the listed keys
441452 // are copied into the Key Secret; any other data in the referenced configmap is ignored.
442453 referencedConfigMapName () (string , []string , error )
454+ // migrationRequired reports whether switching from latest (stored in
455+ // the key secret) to this provider config requires a new encryption key.
456+ migrationRequired (latest configv1.KMSPluginConfig ) bool
443457}
444458
459+ // noopKMSProviderConfig is a safe zero-value implementation used for non-KMS modes.
460+ // All methods return empty/false so callers never need nil checks.
461+ type noopKMSProviderConfig struct {}
462+
463+ func (noopKMSProviderConfig ) referencedSecretName () (string , []string , error ) { return "" , nil , nil }
464+ func (noopKMSProviderConfig ) referencedConfigMapName () (string , []string , error ) { return "" , nil , nil }
465+ func (noopKMSProviderConfig ) migrationRequired (configv1.KMSPluginConfig ) bool { return false }
466+
445467func newKMSProviderConfig (plugin configv1.KMSPluginConfig ) (kmsProviderConfig , error ) {
446468 switch plugin .Type {
447469 case configv1 .VaultKMSProvider :
@@ -473,6 +495,30 @@ func (v *vaultProviderConfig) referencedConfigMapName() (string, []string, error
473495 return v .vault .TLS .CABundle .Name , []string {"ca-bundle.crt" }, nil
474496}
475497
498+ func (v * vaultProviderConfig ) migrationRequired (latest configv1.KMSPluginConfig ) bool {
499+ if latest .Type != configv1 .VaultKMSProvider {
500+ klog .V (2 ).Infof ("KMS migration required: provider type changed from %q to %q" , latest .Type , configv1 .VaultKMSProvider )
501+ return true
502+ }
503+ if v .vault .VaultAddress != latest .Vault .VaultAddress {
504+ klog .V (2 ).Infof ("KMS migration required: VaultAddress changed from %q to %q" , latest .Vault .VaultAddress , v .vault .VaultAddress )
505+ return true
506+ }
507+ if v .vault .VaultNamespace != latest .Vault .VaultNamespace {
508+ klog .V (2 ).Infof ("KMS migration required: VaultNamespace changed from %q to %q" , latest .Vault .VaultNamespace , v .vault .VaultNamespace )
509+ return true
510+ }
511+ if v .vault .TransitMount != latest .Vault .TransitMount {
512+ klog .V (2 ).Infof ("KMS migration required: TransitMount changed from %q to %q" , latest .Vault .TransitMount , v .vault .TransitMount )
513+ return true
514+ }
515+ if v .vault .TransitKey != latest .Vault .TransitKey {
516+ klog .V (2 ).Infof ("KMS migration required: TransitKey changed from %q to %q" , latest .Vault .TransitKey , v .vault .TransitKey )
517+ return true
518+ }
519+ return false
520+ }
521+
476522// TODO make this un-settable once set
477523// ex: we could require the tech preview no upgrade flag to be set before we will honor this field
478524type unsupportedEncryptionConfig struct {
0 commit comments