From f0885393316bfcc9de4ca8b21a11252e3a36ca3b Mon Sep 17 00:00:00 2001 From: James Rasell Date: Tue, 12 Nov 2024 11:47:33 +0000 Subject: [PATCH 1/2] keyring: Fix a panic when decrypting aead with empty RSA block. Clusters that have gone through several upgrades have be found to include keyring material which has an empty RSA block. In more recent versions of Nomad, an empty RSA block is omitted from being written to disk. This results in the panic not being present. Older versions, however, did not have this struct tag meaning we wrote an empty JSON block which is not accounted for in the current version. --- nomad/encrypter.go | 2 +- nomad/encrypter_test.go | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/nomad/encrypter.go b/nomad/encrypter.go index 64bd4c047a1..0409f5c30f6 100644 --- a/nomad/encrypter.go +++ b/nomad/encrypter.go @@ -477,7 +477,7 @@ func (e *Encrypter) decryptWrappedKeyTask(ctx context.Context, cancel context.Ca // Decrypt RSAKey for Workload Identity JWT signing if one exists. Prior to // 1.7 an ed25519 key derived from the root key was used instead of an RSA // key. - if wrappedKey.WrappedRSAKey != nil { + if wrappedKey.WrappedRSAKey != nil && len(wrappedKey.WrappedRSAKey.Ciphertext) > 0 { rsaKey, err = wrapper.Decrypt(e.srv.shutdownCtx, wrappedKey.WrappedRSAKey) if err != nil { err := fmt.Errorf("%w (rsa key): %w", ErrDecryptFailed, err) diff --git a/nomad/encrypter_test.go b/nomad/encrypter_test.go index e539ac1a5b5..6d866e84294 100644 --- a/nomad/encrypter_test.go +++ b/nomad/encrypter_test.go @@ -17,6 +17,7 @@ import ( "time" "github.com/go-jose/go-jose/v3/jwt" + wrapping "github.com/hashicorp/go-kms-wrapping/v2" msgpackrpc "github.com/hashicorp/net-rpc-msgpackrpc/v2" "github.com/hashicorp/nomad/ci" "github.com/hashicorp/nomad/helper/pointer" @@ -834,3 +835,42 @@ func TestEncrypter_TransitConfigFallback(t *testing.T) { fallbackVaultConfig(providers[2], &config.VaultConfig{}) must.Eq(t, expect, providers[2].Config, must.Sprint("expected fallback to env")) } + +func TestEncrypter_decryptWrappedKeyTask(t *testing.T) { + ci.Parallel(t) + + srv := &Server{ + logger: testlog.HCLogger(t), + config: &Config{}, + } + + tmpDir := t.TempDir() + + key, err := structs.NewUnwrappedRootKey(structs.EncryptionAlgorithmAES256GCM) + must.NoError(t, err) + + encrypter, err := NewEncrypter(srv, tmpDir) + must.NoError(t, err) + + wrappedKey, err := encrypter.encryptDEK(key, &structs.KEKProviderConfig{}) + must.NotNil(t, wrappedKey) + must.NoError(t, err) + + // Purposely empty the RSA key, but do not nil it, so we can test for a + // panic where the key doesn't contain the ciphertext. + wrappedKey.WrappedRSAKey = &wrapping.BlobInfo{} + + provider, ok := encrypter.providerConfigs[string(structs.KEKProviderAEAD)] + must.True(t, ok) + must.NotNil(t, provider) + + KMSWrapper, err := encrypter.newKMSWrapper(provider, key.Meta.KeyID, wrappedKey.KeyEncryptionKey) + must.NoError(t, err) + must.NotNil(t, KMSWrapper) + + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + err = encrypter.decryptWrappedKeyTask(ctx, cancel, KMSWrapper, provider, key.Meta, wrappedKey) + must.NoError(t, err) +} From e4decda39448299f1eb9e3e3c42982e85bd0e225 Mon Sep 17 00:00:00 2001 From: James Rasell Date: Tue, 12 Nov 2024 11:54:56 +0000 Subject: [PATCH 2/2] changelog: add entry for #24442 --- .changelog/24442.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/24442.txt diff --git a/.changelog/24442.txt b/.changelog/24442.txt new file mode 100644 index 00000000000..324bab1a400 --- /dev/null +++ b/.changelog/24442.txt @@ -0,0 +1,3 @@ +```release-note:bug +keyring: Fixed a bug when decrypting aead with an empty RSA block on state upserts +```