Skip to content

Commit feb2782

Browse files
committed
Introduce kms to kms migration
1 parent 3febb81 commit feb2782

3 files changed

Lines changed: 373 additions & 23 deletions

File tree

pkg/operator/encryption/controllers/key_controller.go

Lines changed: 61 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
445467
func 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
478524
type unsupportedEncryptionConfig struct {

0 commit comments

Comments
 (0)