@@ -20,13 +20,15 @@ import (
2020 "k8s.io/klog/v2"
2121 "k8s.io/utils/ptr"
2222
23+ configv1 "github.com/openshift/api/config/v1"
2324 operatorv1 "github.com/openshift/api/operator/v1"
2425 configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
2526 configv1informers "github.com/openshift/client-go/config/informers/externalversions/config/v1"
2627 applyoperatorv1 "github.com/openshift/client-go/operator/applyconfigurations/operator/v1"
2728
2829 "github.com/openshift/library-go/pkg/controller/factory"
2930 "github.com/openshift/library-go/pkg/operator/encryption/crypto"
31+ "github.com/openshift/library-go/pkg/operator/encryption/kms"
3032 "github.com/openshift/library-go/pkg/operator/encryption/secrets"
3133 "github.com/openshift/library-go/pkg/operator/encryption/state"
3234 "github.com/openshift/library-go/pkg/operator/encryption/statemachine"
@@ -159,11 +161,46 @@ func (c *keyController) sync(ctx context.Context, syncCtx factory.SyncContext) (
159161}
160162
161163func (c * keyController ) checkAndCreateKeys (ctx context.Context , syncContext factory.SyncContext , encryptedGRs []schema.GroupResource ) error {
162- currentMode , externalReason , err := c .getCurrentModeAndExternalReason (ctx )
164+ currentMode , externalReason , kmsConfig , err := c .getCurrentModeAndExternalReason (ctx )
163165 if err != nil {
164166 return err
165167 }
166168
169+ // Compute KMS hashes if using KMS mode
170+ var kmsConfigHash , kmsKeyIDHash string
171+ if currentMode == state .KMS && kmsConfig != nil {
172+ kmsConfigHash , err = kms .ComputeKMSConfigHash (kmsConfig )
173+ if err != nil {
174+ return fmt .Errorf ("failed to compute KMS config hash: %w" , err )
175+ }
176+
177+ // Generate unix socket path from KMS config
178+ socketPath , err := kms .GenerateUnixSocketPath (kmsConfig )
179+ if err != nil {
180+ return fmt .Errorf ("failed to generate KMS unix socket path: %w" , err )
181+ }
182+
183+ // Create KMS client and call Status endpoint
184+ kmsClient , err := kms .NewKMSClient (ctx , socketPath )
185+ if err != nil {
186+ return fmt .Errorf ("failed to create KMS client: %w" , err )
187+ }
188+ defer kmsClient .Close ()
189+
190+ statusResp , err := kmsClient .Status (ctx )
191+ if err != nil {
192+ return fmt .Errorf ("failed to call KMS Status endpoint: %w" , err )
193+ }
194+
195+ // Check if KMS plugin is healthy
196+ if statusResp .Healthz != "ok" {
197+ return fmt .Errorf ("KMS plugin is unhealthy: %s" , statusResp .Healthz )
198+ }
199+
200+ // Compute hash of the KeyID returned by KMS
201+ kmsKeyIDHash = kms .ComputeKMSKeyIDHash (statusResp .KeyID )
202+ }
203+
167204 currentConfig , desiredEncryptionState , secrets , isProgressingReason , err := statemachine .GetEncryptionConfigAndState (ctx , c .deployer , c .secretClient , c .encryptionSecretSelector , encryptedGRs )
168205 if err != nil {
169206 return err
@@ -191,7 +228,7 @@ func (c *keyController) checkAndCreateKeys(ctx context.Context, syncContext fact
191228
192229 var commonReason * string
193230 for gr , grKeys := range desiredEncryptionState {
194- latestKeyID , internalReason , needed := needsNewKey (grKeys , currentMode , externalReason , encryptedGRs )
231+ latestKeyID , internalReason , needed := needsNewKey (grKeys , currentMode , externalReason , encryptedGRs , kmsConfigHash , kmsKeyIDHash )
195232 if ! needed {
196233 continue
197234 }
@@ -218,7 +255,7 @@ func (c *keyController) checkAndCreateKeys(ctx context.Context, syncContext fact
218255
219256 sort .Sort (sort .StringSlice (reasons ))
220257 internalReason := strings .Join (reasons , ", " )
221- keySecret , err := c .generateKeySecret (newKeyID , currentMode , internalReason , externalReason )
258+ keySecret , err := c .generateKeySecret (newKeyID , currentMode , internalReason , externalReason , kmsConfigHash , kmsKeyIDHash )
222259 if err != nil {
223260 return fmt .Errorf ("failed to create key: %v" , err )
224261 }
@@ -255,7 +292,7 @@ func (c *keyController) validateExistingSecret(ctx context.Context, keySecret *c
255292 return nil // we made this key earlier
256293}
257294
258- func (c * keyController ) generateKeySecret (keyID uint64 , currentMode state.Mode , internalReason , externalReason string ) (* corev1.Secret , error ) {
295+ func (c * keyController ) generateKeySecret (keyID uint64 , currentMode state.Mode , internalReason , externalReason , kmsConfigHash , kmsKeyIDHash string ) (* corev1.Secret , error ) {
259296 bs := crypto .ModeToNewKeyFunc [currentMode ]()
260297 ks := state.KeyState {
261298 Key : apiserverv1.Key {
@@ -265,40 +302,44 @@ func (c *keyController) generateKeySecret(keyID uint64, currentMode state.Mode,
265302 Mode : currentMode ,
266303 InternalReason : internalReason ,
267304 ExternalReason : externalReason ,
305+ KMSConfigHash : kmsConfigHash ,
306+ KMSKeyIDHash : kmsKeyIDHash ,
268307 }
269308 return secrets .FromKeyState (c .instanceName , ks )
270309}
271310
272- func (c * keyController ) getCurrentModeAndExternalReason (ctx context.Context ) (state.Mode , string , error ) {
311+ func (c * keyController ) getCurrentModeAndExternalReason (ctx context.Context ) (state.Mode , string , * configv1. KMSConfig , error ) {
273312 apiServer , err := c .apiServerClient .Get (ctx , "cluster" , metav1.GetOptions {})
274313 if err != nil {
275- return "" , "" , err
314+ return "" , "" , nil , err
276315 }
277316
278317 operatorSpec , _ , _ , err := c .operatorClient .GetOperatorState ()
279318 if err != nil {
280- return "" , "" , err
319+ return "" , "" , nil , err
281320 }
282321
283322 encryptionConfig , err := structuredUnsupportedConfigFrom (operatorSpec .UnsupportedConfigOverrides .Raw , c .unsupportedConfigPrefix )
284323 if err != nil {
285- return "" , "" , err
324+ return "" , "" , nil , err
286325 }
287326
288327 reason := encryptionConfig .Encryption .Reason
289328 switch currentMode := state .Mode (apiServer .Spec .Encryption .Type ); currentMode {
290329 case state .AESCBC , state .AESGCM , state .Identity : // secretbox is disabled for now
291- return currentMode , reason , nil
330+ return currentMode , reason , nil , nil
331+ case state .KMS :
332+ return currentMode , reason , apiServer .Spec .Encryption .KMS , nil
292333 case "" : // unspecified means use the default (which can change over time)
293- return state .DefaultMode , reason , nil
334+ return state .DefaultMode , reason , nil , nil
294335 default :
295- return "" , "" , fmt .Errorf ("unknown encryption mode configured: %s" , currentMode )
336+ return "" , "" , nil , fmt .Errorf ("unknown encryption mode configured: %s" , currentMode )
296337 }
297338}
298339
299340// needsNewKey checks whether a new key must be created for the given resource. If true, it also returns the latest
300341// used key ID and a reason string.
301- func needsNewKey (grKeys state.GroupResourceState , currentMode state.Mode , externalReason string , encryptedGRs []schema.GroupResource ) (uint64 , string , bool ) {
342+ func needsNewKey (grKeys state.GroupResourceState , currentMode state.Mode , externalReason string , encryptedGRs []schema.GroupResource , kmsConfigHash , kmsKeyIDHash string ) (uint64 , string , bool ) {
302343 // we always need to have some encryption keys unless we are turned off
303344 if len (grKeys .ReadKeys ) == 0 {
304345 return 0 , "key-does-not-exist" , currentMode != state .Identity
@@ -346,6 +387,21 @@ func needsNewKey(grKeys state.GroupResourceState, currentMode state.Mode, extern
346387 return latestKeyID , "external-reason-changed" , true
347388 }
348389
390+ // if we are using KMS, check if the KMS configuration or key ID hash has changed
391+ if currentMode == state .KMS {
392+ if latestKey .KMSConfigHash != kmsConfigHash && len (kmsConfigHash ) != 0 {
393+ return latestKeyID , "kms-config-changed" , true
394+ }
395+
396+ if latestKey .KMSKeyIDHash != kmsKeyIDHash && len (kmsKeyIDHash ) != 0 {
397+ return latestKeyID , "kms-key-id-changed" , true
398+ }
399+
400+ // For KMS mode, we don't do time-based rotation
401+ // KMS keys are rotated externally by the KMS system
402+ return 0 , "" , false
403+ }
404+
349405 // we check for encryptionSecretMigratedTimestamp set by migration controller to determine when migration completed
350406 // this also generates back pressure for key rotation when migration takes a long time or was recently completed
351407 return latestKeyID , "rotation-interval-has-passed" , time .Since (latestKey .Migrated .Timestamp ) > encryptionSecretMigrationInterval
0 commit comments