Secrets: Propagate ctx cancel and label it on decryptions (#116058)

This commit is contained in:
Matheus Macabu
2026-01-09 14:25:29 +01:00
committed by GitHub
parent 98453fbcff
commit 52cd096d92
4 changed files with 54 additions and 3 deletions
-3
View File
@@ -11,9 +11,6 @@ import (
_ "github.com/Azure/azure-sdk-for-go/services/keyvault/v7.1/keyvault"
_ "github.com/Azure/go-autorest/autorest"
_ "github.com/Azure/go-autorest/autorest/adal"
_ "github.com/aws/aws-sdk-go-v2/credentials"
_ "github.com/aws/aws-sdk-go-v2/service/secretsmanager"
_ "github.com/aws/aws-sdk-go-v2/service/sts"
_ "github.com/beevik/etree"
_ "github.com/blugelabs/bluge"
_ "github.com/blugelabs/bluge_segment_api"
@@ -127,6 +127,10 @@ func (s *decryptStorage) Decrypt(ctx context.Context, namespace xkube.Namespace,
// function call happens after this.
sv, err := s.secureValueMetadataStorage.Read(ctx, namespace, name, contracts.ReadOpts{})
if err != nil {
if errors.Is(err, context.Canceled) {
return "", fmt.Errorf("operation canceled while reading secure value metadata storage: %v (%w)", err, context.Canceled)
}
return "", fmt.Errorf("failed to read secure value metadata storage: %v (%w)", err, contracts.ErrDecryptNotFound)
}
@@ -137,6 +141,10 @@ func (s *decryptStorage) Decrypt(ctx context.Context, namespace xkube.Namespace,
keeperConfig, err := s.keeperMetadataStorage.GetKeeperConfig(ctx, namespace.String(), sv.Status.Keeper, contracts.ReadOpts{})
if err != nil {
if errors.Is(err, context.Canceled) {
return "", fmt.Errorf("operation canceled while reading keeper config metadata storage: %v (%w)", err, context.Canceled)
}
return "", fmt.Errorf("failed to read keeper config metadata storage: %v (%w)", err, contracts.ErrDecryptFailed)
}
@@ -148,13 +156,22 @@ func (s *decryptStorage) Decrypt(ctx context.Context, namespace xkube.Namespace,
if sv.Spec.Ref != nil {
exposedValue, err := keeper.RetrieveReference(ctx, keeperConfig, *sv.Spec.Ref)
if err != nil {
if errors.Is(err, context.Canceled) {
return "", fmt.Errorf("operation canceled while exposing secret using reference: %v (%w)", err, context.Canceled)
}
return "", fmt.Errorf("failed to expose secret using reference: %v (%w)", err, contracts.ErrDecryptFailed)
}
return exposedValue, nil
}
exposedValue, err := keeper.Expose(ctx, keeperConfig, namespace, name, sv.Status.Version)
if err != nil {
if errors.Is(err, context.Canceled) {
return "", fmt.Errorf("operation canceled while exposing secret: %v (%w)", err, context.Canceled)
}
return "", fmt.Errorf("failed to expose secret: %v (%w)", err, contracts.ErrDecryptFailed)
}
@@ -68,6 +68,40 @@ func TestIntegrationDecrypt(t *testing.T) {
}
})
t.Run("when the context is cancelled, it returns an error", func(t *testing.T) {
t.Parallel()
ctx, cancel := context.WithCancel(context.Background())
svcIdentity := "svc"
// Create auth context with proper permissions that match the decrypters
authCtx := createAuthContext(ctx, "default", []string{"secret.grafana.app/securevalues:decrypt"}, svcIdentity, types.TypeUser)
// Setup service
sut := testutils.Setup(t)
// Create a secure value
spec := secretv1beta1.SecureValueSpec{
Description: "description",
Decrypters: []string{svcIdentity},
Value: ptr.To(secretv1beta1.NewExposedSecureValue("value")),
}
sv := &secretv1beta1.SecureValue{Spec: spec}
sv.Name = "sv-test"
sv.Namespace = "default"
_, err := sut.CreateSv(authCtx, testutils.CreateSvWithSv(sv))
require.NoError(t, err)
// Cancel immediately!
cancel()
exposed, err := sut.DecryptStorage.Decrypt(authCtx, "default", "sv-test")
require.ErrorIs(t, err, context.Canceled)
require.Empty(t, exposed)
})
t.Run("when happy path with valid auth and permissions, it returns decrypted value", func(t *testing.T) {
t.Parallel()
@@ -1,6 +1,7 @@
package metrics
import (
"context"
"errors"
"sync"
@@ -185,6 +186,8 @@ func DecryptResultLabel(err error) string {
return "error_not_found"
} else if errors.Is(err, contracts.ErrDecryptNotAuthorized) {
return "error_unauthorized"
} else if errors.Is(err, context.Canceled) {
return "error_context_canceled"
}
return "error_generic_failure"