@@ -20,13 +20,15 @@ import (
20
20
"k8s.io/klog/v2"
21
21
"k8s.io/utils/ptr"
22
22
23
+ configv1 "github.com/openshift/api/config/v1"
23
24
operatorv1 "github.com/openshift/api/operator/v1"
24
25
configv1client "github.com/openshift/client-go/config/clientset/versioned/typed/config/v1"
25
26
configv1informers "github.com/openshift/client-go/config/informers/externalversions/config/v1"
26
27
applyoperatorv1 "github.com/openshift/client-go/operator/applyconfigurations/operator/v1"
27
28
28
29
"github.com/openshift/library-go/pkg/controller/factory"
29
30
"github.com/openshift/library-go/pkg/operator/encryption/crypto"
31
+ "github.com/openshift/library-go/pkg/operator/encryption/encryptionconfig"
30
32
"github.com/openshift/library-go/pkg/operator/encryption/secrets"
31
33
"github.com/openshift/library-go/pkg/operator/encryption/state"
32
34
"github.com/openshift/library-go/pkg/operator/encryption/statemachine"
@@ -159,7 +161,7 @@ func (c *keyController) sync(ctx context.Context, syncCtx factory.SyncContext) (
159
161
}
160
162
161
163
func (c * keyController ) checkAndCreateKeys (ctx context.Context , syncContext factory.SyncContext , encryptedGRs []schema.GroupResource ) error {
162
- currentMode , externalReason , err := c .getCurrentModeAndExternalReason (ctx )
164
+ currentKeyState , err := c .getCurrentEncryptionModeWithExternalReason (ctx )
163
165
if err != nil {
164
166
return err
165
167
}
@@ -175,13 +177,15 @@ func (c *keyController) checkAndCreateKeys(ctx context.Context, syncContext fact
175
177
176
178
// avoid intended start of encryption
177
179
hasBeenOnBefore := currentConfig != nil || len (secrets ) > 0
178
- if currentMode == state .Identity && ! hasBeenOnBefore {
180
+ if currentKeyState . Mode == state .Identity && ! hasBeenOnBefore {
179
181
return nil
180
182
}
181
183
182
184
var (
183
185
newKeyRequired bool
184
186
newKeyID uint64
187
+ latestKeyID uint64
188
+ ok bool
185
189
reasons []string
186
190
)
187
191
@@ -191,23 +195,34 @@ func (c *keyController) checkAndCreateKeys(ctx context.Context, syncContext fact
191
195
192
196
var commonReason * string
193
197
for gr , grKeys := range desiredEncryptionState {
194
- latestKeyID , internalReason , needed := needsNewKey (grKeys , currentMode , externalReason , encryptedGRs )
198
+ // if kmsKeyID in GR ReadKey is not the same as current kmsKeyID, needed is true.
199
+ ks , needed := needsNewKeyWithInternalReason (grKeys , currentKeyState .Mode , currentKeyState .KMSKeyID , currentKeyState .ExternalReason , encryptedGRs )
195
200
if ! needed {
196
201
continue
197
202
}
198
203
204
+ if ks .Mode != state .KMS {
205
+ latestKeyID , ok = state .NameToKeyID (ks .Key .Name )
206
+ if ! ok {
207
+ latestKeyID = 0
208
+ }
209
+ }
210
+
199
211
if commonReason == nil {
200
- commonReason = & internalReason
201
- } else if * commonReason != internalReason {
212
+ commonReason = & ks . InternalReason
213
+ } else if * commonReason != ks . InternalReason {
202
214
commonReason = ptr .To ("" ) // this means we have no common reason
203
215
}
204
216
205
217
newKeyRequired = true
218
+
219
+ // tracking the newKeyID is only required for non-KMS
206
220
nextKeyID := latestKeyID + 1
207
- if newKeyID < nextKeyID {
221
+ if ks . Mode != state . KMS && newKeyID < nextKeyID {
208
222
newKeyID = nextKeyID
209
223
}
210
- reasons = append (reasons , fmt .Sprintf ("%s-%s" , gr .Resource , internalReason ))
224
+
225
+ reasons = append (reasons , fmt .Sprintf ("%s-%s" , gr .Resource , ks .InternalReason ))
211
226
}
212
227
if ! newKeyRequired {
213
228
return nil
@@ -216,12 +231,20 @@ func (c *keyController) checkAndCreateKeys(ctx context.Context, syncContext fact
216
231
reasons = []string {* commonReason } // don't repeat reasons
217
232
}
218
233
219
- sort .Sort (sort .StringSlice (reasons ))
220
- internalReason := strings .Join (reasons , ", " )
221
- keySecret , err := c .generateKeySecret (newKeyID , currentMode , internalReason , externalReason )
234
+ sort .Strings (reasons )
235
+ currentKeyState .InternalReason = strings .Join (reasons , ", " )
236
+
237
+ var keySecret * corev1.Secret
238
+ if currentKeyState .Mode == state .KMS {
239
+ keySecret , err = c .generateKMSKeySecret (currentKeyState .KMSConfig , currentKeyState .InternalReason , currentKeyState .ExternalReason )
240
+ } else {
241
+ keySecret , err = c .generateLocalKeySecret (newKeyID , currentKeyState .Mode , currentKeyState .InternalReason , currentKeyState .ExternalReason )
242
+ }
243
+
222
244
if err != nil {
223
245
return fmt .Errorf ("failed to create key: %v" , err )
224
246
}
247
+
225
248
_ , createErr := c .secretClient .Secrets ("openshift-config-managed" ).Create (ctx , keySecret , metav1.CreateOptions {})
226
249
if errors .IsAlreadyExists (createErr ) {
227
250
return c .validateExistingSecret (ctx , keySecret , newKeyID )
@@ -242,20 +265,31 @@ func (c *keyController) validateExistingSecret(ctx context.Context, keySecret *c
242
265
return err
243
266
}
244
267
268
+ ks , err := secrets .ToKeyState (actualKeySecret )
269
+ if err != nil {
270
+ return fmt .Errorf ("secret %s/%s is invalid, new keys cannot be created for encryption target" , keySecret .Namespace , keySecret .Name )
271
+ }
272
+
273
+ if ks .Mode == state .KMS && ks .KMSKeyID != "" {
274
+ return nil
275
+ }
276
+
277
+ if ks .Mode == state .KMS && ks .KMSKeyID == "" {
278
+ // kmsKeyID is mandatory in case of KMS
279
+ return fmt .Errorf ("secret %s/%s is invalid, new KMS keys cannot be created for encryption target" , keySecret .Namespace , keySecret .Name )
280
+ }
281
+
282
+ // checks for local aes (non-KMS) keys only
245
283
actualKeyID , ok := state .NameToKeyID (actualKeySecret .Name )
246
284
if ! ok || actualKeyID != keyID {
247
285
// TODO we can just get stuck in degraded here ...
248
- return fmt .Errorf ("secret %s has an invalid name, new keys cannot be created for encryption target" , keySecret .Name )
249
- }
250
-
251
- if _ , err := secrets .ToKeyState (actualKeySecret ); err != nil {
252
- return fmt .Errorf ("secret %s is invalid, new keys cannot be created for encryption target" , keySecret .Name )
286
+ return fmt .Errorf ("secret %s/%s has an invalid name, new keys cannot be created for encryption target" , keySecret .Namespace , keySecret .Name )
253
287
}
254
288
255
289
return nil // we made this key earlier
256
290
}
257
291
258
- func (c * keyController ) generateKeySecret (keyID uint64 , currentMode state.Mode , internalReason , externalReason string ) (* corev1.Secret , error ) {
292
+ func (c * keyController ) generateLocalKeySecret (keyID uint64 , currentMode state.Mode , internalReason , externalReason string ) (* corev1.Secret , error ) {
259
293
bs := crypto .ModeToNewKeyFunc [currentMode ]()
260
294
ks := state.KeyState {
261
295
Key : apiserverv1.Key {
@@ -269,50 +303,85 @@ func (c *keyController) generateKeySecret(keyID uint64, currentMode state.Mode,
269
303
return secrets .FromKeyState (c .instanceName , ks )
270
304
}
271
305
272
- func (c * keyController ) getCurrentModeAndExternalReason (ctx context.Context ) (state.Mode , string , error ) {
306
+ func (c * keyController ) generateKMSKeySecret (kmsConfig * configv1.KMSConfig , internalReason , externalReason string ) (* corev1.Secret , error ) {
307
+ kmsConfig = kmsConfig .DeepCopy ()
308
+
309
+ kmsKeyID , err := encryptionconfig .HashKMSConfig (* kmsConfig )
310
+ if err != nil {
311
+ return nil , err
312
+ }
313
+
314
+ ks := state.KeyState {
315
+ Mode : state .KMS ,
316
+ InternalReason : internalReason ,
317
+ ExternalReason : externalReason ,
318
+ KMSKeyID : kmsKeyID ,
319
+ KMSConfig : kmsConfig ,
320
+ }
321
+ return secrets .FromKeyState (c .instanceName , ks )
322
+ }
323
+
324
+ func (c * keyController ) getCurrentEncryptionModeWithExternalReason (ctx context.Context ) (state.KeyState , error ) {
273
325
apiServer , err := c .apiServerClient .Get (ctx , "cluster" , metav1.GetOptions {})
274
326
if err != nil {
275
- return "" , "" , err
327
+ return state. KeyState {} , err
276
328
}
277
329
278
330
operatorSpec , _ , _ , err := c .operatorClient .GetOperatorState ()
279
331
if err != nil {
280
- return "" , "" , err
332
+ return state. KeyState {} , err
281
333
}
282
334
283
335
encryptionConfig , err := structuredUnsupportedConfigFrom (operatorSpec .UnsupportedConfigOverrides .Raw , c .unsupportedConfigPrefix )
284
336
if err != nil {
285
- return "" , "" , err
337
+ return state. KeyState {} , err
286
338
}
287
339
288
340
reason := encryptionConfig .Encryption .Reason
289
341
switch currentMode := state .Mode (apiServer .Spec .Encryption .Type ); currentMode {
290
342
case state .AESCBC , state .AESGCM , state .Identity : // secretbox is disabled for now
291
- return currentMode , reason , nil
343
+ return state.KeyState {Mode : currentMode , ExternalReason : reason }, nil
344
+ case state .KMS :
345
+ kmsConfig := apiServer .Spec .Encryption .KMS .DeepCopy ()
346
+
347
+ kmsKeyID , err := encryptionconfig .HashKMSConfig (* kmsConfig )
348
+ if err != nil {
349
+ return state.KeyState {}, fmt .Errorf ("encryption mode configured: %s, but provided kms config could not generate required kms key id %v" , currentMode , err )
350
+ }
351
+
352
+ ks := state.KeyState {
353
+ Mode : state .KMS ,
354
+ KMSKeyID : kmsKeyID ,
355
+ KMSConfig : kmsConfig ,
356
+ ExternalReason : reason ,
357
+ }
358
+ return ks , nil
292
359
case "" : // unspecified means use the default (which can change over time)
293
- return state .DefaultMode , reason , nil
360
+ return state.KeyState { Mode : state . DefaultMode , ExternalReason : reason } , nil
294
361
default :
295
- return "" , "" , fmt .Errorf ("unknown encryption mode configured: %s" , currentMode )
362
+ return state. KeyState {} , fmt .Errorf ("unknown encryption mode configured: %s" , currentMode )
296
363
}
297
364
}
298
365
299
- // needsNewKey checks whether a new key must be created for the given resource. If true, it also returns the latest
366
+ // needsNewKeyWithInternalReason checks whether a new key must be created for the given resource. If true, it also returns the latest
300
367
// used key ID and a reason string.
301
- func needsNewKey (grKeys state.GroupResourceState , currentMode state.Mode , externalReason string , encryptedGRs []schema.GroupResource ) (uint64 , string , bool ) {
368
+ func needsNewKeyWithInternalReason (grKeys state.GroupResourceState , currentMode state.Mode , optionalCurrentKMSKeyID string , externalReason string , encryptedGRs []schema.GroupResource ) (state. KeyState , bool ) {
302
369
// we always need to have some encryption keys unless we are turned off
303
370
if len (grKeys .ReadKeys ) == 0 {
304
- return 0 , "key-does-not-exist" , currentMode != state .Identity
371
+ return state. KeyState { InternalReason : "key-does-not-exist" } , currentMode != state .Identity
305
372
}
306
373
307
374
latestKey := grKeys .ReadKeys [0 ]
308
375
latestKeyID , ok := state .NameToKeyID (latestKey .Key .Name )
309
376
if ! ok {
310
- return latestKeyID , fmt .Sprintf ("key-secret-%d-is-invalid" , latestKeyID ), true
377
+ latestKey .InternalReason = fmt .Sprintf ("key-secret-%d-is-invalid" , latestKeyID )
378
+ return latestKey , true
311
379
}
312
380
313
381
// if latest secret has been deleted, we will never be able to migrate to that key.
314
382
if ! latestKey .Backed {
315
- return latestKeyID , fmt .Sprintf ("encryption-config-key-%d-not-backed-by-secret" , latestKeyID ), true
383
+ latestKey .InternalReason = fmt .Sprintf ("encryption-config-key-%d-not-backed-by-secret" , latestKeyID )
384
+ return latestKey , true
316
385
}
317
386
318
387
// check that we have pruned read-keys: the write-keys, plus at most one more backed read-key (potentially some unbacked once before)
@@ -323,32 +392,41 @@ func needsNewKey(grKeys state.GroupResourceState, currentMode state.Mode, extern
323
392
}
324
393
}
325
394
if backedKeys > 2 {
326
- return 0 , "" , false
395
+ return state. KeyState {} , false
327
396
}
328
397
329
398
// we have not migrated the latest key, do nothing until that is complete
330
399
if allMigrated , _ , _ := state .MigratedFor (encryptedGRs , latestKey ); ! allMigrated {
331
- return 0 , "" , false
400
+ return state. KeyState {} , false
332
401
}
333
402
334
403
// if the most recent secret was encrypted in a mode different than the current mode, we need to generate a new key
335
404
if latestKey .Mode != currentMode {
336
- return latestKeyID , "encryption-mode-changed" , true
405
+ latestKey .InternalReason = "encryption-mode-changed"
406
+ return latestKey , true
337
407
}
338
408
339
409
// if the most recent secret turned off encryption and we want to keep it that way, do nothing
340
410
if latestKey .Mode == state .Identity && currentMode == state .Identity {
341
- return 0 , "" , false
411
+ return state.KeyState {}, false
412
+ }
413
+
414
+ // if the hash of the kms config (kmsKeyID) has updated, we need a new KMS backing secret
415
+ if currentMode == state .KMS && latestKey .KMSKeyID != optionalCurrentKMSKeyID {
416
+ latestKey .InternalReason = "kms-config-changed"
417
+ return latestKey , true
342
418
}
343
419
344
420
// if the most recent secret has a different external reason than the current reason, we need to generate a new key
345
421
if latestKey .ExternalReason != externalReason && len (externalReason ) != 0 {
346
- return latestKeyID , "external-reason-changed" , true
422
+ latestKey .InternalReason = "external-reason-changed"
423
+ return latestKey , true
347
424
}
348
425
349
426
// we check for encryptionSecretMigratedTimestamp set by migration controller to determine when migration completed
350
427
// this also generates back pressure for key rotation when migration takes a long time or was recently completed
351
- return latestKeyID , "rotation-interval-has-passed" , time .Since (latestKey .Migrated .Timestamp ) > encryptionSecretMigrationInterval
428
+ latestKey .InternalReason = "rotation-interval-has-passed"
429
+ return latestKey , time .Since (latestKey .Migrated .Timestamp ) > encryptionSecretMigrationInterval
352
430
}
353
431
354
432
// TODO make this un-settable once set
0 commit comments