From 8512b219c5fe1625187e59a425ac795698028117 Mon Sep 17 00:00:00 2001 From: Matheus Macabu Date: Fri, 17 Oct 2025 17:35:01 +0200 Subject: [PATCH] Secrets: Try to get the service identity from the context if not found in errors (#112598) --- pkg/storage/secret/metadata/decrypt_store.go | 11 +++++++++++ .../secret/metadata/decrypt_store_test.go | 18 ++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/pkg/storage/secret/metadata/decrypt_store.go b/pkg/storage/secret/metadata/decrypt_store.go index d148e365925..39aa4db9506 100644 --- a/pkg/storage/secret/metadata/decrypt_store.go +++ b/pkg/storage/secret/metadata/decrypt_store.go @@ -5,6 +5,7 @@ import ( "context" "errors" "fmt" + "strings" "time" "github.com/prometheus/client_golang/prometheus" @@ -13,6 +14,7 @@ import ( "go.opentelemetry.io/otel/trace" "google.golang.org/grpc/metadata" + "github.com/grafana/authlib/authn" claims "github.com/grafana/authlib/types" "github.com/grafana/grafana-app-sdk/logging" @@ -66,6 +68,15 @@ func (s *decryptStorage) Decrypt(ctx context.Context, namespace xkube.Namespace, start := time.Now() // TEMPORARY: While we evaluate all of our auditing needs, provide one for decrypt operations. defer func() { + // If at this point the identity is still empty, try to get it from the auth info in context. + if decrypterIdentity == "" { + if authInfo, ok := claims.AuthInfoFrom(ctx); authInfo != nil && ok { + if serviceIdentityList, ok := authInfo.GetExtra()[authn.ServiceIdentityKey]; ok && len(serviceIdentityList) > 0 { + decrypterIdentity = strings.TrimSpace(serviceIdentityList[0]) + } + } + } + span.SetAttributes(attribute.String("decrypter.identity", decrypterIdentity)) args := []any{ diff --git a/pkg/storage/secret/metadata/decrypt_store_test.go b/pkg/storage/secret/metadata/decrypt_store_test.go index 5b29fd1fd62..c07b65dbf04 100644 --- a/pkg/storage/secret/metadata/decrypt_store_test.go +++ b/pkg/storage/secret/metadata/decrypt_store_test.go @@ -43,13 +43,27 @@ func TestIntegrationDecrypt(t *testing.T) { t.Cleanup(cancel) // Create auth context with proper permissions - authCtx := createAuthContext(ctx, "default", []string{"secret.grafana.app/securevalues/group1:decrypt"}, "svc", types.TypeUser) + svcIdentity := "svc" + authCtx := createAuthContext(ctx, "default", []string{"secret.grafana.app/securevalues/group1:decrypt"}, svcIdentity, types.TypeUser) + + fakeLogger := &mockLogger{} + loggerCtx := logging.Context(authCtx, fakeLogger) sut := testutils.Setup(t) - exposed, err := sut.DecryptStorage.Decrypt(authCtx, "default", "non-existent-value") + exposed, err := sut.DecryptStorage.Decrypt(loggerCtx, "default", "non-existent-value") require.Equal(t, err.Error(), contracts.ErrDecryptNotFound.Error()) // make sure we are stripping the error details require.Empty(t, exposed) + + require.Len(t, fakeLogger.InfoArgs, 2) + // we only want to check the audit log args + args := fakeLogger.InfoArgs[1] + require.Contains(t, args, "decrypter_identity") + for i, arg := range args { + if arg == "decrypter_identity" { + require.Equal(t, svcIdentity, args[i+1].(string)) + } + } }) t.Run("when happy path with valid auth and permissions, it returns decrypted value", func(t *testing.T) {