@@ -10,6 +10,7 @@ import (
1010 "strings"
1111 "time"
1212
13+ "github.com/openshift/library-go/pkg/operator/encryption/kms"
1314 corev1 "k8s.io/api/core/v1"
1415 "k8s.io/apimachinery/pkg/api/errors"
1516 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -20,6 +21,7 @@ import (
2021 "k8s.io/klog/v2"
2122 "k8s.io/utils/ptr"
2223
24+ configv1 "github.com/openshift/api/config/v1"
2325 operatorv1 "github.com/openshift/api/operator/v1"
2426 configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
2527 configv1informers "github.com/openshift/client-go/config/informers/externalversions/config/v1"
@@ -159,11 +161,20 @@ 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 , kmsKeyIDHash , err = c .getKMSHashes (ctx , kmsConfig )
173+ if err != nil {
174+ return err
175+ }
176+ }
177+
167178 currentConfig , desiredEncryptionState , secrets , isProgressingReason , err := statemachine .GetEncryptionConfigAndState (ctx , c .deployer , c .secretClient , c .encryptionSecretSelector , encryptedGRs )
168179 if err != nil {
169180 return err
@@ -191,7 +202,7 @@ func (c *keyController) checkAndCreateKeys(ctx context.Context, syncContext fact
191202
192203 var commonReason * string
193204 for gr , grKeys := range desiredEncryptionState {
194- latestKeyID , internalReason , needed := needsNewKey (grKeys , currentMode , externalReason , encryptedGRs )
205+ latestKeyID , internalReason , needed := needsNewKey (grKeys , currentMode , externalReason , encryptedGRs , kmsConfigHash , kmsKeyIDHash )
195206 if ! needed {
196207 continue
197208 }
@@ -218,7 +229,7 @@ func (c *keyController) checkAndCreateKeys(ctx context.Context, syncContext fact
218229
219230 sort .Sort (sort .StringSlice (reasons ))
220231 internalReason := strings .Join (reasons , ", " )
221- keySecret , err := c .generateKeySecret (newKeyID , currentMode , internalReason , externalReason )
232+ keySecret , err := c .generateKeySecret (newKeyID , currentMode , internalReason , externalReason , kmsConfigHash , kmsKeyIDHash )
222233 if err != nil {
223234 return fmt .Errorf ("failed to create key: %v" , err )
224235 }
@@ -255,7 +266,7 @@ func (c *keyController) validateExistingSecret(ctx context.Context, keySecret *c
255266 return nil // we made this key earlier
256267}
257268
258- func (c * keyController ) generateKeySecret (keyID uint64 , currentMode state.Mode , internalReason , externalReason string ) (* corev1.Secret , error ) {
269+ func (c * keyController ) generateKeySecret (keyID uint64 , currentMode state.Mode , internalReason , externalReason , kmsConfigHash , kmsKeyIDHash string ) (* corev1.Secret , error ) {
259270 bs := crypto .ModeToNewKeyFunc [currentMode ]()
260271 ks := state.KeyState {
261272 Key : apiserverv1.Key {
@@ -265,40 +276,69 @@ func (c *keyController) generateKeySecret(keyID uint64, currentMode state.Mode,
265276 Mode : currentMode ,
266277 InternalReason : internalReason ,
267278 ExternalReason : externalReason ,
279+ KMSConfigHash : kmsConfigHash ,
280+ KMSKeyIDHash : kmsKeyIDHash ,
268281 }
269282 return secrets .FromKeyState (c .instanceName , ks )
270283}
271284
272- func (c * keyController ) getCurrentModeAndExternalReason (ctx context.Context ) (state.Mode , string , error ) {
285+ func (c * keyController ) getCurrentModeAndExternalReason (ctx context.Context ) (state.Mode , string , * configv1. KMSConfig , error ) {
273286 apiServer , err := c .apiServerClient .Get (ctx , "cluster" , metav1.GetOptions {})
274287 if err != nil {
275- return "" , "" , err
288+ return "" , "" , nil , err
276289 }
277290
278291 operatorSpec , _ , _ , err := c .operatorClient .GetOperatorState ()
279292 if err != nil {
280- return "" , "" , err
293+ return "" , "" , nil , err
281294 }
282295
283296 encryptionConfig , err := structuredUnsupportedConfigFrom (operatorSpec .UnsupportedConfigOverrides .Raw , c .unsupportedConfigPrefix )
284297 if err != nil {
285- return "" , "" , err
298+ return "" , "" , nil , err
286299 }
287300
288301 reason := encryptionConfig .Encryption .Reason
289302 switch currentMode := state .Mode (apiServer .Spec .Encryption .Type ); currentMode {
290303 case state .AESCBC , state .AESGCM , state .Identity : // secretbox is disabled for now
291- return currentMode , reason , nil
304+ return currentMode , reason , nil , nil
305+ case state .KMS :
306+ return currentMode , reason , apiServer .Spec .Encryption .KMS , nil
292307 case "" : // unspecified means use the default (which can change over time)
293- return state .DefaultMode , reason , nil
308+ return state .DefaultMode , reason , nil , nil
294309 default :
295- return "" , "" , fmt .Errorf ("unknown encryption mode configured: %s" , currentMode )
310+ return "" , "" , nil , fmt .Errorf ("unknown encryption mode configured: %s" , currentMode )
311+ }
312+ }
313+
314+ func (c * keyController ) getKMSHashes (ctx context.Context , kmsConfig * configv1.KMSConfig ) (string , string , error ) {
315+ // Generate unix socket path from KMS config and get the hash
316+ socketPath , configHash , err := kms .GenerateUnixSocketPath (kmsConfig )
317+ if err != nil {
318+ return "" , "" , fmt .Errorf ("failed to generate KMS unix socket path: %w" , err )
319+ }
320+
321+ kmsClient , err := kms .NewKMSClient (socketPath )
322+ if err != nil {
323+ return "" , "" , fmt .Errorf ("failed to create KMS client: %w" , err )
324+ }
325+ defer kmsClient .Close ()
326+
327+ statusResp , err := kmsClient .Status (ctx )
328+ if err != nil {
329+ return "" , "" , fmt .Errorf ("failed to call KMS Status endpoint: %w" , err )
330+ }
331+
332+ if statusResp .Healthz != "ok" {
333+ return "" , "" , fmt .Errorf ("KMS plugin is unhealthy: %s" , statusResp .Healthz )
296334 }
335+
336+ return configHash , kms .ComputeKMSKeyIDHash (statusResp .KeyID ), nil
297337}
298338
299339// needsNewKey checks whether a new key must be created for the given resource. If true, it also returns the latest
300340// used key ID and a reason string.
301- func needsNewKey (grKeys state.GroupResourceState , currentMode state.Mode , externalReason string , encryptedGRs []schema.GroupResource ) (uint64 , string , bool ) {
341+ func needsNewKey (grKeys state.GroupResourceState , currentMode state.Mode , externalReason string , encryptedGRs []schema.GroupResource , kmsConfigHash , kmsKeyIDHash string ) (uint64 , string , bool ) {
302342 // we always need to have some encryption keys unless we are turned off
303343 if len (grKeys .ReadKeys ) == 0 {
304344 return 0 , "key-does-not-exist" , currentMode != state .Identity
@@ -346,6 +386,21 @@ func needsNewKey(grKeys state.GroupResourceState, currentMode state.Mode, extern
346386 return latestKeyID , "external-reason-changed" , true
347387 }
348388
389+ // if we are using KMS, check if the KMS configuration or key ID hash has changed
390+ if currentMode == state .KMS {
391+ if latestKey .KMSConfigHash != kmsConfigHash && len (kmsConfigHash ) != 0 {
392+ return latestKeyID , "kms-config-changed" , true
393+ }
394+
395+ if latestKey .KMSKeyIDHash != kmsKeyIDHash && len (kmsKeyIDHash ) != 0 {
396+ return latestKeyID , "kms-key-id-changed" , true
397+ }
398+
399+ // For KMS mode, we don't do time-based rotation
400+ // KMS keys are rotated externally by the KMS system
401+ return 0 , "" , false
402+ }
403+
349404 // we check for encryptionSecretMigratedTimestamp set by migration controller to determine when migration completed
350405 // this also generates back pressure for key rotation when migration takes a long time or was recently completed
351406 return latestKeyID , "rotation-interval-has-passed" , time .Since (latestKey .Migrated .Timestamp ) > encryptionSecretMigrationInterval
0 commit comments