Skip to content

Commit 01cd762

Browse files
authored
encrypter: Ignore wrapped key additions with zero wrapped keys. (#25791)
When a Nomad server restores its state via a snapshot and logs, it is possible a legacy wrapped key object/log is found. This key will not contain any wrapped keys and therefore should be ingored within the encrypter. It is theoretically possible without this change that a key which generates zero decrypt tasks supersedes a running task and will place itself in the tracked decrypt task tracker. This decrypt task has no running work to remove its entry.
1 parent dfc1412 commit 01cd762

File tree

2 files changed

+49
-1
lines changed

2 files changed

+49
-1
lines changed

nomad/encrypter.go

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,18 @@ func (e *Encrypter) AddUnwrappedKey(rootKey *structs.UnwrappedRootKey, isUpgrade
368368
// but it returns an error for ease of testing.
369369
func (e *Encrypter) AddWrappedKey(ctx context.Context, wrappedKeys *structs.RootKey) error {
370370

371+
// If the passed root key does not contain any wrapped keys, it has no
372+
// decryption tasks to perform and therefore should not supersede or impact
373+
// tasks running for the same keyID.
374+
//
375+
// This conditional will only be hit when the FSM is taking action on
376+
// fsm.RootKeyMetaSnapshot and structs.RootKeyMetaUpsertRequestType types
377+
// which represent legacy style keys. When support is removed for these in
378+
// 1.12.0, we should reconsider this conditional too.
379+
if len(wrappedKeys.WrappedKeys) == 0 {
380+
return nil
381+
}
382+
371383
logger := e.log.With("key_id", wrappedKeys.KeyID)
372384

373385
e.lock.Lock()
@@ -387,7 +399,7 @@ func (e *Encrypter) AddWrappedKey(ctx context.Context, wrappedKeys *structs.Root
387399

388400
if cancel, ok := e.decryptTasks[wrappedKeys.KeyID]; ok {
389401
// stop any previous tasks for this same key ID under the assumption
390-
// they're broken or being superceded, but don't remove the CancelFunc
402+
// they're broken or being superseded, but don't remove the CancelFunc
391403
// from the map yet so that other callers don't think we can continue
392404
cancel()
393405
}

nomad/encrypter_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -874,3 +874,39 @@ func TestEncrypter_decryptWrappedKeyTask(t *testing.T) {
874874
err = encrypter.decryptWrappedKeyTask(ctx, cancel, KMSWrapper, provider, key.Meta, wrappedKey)
875875
must.NoError(t, err)
876876
}
877+
878+
func TestEncrypter_AddWrappedKey_noWrappedKeys(t *testing.T) {
879+
ci.Parallel(t)
880+
881+
srv := &Server{
882+
logger: testlog.HCLogger(t),
883+
config: &Config{},
884+
}
885+
886+
encrypter, err := NewEncrypter(srv, t.TempDir())
887+
must.NoError(t, err)
888+
889+
// Fake life as a 1.6 server by writing only ed25519 keys and removing the
890+
// RSAKey. Add this to the encrypter as if we are loading it as part of the
891+
// FSM restore process which actions the trailing logs.
892+
oldKey, err := structs.NewUnwrappedRootKey(structs.EncryptionAlgorithmAES256GCM)
893+
must.NoError(t, err)
894+
895+
oldKey.RSAKey = nil
896+
wrappedOldKey := structs.NewRootKey(oldKey.Meta)
897+
898+
shutdownCtx, shutdownCancel := context.WithCancel(context.Background())
899+
t.Cleanup(shutdownCancel)
900+
901+
// Add the wrapped key and then wait for the encrypter to become ready. If
902+
// it reaches the timeout, it means the encrypter has added a decryption
903+
// task to its internal tracking without launching any decryptWrappedKeyTask
904+
// routines that can remove this task entry.
905+
must.NoError(t, encrypter.AddWrappedKey(shutdownCtx, wrappedOldKey))
906+
907+
timeoutCtx, timeoutCancel := context.WithTimeout(shutdownCtx, 3*time.Second)
908+
t.Cleanup(timeoutCancel)
909+
910+
must.NoError(t, encrypter.IsReady(timeoutCtx))
911+
must.MapLen(t, 0, encrypter.decryptTasks)
912+
}

0 commit comments

Comments
 (0)