Skip to content

Commit 16d1ed4

Browse files
committed
Introduce KMS encryption mode into encryption controllers
1 parent e9c2485 commit 16d1ed4

File tree

12 files changed

+1181
-23
lines changed

12 files changed

+1181
-23
lines changed

pkg/operator/encryption/controllers/key_controller.go

Lines changed: 56 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010
"strings"
1111
"time"
1212

13+
configv1 "github.com/openshift/api/config/v1"
14+
"github.com/openshift/library-go/pkg/operator/encryption/kms"
1315
corev1 "k8s.io/api/core/v1"
1416
"k8s.io/apimachinery/pkg/api/errors"
1517
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -39,6 +41,9 @@ import (
3941
// greater than the last key's ID (the first key has a key ID of 1).
4042
const encryptionSecretMigrationInterval = time.Hour * 24 * 7 // one week
4143

44+
// kmsHashesGetter is a function type for getting KMS config and key ID hashes
45+
var kmsHashesGetterFunc func(ctx context.Context, kmsConfig *configv1.KMSConfig) (configHash string, keyIDHash []byte, err error)
46+
4247
// keyController creates new keys if necessary. It
4348
// * watches
4449
// - secrets in openshift-config-managed
@@ -104,6 +109,8 @@ func NewKeyController(
104109
secretClient: secretClient,
105110
}
106111

112+
kmsHashesGetterFunc = defaultGetKMSHashes
113+
107114
return factory.New().
108115
WithSync(c.sync).
109116
WithControllerInstanceName(c.controllerInstanceName).
@@ -159,11 +166,21 @@ func (c *keyController) sync(ctx context.Context, syncCtx factory.SyncContext) (
159166
}
160167

161168
func (c *keyController) checkAndCreateKeys(ctx context.Context, syncContext factory.SyncContext, encryptedGRs []schema.GroupResource) error {
162-
currentMode, externalReason, err := c.getCurrentModeAndExternalReason(ctx)
169+
currentMode, externalReason, kmsConfig, err := c.getCurrentModeAndExternalReason(ctx)
163170
if err != nil {
164171
return err
165172
}
166173

174+
// Compute KMS hashes if using KMS mode
175+
var kmsConfigHash string
176+
var kmsKeyHash []byte
177+
if currentMode == state.KMS && kmsConfig != nil {
178+
kmsConfigHash, kmsKeyHash, err = kmsHashesGetterFunc(ctx, kmsConfig)
179+
if err != nil {
180+
return err
181+
}
182+
}
183+
167184
currentConfig, desiredEncryptionState, secrets, isProgressingReason, err := statemachine.GetEncryptionConfigAndState(ctx, c.deployer, c.secretClient, c.encryptionSecretSelector, encryptedGRs)
168185
if err != nil {
169186
return err
@@ -191,7 +208,7 @@ func (c *keyController) checkAndCreateKeys(ctx context.Context, syncContext fact
191208

192209
var commonReason *string
193210
for gr, grKeys := range desiredEncryptionState {
194-
latestKeyID, internalReason, needed := needsNewKey(grKeys, currentMode, externalReason, encryptedGRs)
211+
latestKeyID, internalReason, needed := needsNewKey(grKeys, currentMode, externalReason, encryptedGRs, kmsKeyHash)
195212
if !needed {
196213
continue
197214
}
@@ -218,7 +235,7 @@ func (c *keyController) checkAndCreateKeys(ctx context.Context, syncContext fact
218235

219236
sort.Sort(sort.StringSlice(reasons))
220237
internalReason := strings.Join(reasons, ", ")
221-
keySecret, err := c.generateKeySecret(newKeyID, currentMode, internalReason, externalReason)
238+
keySecret, err := c.generateKeySecret(newKeyID, currentMode, internalReason, externalReason, kmsConfigHash, kmsKeyHash)
222239
if err != nil {
223240
return fmt.Errorf("failed to create key: %v", err)
224241
}
@@ -255,8 +272,8 @@ func (c *keyController) validateExistingSecret(ctx context.Context, keySecret *c
255272
return nil // we made this key earlier
256273
}
257274

258-
func (c *keyController) generateKeySecret(keyID uint64, currentMode state.Mode, internalReason, externalReason string) (*corev1.Secret, error) {
259-
bs := crypto.ModeToNewKeyFunc[currentMode]()
275+
func (c *keyController) generateKeySecret(keyID uint64, currentMode state.Mode, internalReason, externalReason string, kmsConfigHash string, kmsKeyIDHash []byte) (*corev1.Secret, error) {
276+
bs := crypto.ModeToNewKeyFunc[currentMode](kmsKeyIDHash)
260277
ks := state.KeyState{
261278
Key: apiserverv1.Key{
262279
Name: fmt.Sprintf("%d", keyID),
@@ -265,40 +282,55 @@ func (c *keyController) generateKeySecret(keyID uint64, currentMode state.Mode,
265282
Mode: currentMode,
266283
InternalReason: internalReason,
267284
ExternalReason: externalReason,
285+
KMSConfigHash: kmsConfigHash,
268286
}
269287
return secrets.FromKeyState(c.instanceName, ks)
270288
}
271289

272-
func (c *keyController) getCurrentModeAndExternalReason(ctx context.Context) (state.Mode, string, error) {
290+
// defaultGetKMSHashes is the default implementation of getting KMS hashes
291+
func defaultGetKMSHashes(ctx context.Context, kmsConfig *configv1.KMSConfig) (string, []byte, error) {
292+
_, configHash, err := kms.GenerateUnixSocketPath(kmsConfig)
293+
if err != nil {
294+
return "", nil, fmt.Errorf("failed to generate KMS unix socket path: %w", err)
295+
}
296+
297+
// TODO: We'll also need to obtain keyId from Status endpoint of KMS plugin to track the key rotation.
298+
keyId := "static-key-id"
299+
return configHash, kms.ComputeKMSKeyHash(configHash, keyId), nil
300+
}
301+
302+
func (c *keyController) getCurrentModeAndExternalReason(ctx context.Context) (state.Mode, string, *configv1.KMSConfig, error) {
273303
apiServer, err := c.apiServerClient.Get(ctx, "cluster", metav1.GetOptions{})
274304
if err != nil {
275-
return "", "", err
305+
return "", "", nil, err
276306
}
277307

278308
operatorSpec, _, _, err := c.operatorClient.GetOperatorState()
279309
if err != nil {
280-
return "", "", err
310+
return "", "", nil, err
281311
}
282312

283313
encryptionConfig, err := structuredUnsupportedConfigFrom(operatorSpec.UnsupportedConfigOverrides.Raw, c.unsupportedConfigPrefix)
284314
if err != nil {
285-
return "", "", err
315+
return "", "", nil, err
286316
}
287317

288318
reason := encryptionConfig.Encryption.Reason
289319
switch currentMode := state.Mode(apiServer.Spec.Encryption.Type); currentMode {
290320
case state.AESCBC, state.AESGCM, state.Identity: // secretbox is disabled for now
291-
return currentMode, reason, nil
321+
return currentMode, reason, nil, nil
322+
case state.KMS:
323+
return currentMode, reason, apiServer.Spec.Encryption.KMS, nil
292324
case "": // unspecified means use the default (which can change over time)
293-
return state.DefaultMode, reason, nil
325+
return state.DefaultMode, reason, nil, nil
294326
default:
295-
return "", "", fmt.Errorf("unknown encryption mode configured: %s", currentMode)
327+
return "", "", nil, fmt.Errorf("unknown encryption mode configured: %s", currentMode)
296328
}
297329
}
298330

299331
// needsNewKey checks whether a new key must be created for the given resource. If true, it also returns the latest
300332
// used key ID and a reason string.
301-
func needsNewKey(grKeys state.GroupResourceState, currentMode state.Mode, externalReason string, encryptedGRs []schema.GroupResource) (uint64, string, bool) {
333+
func needsNewKey(grKeys state.GroupResourceState, currentMode state.Mode, externalReason string, encryptedGRs []schema.GroupResource, kmsKeyHash []byte) (uint64, string, bool) {
302334
// we always need to have some encryption keys unless we are turned off
303335
if len(grKeys.ReadKeys) == 0 {
304336
return 0, "key-does-not-exist", currentMode != state.Identity
@@ -346,6 +378,17 @@ func needsNewKey(grKeys state.GroupResourceState, currentMode state.Mode, extern
346378
return latestKeyID, "external-reason-changed", true
347379
}
348380

381+
// if we are using KMS, check if the KMS configuration or key ID hash has changed
382+
if currentMode == state.KMS {
383+
if latestKey.Key.Secret != base64.StdEncoding.EncodeToString(kmsKeyHash) {
384+
return latestKeyID, "kms-key-changed", true
385+
}
386+
387+
// For KMS mode, we don't do time-based rotation
388+
// KMS keys are rotated externally by the KMS system
389+
return 0, "", false
390+
}
391+
349392
// we check for encryptionSecretMigratedTimestamp set by migration controller to determine when migration completed
350393
// this also generates back pressure for key rotation when migration takes a long time or was recently completed
351394
return latestKeyID, "rotation-interval-has-passed", time.Since(latestKey.Migrated.Timestamp) > encryptionSecretMigrationInterval

0 commit comments

Comments
 (0)