diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go index 8f1445ac049..4aad4f3423c 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config.go @@ -380,18 +380,21 @@ func (h *kmsv2PluginProbe) rotateDEKOnKeyIDChange(ctx context.Context, statusKey // it should be logically impossible for the new state to be invalid but check just in case _, errGen = h.getCurrentState() if errGen == nil { - klog.V(6).InfoS("successfully rotated DEK", - "uid", uid, - "newKeyID", resp.KeyID, - "oldKeyID", state.KeyID, - "expirationTimestamp", expirationTimestamp.Format(time.RFC3339), - ) + klogV6 := klog.V(6) + if klogV6.Enabled() { + klogV6.InfoS("successfully rotated DEK", + "uid", uid, + "newKeyIDHash", envelopekmsv2.GetHashIfNotEmpty(resp.KeyID), + "oldKeyIDHash", envelopekmsv2.GetHashIfNotEmpty(state.KeyID), + "expirationTimestamp", expirationTimestamp.Format(time.RFC3339), + ) + } return nil } } - return fmt.Errorf("failed to rotate DEK uid=%q, errState=%v, errGen=%v, statusKeyID=%q, encryptKeyID=%q, stateKeyID=%q, expirationTimestamp=%s", - uid, errState, errGen, statusKeyID, resp.KeyID, state.KeyID, state.ExpirationTimestamp.Format(time.RFC3339)) + return fmt.Errorf("failed to rotate DEK uid=%q, errState=%v, errGen=%v, statusKeyIDHash=%q, encryptKeyIDHash=%q, stateKeyIDHash=%q, expirationTimestamp=%s", + uid, errState, errGen, envelopekmsv2.GetHashIfNotEmpty(statusKeyID), envelopekmsv2.GetHashIfNotEmpty(resp.KeyID), envelopekmsv2.GetHashIfNotEmpty(state.KeyID), state.ExpirationTimestamp.Format(time.RFC3339)) } // getCurrentState returns the latest state from the last status and encrypt calls. @@ -434,7 +437,7 @@ func (h *kmsv2PluginProbe) isKMSv2ProviderHealthyAndMaybeRotateDEK(ctx context.C if errCode, err := envelopekmsv2.ValidateKeyID(response.KeyID); err != nil { metrics.RecordInvalidKeyIDFromStatus(h.name, string(errCode)) - errs = append(errs, fmt.Errorf("got invalid KMSv2 KeyID %q: %w", response.KeyID, err)) + errs = append(errs, fmt.Errorf("got invalid KMSv2 KeyID hash %q: %w", envelopekmsv2.GetHashIfNotEmpty(response.KeyID), err)) } else { metrics.RecordKeyIDFromStatus(h.name, response.KeyID) // unconditionally append as we filter out nil errors below diff --git a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config_test.go b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config_test.go index 915efec1dc8..936848d12e4 100644 --- a/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config_test.go +++ b/staging/src/k8s.io/apiserver/pkg/server/options/encryptionconfig/config_test.go @@ -1729,7 +1729,7 @@ func Test_kmsv2PluginProbe_rotateDEKOnKeyIDChange(t *testing.T) { wantEncryptCalls: 1, wantLogs: []string{ `"encrypting content using envelope service" uid="panda"`, - fmt.Sprintf(`"successfully rotated DEK" uid="panda" newKeyID="1" oldKeyID="" expirationTimestamp="%s"`, + fmt.Sprintf(`"successfully rotated DEK" uid="panda" newKeyIDHash="sha256:6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b" oldKeyIDHash="" expirationTimestamp="%s"`, now.Add(3*time.Minute).Format(time.RFC3339)), }, wantErr: "", @@ -1772,7 +1772,7 @@ func Test_kmsv2PluginProbe_rotateDEKOnKeyIDChange(t *testing.T) { wantEncryptCalls: 1, wantLogs: []string{ `"encrypting content using envelope service" uid="panda"`, - fmt.Sprintf(`"successfully rotated DEK" uid="panda" newKeyID="4" oldKeyID="3" expirationTimestamp="%s"`, + fmt.Sprintf(`"successfully rotated DEK" uid="panda" newKeyIDHash="sha256:4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a" oldKeyIDHash="sha256:4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce" expirationTimestamp="%s"`, now.Add(3*time.Minute).Format(time.RFC3339)), }, wantErr: "", @@ -1791,8 +1791,8 @@ func Test_kmsv2PluginProbe_rotateDEKOnKeyIDChange(t *testing.T) { `"encrypting content using envelope service" uid="panda"`, }, wantErr: `failed to rotate DEK uid="panda", ` + - `errState=, errGen=failed to encrypt DEK, error: broken, statusKeyID="5", ` + - `encryptKeyID="", stateKeyID="4", expirationTimestamp=` + now.Add(7*time.Minute).Format(time.RFC3339), + `errState=, errGen=failed to encrypt DEK, error: broken, statusKeyIDHash="sha256:ef2d127de37b942baad06145e54b0c619a1f22327b2ebbcfbec78f5564afe39d", ` + + `encryptKeyIDHash="", stateKeyIDHash="sha256:4b227777d4dd1fc61c6f884f48641d02b4d121d3fd328cb08b5531fcacdabf8a", expirationTimestamp=` + now.Add(7*time.Minute).Format(time.RFC3339), }, { name: "invalid service response, no previous state", @@ -1806,8 +1806,8 @@ func Test_kmsv2PluginProbe_rotateDEKOnKeyIDChange(t *testing.T) { }, wantErr: `failed to rotate DEK uid="panda", ` + `errState=got unexpected nil transformer, errGen=failed to validate annotations: annotations: Invalid value: "panda": ` + - `should be a domain with at least two segments separated by dots, statusKeyID="1", ` + - `encryptKeyID="", stateKeyID="", expirationTimestamp=` + (time.Time{}).Format(time.RFC3339), + `should be a domain with at least two segments separated by dots, statusKeyIDHash="sha256:6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b", ` + + `encryptKeyIDHash="", stateKeyIDHash="", expirationTimestamp=` + (time.Time{}).Format(time.RFC3339), }, { name: "invalid service response, with previous state", @@ -1824,8 +1824,8 @@ func Test_kmsv2PluginProbe_rotateDEKOnKeyIDChange(t *testing.T) { }, wantErr: `failed to rotate DEK uid="panda", ` + `errState=, errGen=failed to validate annotations: annotations: Invalid value: "panda": ` + - `should be a domain with at least two segments separated by dots, statusKeyID="3", ` + - `encryptKeyID="", stateKeyID="2", expirationTimestamp=` + now.Format(time.RFC3339), + `should be a domain with at least two segments separated by dots, statusKeyIDHash="sha256:4e07408562bedb8b60ce05c1decfe3ad16b72230967de01f640b7e4729b49fce", ` + + `encryptKeyIDHash="", stateKeyIDHash="sha256:d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35", expirationTimestamp=` + now.Format(time.RFC3339), }, } for _, tt := range tests { diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/kmsv2/envelope.go b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/kmsv2/envelope.go index f7dd4e984ca..bd78e7e0b9c 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/kmsv2/envelope.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/kmsv2/envelope.go @@ -20,6 +20,7 @@ package kmsv2 import ( "context" "crypto/aes" + "crypto/sha256" "fmt" "sort" "time" @@ -97,8 +98,8 @@ type State struct { func (s *State) ValidateEncryptCapability() error { if now := NowFunc(); now.After(s.ExpirationTimestamp) { - return fmt.Errorf("EDEK with keyID %q expired at %s (current time is %s)", - s.KeyID, s.ExpirationTimestamp.Format(time.RFC3339), now.Format(time.RFC3339)) + return fmt.Errorf("EDEK with keyID hash %q expired at %s (current time is %s)", + GetHashIfNotEmpty(s.KeyID), s.ExpirationTimestamp.Format(time.RFC3339), now.Format(time.RFC3339)) } return nil } @@ -422,3 +423,11 @@ func toBytes(s string) []byte { // https://github.com/golang/go/blob/202a1a57064127c3f19d96df57b9f9586145e21c/src/os/file.go#L246 return unsafe.Slice(unsafe.StringData(s), len(s)) } + +// GetHashIfNotEmpty returns the sha256 hash of the data if it is not empty. +func GetHashIfNotEmpty(data string) string { + if len(data) > 0 { + return fmt.Sprintf("sha256:%x", sha256.Sum256([]byte(data))) + } + return "" +} diff --git a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/kmsv2/envelope_test.go b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/kmsv2/envelope_test.go index 5b7cf3a2058..e9ab0fd3d3b 100644 --- a/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/kmsv2/envelope_test.go +++ b/staging/src/k8s.io/apiserver/pkg/storage/value/encrypt/envelope/kmsv2/envelope_test.go @@ -401,7 +401,7 @@ func TestEnvelopeTransformerStateFunc(t *testing.T) { t.Run("writes fail when the plugin is down and the state is invalid", func(t *testing.T) { _, err := transformer.TransformToStorage(ctx, originalText, dataCtx) - if !strings.Contains(errString(err), `EDEK with keyID "1" expired at`) { + if !strings.Contains(errString(err), `EDEK with keyID hash "sha256:6b86b273ff34fce19d6b804eff5a3f5747ada4eaa22f1d49c01e52ddb7875b4b" expired at`) { t.Fatalf("expected expiration error, got: %v", err) } }) diff --git a/test/integration/controlplane/transformation/kmsv2_transformation_test.go b/test/integration/controlplane/transformation/kmsv2_transformation_test.go index 6f1348db940..b0e8235638f 100644 --- a/test/integration/controlplane/transformation/kmsv2_transformation_test.go +++ b/test/integration/controlplane/transformation/kmsv2_transformation_test.go @@ -378,7 +378,7 @@ resources: // 6. when kms-plugin is down, expect creation of new pod and encryption to fail because the DEK is invalid _, err = test.createPod(testNamespace, dynamicClient) - if err == nil || !strings.Contains(err.Error(), `EDEK with keyID "2" expired at 2`) { + if err == nil || !strings.Contains(err.Error(), `EDEK with keyID hash "sha256:d4735e3a265e16eee03f59718b9b5d03019c07d8b6c51f90da3a666eec13ab35" expired at 2`) { t.Fatalf("Create test pod should have failed due to encryption, ns: %s, got: %v", testNamespace, err) }