Browse Source

feat(aws): add defining a resource policy via metadata for secretsmanager (#5399)

* feat(aws): add defining a resource policy via metadata for secretsmanager

Signed-off-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>

* added stable comparison of the policies

Signed-off-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>

---------

Signed-off-by: Gergely Brautigam <182850+Skarlso@users.noreply.github.com>
Gergely Brautigam 5 months ago
parent
commit
c96b44929f

+ 82 - 2
docs/provider/aws-secrets-manager.md

@@ -62,7 +62,10 @@ If you're planning to use `PushSecret`, ensure you also have the following permi
     "secretsmanager:CreateSecret",
     "secretsmanager:PutSecretValue",
     "secretsmanager:TagResource",
-    "secretsmanager:DeleteSecret"
+    "secretsmanager:DeleteSecret",
+    "secretsmanager:GetResourcePolicy",
+    "secretsmanager:PutResourcePolicy",
+    "secretsmanager:DeleteResourcePolicy"
   ],
   "Resource": [
     "arn:aws:secretsmanager:us-west-2:111122223333:secret:dev-*"
@@ -70,6 +73,8 @@ If you're planning to use `PushSecret`, ensure you also have the following permi
 }
 ```
 
+**Note:** The resource policy permissions (`GetResourcePolicy`, `PutResourcePolicy`, `DeleteResourcePolicy`) are only required if you're using the `resourcePolicy` metadata option to manage resource-based policies on secrets.
+
 Here's a more restrictive version of the IAM policy:
 
 ``` json
@@ -81,7 +86,10 @@ Here's a more restrictive version of the IAM policy:
       "Action": [
         "secretsmanager:CreateSecret",
         "secretsmanager:PutSecretValue",
-        "secretsmanager:TagResource"
+        "secretsmanager:TagResource",
+        "secretsmanager:GetResourcePolicy",
+        "secretsmanager:PutResourcePolicy",
+        "secretsmanager:DeleteResourcePolicy"
       ],
       "Resource": [
         "arn:aws:secretsmanager:us-west-2:111122223333:secret:dev-*"
@@ -122,6 +130,7 @@ Optionally, it is possible to configure additional options for the parameter. Th
 - secretPushFormat
 - description
 - tags
+- resourcePolicy
 
 To control this behavior set the following provider metadata:
 
@@ -133,6 +142,77 @@ To control this behavior set the following provider metadata:
 - `kmsKeyID` takes a KMS Key `$ID` or `$ARN` (in case a key source is created in another account) as a string, where `alias/aws/secretsmanager` is the _default_.
 - `description` Description of the secret.
 - `tags` Key-value map of user-defined tags that are attached to the secret.
+- `resourcePolicy` Attach a resource-based policy to the secret for cross-account access or advanced access control.
+  - `blockPublicPolicy` (optional) - Set to `true` to validate that the policy doesn't grant public access before applying. Defaults to AWS behavior.
+  - `policySourceRef` (required) - Reference to a ConfigMap or Secret containing the policy JSON.
+    - `kind` - Either `ConfigMap` or `Secret`.
+    - `name` - Name of the ConfigMap or Secret.
+    - `key` - Key within the ConfigMap/Secret data that contains the policy JSON.
+
+##### Resource Policy Example
+
+To attach a resource policy to a secret for cross-account access:
+
+```yaml
+apiVersion: external-secrets.io/v1alpha1
+kind: PushSecret
+metadata:
+  name: pushsecret-example
+  namespace: default
+spec:
+  refreshInterval: 10s
+  secretStoreRefs:
+    - name: aws-secretsmanager
+      kind: SecretStore
+  selector:
+    secret:
+      name: pokedex-credentials
+  data:
+    - match:
+        secretKey: my-secret-key
+        remoteRef:
+          remoteKey: my-remote-secret
+          property: password
+  metadata:
+    resourcePolicy:
+      blockPublicPolicy: true
+      policySourceRef:
+        kind: ConfigMap
+        name: my-secret-resource-policy
+        key: policy.json
+    kmsKeyID: bb123123-b2b0-4f60-ac3a-44a13f0e6b6c
+    secretPushFormat: string
+    description: "Cross-account accessible secret"
+    tags:
+      team: platform-engineering
+```
+
+The ConfigMap should contain the policy JSON:
+
+```yaml
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: my-secret-resource-policy
+  namespace: default
+data:
+  policy.json: |
+    {
+      "Version": "2012-10-17",
+      "Statement": [
+        {
+          "Effect": "Allow",
+          "Principal": {
+            "AWS": "arn:aws:iam::123456789012:root"
+          },
+          "Action": "secretsmanager:GetSecretValue",
+          "Resource": "*"
+        }
+      ]
+    }
+```
+
+**Note:** The resource policy is applied after the secret is created or updated. If the `resourcePolicy` field is removed from metadata, the existing policy will be deleted from the secret.
 
 ### JSON Secret Values
 

+ 3 - 0
pkg/constants/constants.go

@@ -30,6 +30,9 @@ const (
 	CallAWSSMBatchGetSecretValue = "BatchGetSecretValue"
 	CallAWSSMUntagResource       = "UntagResource"
 	CallAWSSMTagResource         = "TagResource"
+	CallAWSSMPutResourcePolicy   = "PutResourcePolicy"
+	CallAWSSMGetResourcePolicy   = "GetResourcePolicy"
+	CallAWSSMDeleteResourcePolicy = "DeleteResourcePolicy"
 
 	ProviderAWSPS                = "AWS/ParameterStore"
 	CallAWSPSGetParameter        = "GetParameter"

+ 2 - 2
pkg/provider/aws/provider.go

@@ -158,7 +158,7 @@ func newClient(ctx context.Context, store esv1.GenericStore, kube client.Client,
 		}
 		switch prov.Service {
 		case esv1.AWSServiceSecretsManager:
-			return secretsmanager.New(ctx, &cfg, prov.SecretsManager, storeSpec.Provider.AWS.Prefix, true)
+			return secretsmanager.New(ctx, &cfg, prov.SecretsManager, storeSpec.Provider.AWS.Prefix, true, kube, namespace)
 		case esv1.AWSServiceParameterStore:
 			return parameterstore.New(ctx, &cfg, storeSpec.Provider.AWS.Prefix, true)
 		}
@@ -213,7 +213,7 @@ func newClient(ctx context.Context, store esv1.GenericStore, kube client.Client,
 
 	switch prov.Service {
 	case esv1.AWSServiceSecretsManager:
-		return secretsmanager.New(ctx, cfg, prov.SecretsManager, storeSpec.Provider.AWS.Prefix, false)
+		return secretsmanager.New(ctx, cfg, prov.SecretsManager, storeSpec.Provider.AWS.Prefix, false, kube, namespace)
 	case esv1.AWSServiceParameterStore:
 		return parameterstore.New(ctx, cfg, storeSpec.Provider.AWS.Prefix, false)
 	}

+ 45 - 0
pkg/provider/aws/secretsmanager/fake/fake.go

@@ -44,6 +44,9 @@ type Client struct {
 	BatchGetSecretValueFn BatchGetSecretValueFn
 	TagResourceFn         TagResourceFn
 	UntagResourceFn       UntagResourceFn
+	PutResourcePolicyFn   PutResourcePolicyFn
+	GetResourcePolicyFn   GetResourcePolicyFn
+	DeleteResourcePolicyFn DeleteResourcePolicyFn
 }
 type CreateSecretFn func(context.Context, *awssm.CreateSecretInput, ...func(*awssm.Options)) (*awssm.CreateSecretOutput, error)
 type GetSecretValueFn func(context.Context, *awssm.GetSecretValueInput, ...func(*awssm.Options)) (*awssm.GetSecretValueOutput, error)
@@ -55,6 +58,9 @@ type BatchGetSecretValueFn func(context.Context, *awssm.BatchGetSecretValueInput
 
 type TagResourceFn func(context.Context, *awssm.TagResourceInput, ...func(*awssm.Options)) (*awssm.TagResourceOutput, error)
 type UntagResourceFn func(context.Context, *awssm.UntagResourceInput, ...func(*awssm.Options)) (*awssm.UntagResourceOutput, error)
+type PutResourcePolicyFn func(context.Context, *awssm.PutResourcePolicyInput, ...func(*awssm.Options)) (*awssm.PutResourcePolicyOutput, error)
+type GetResourcePolicyFn func(context.Context, *awssm.GetResourcePolicyInput, ...func(*awssm.Options)) (*awssm.GetResourcePolicyOutput, error)
+type DeleteResourcePolicyFn func(context.Context, *awssm.DeleteResourcePolicyInput, ...func(*awssm.Options)) (*awssm.DeleteResourcePolicyOutput, error)
 
 func (sm *Client) CreateSecret(ctx context.Context, input *awssm.CreateSecretInput, options ...func(*awssm.Options)) (*awssm.CreateSecretOutput, error) {
 	return sm.CreateSecretFn(ctx, input, options...)
@@ -226,3 +232,42 @@ func NewUntagResourceFn(output *awssm.UntagResourceOutput, err error, aFunc ...f
 		return output, err
 	}
 }
+
+func (sm *Client) PutResourcePolicy(ctx context.Context, params *awssm.PutResourcePolicyInput, optFns ...func(*awssm.Options)) (*awssm.PutResourcePolicyOutput, error) {
+	return sm.PutResourcePolicyFn(ctx, params, optFns...)
+}
+
+func NewPutResourcePolicyFn(output *awssm.PutResourcePolicyOutput, err error, aFunc ...func(input *awssm.PutResourcePolicyInput)) PutResourcePolicyFn {
+	return func(ctx context.Context, params *awssm.PutResourcePolicyInput, optFns ...func(*awssm.Options)) (*awssm.PutResourcePolicyOutput, error) {
+		for _, f := range aFunc {
+			f(params)
+		}
+		return output, err
+	}
+}
+
+func (sm *Client) GetResourcePolicy(ctx context.Context, params *awssm.GetResourcePolicyInput, optFns ...func(*awssm.Options)) (*awssm.GetResourcePolicyOutput, error) {
+	return sm.GetResourcePolicyFn(ctx, params, optFns...)
+}
+
+func NewGetResourcePolicyFn(output *awssm.GetResourcePolicyOutput, err error, aFunc ...func(input *awssm.GetResourcePolicyInput)) GetResourcePolicyFn {
+	return func(ctx context.Context, params *awssm.GetResourcePolicyInput, optFns ...func(*awssm.Options)) (*awssm.GetResourcePolicyOutput, error) {
+		for _, f := range aFunc {
+			f(params)
+		}
+		return output, err
+	}
+}
+
+func (sm *Client) DeleteResourcePolicy(ctx context.Context, params *awssm.DeleteResourcePolicyInput, optFns ...func(*awssm.Options)) (*awssm.DeleteResourcePolicyOutput, error) {
+	return sm.DeleteResourcePolicyFn(ctx, params, optFns...)
+}
+
+func NewDeleteResourcePolicyFn(output *awssm.DeleteResourcePolicyOutput, err error, aFunc ...func(input *awssm.DeleteResourcePolicyInput)) DeleteResourcePolicyFn {
+	return func(ctx context.Context, params *awssm.DeleteResourcePolicyInput, optFns ...func(*awssm.Options)) (*awssm.DeleteResourcePolicyOutput, error) {
+		for _, f := range aFunc {
+			f(params)
+		}
+		return output, err
+	}
+}

+ 178 - 8
pkg/provider/aws/secretsmanager/secretsmanager.go

@@ -22,6 +22,7 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
+	"maps"
 	"slices"
 	"strings"
 
@@ -37,6 +38,7 @@ import (
 	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	utilpointer "k8s.io/utils/ptr"
 	ctrl "sigs.k8s.io/controller-runtime"
+	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	esv1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1"
 	"github.com/external-secrets/external-secrets/pkg/constants"
@@ -48,10 +50,22 @@ import (
 
 // PushSecretMetadataSpec contains metadata information for pushing secrets to AWS Secret Manager.
 type PushSecretMetadataSpec struct {
-	Tags             map[string]string `json:"tags,omitempty"`
-	Description      string            `json:"description,omitempty"`
-	SecretPushFormat string            `json:"secretPushFormat,omitempty"`
-	KMSKeyID         string            `json:"kmsKeyId,omitempty"`
+	Tags             map[string]string   `json:"tags,omitempty"`
+	Description      string              `json:"description,omitempty"`
+	SecretPushFormat string              `json:"secretPushFormat,omitempty"`
+	KMSKeyID         string              `json:"kmsKeyId,omitempty"`
+	ResourcePolicy   *ResourcePolicySpec `json:"resourcePolicy,omitempty"`
+}
+
+type ResourcePolicySpec struct {
+	BlockPublicPolicy *bool            `json:"blockPublicPolicy,omitempty"`
+	PolicySourceRef   *PolicySourceRef `json:"policySourceRef,omitempty"`
+}
+
+type PolicySourceRef struct {
+	Kind string `json:"kind"`
+	Name string `json:"name"`
+	Key  string `json:"key"`
 }
 
 // Declares metadata information for pushing secrets to AWS Secret Store.
@@ -74,6 +88,8 @@ type SecretsManager struct {
 	config       *esv1.SecretsManager
 	prefix       string
 	newUUID      func() string
+	kube         client.Client
+	namespace    string
 }
 
 // SMInterface is a subset of the smiface api.
@@ -88,6 +104,9 @@ type SMInterface interface {
 	DeleteSecret(ctx context.Context, params *awssm.DeleteSecretInput, optFuncs ...func(*awssm.Options)) (*awssm.DeleteSecretOutput, error)
 	TagResource(ctx context.Context, params *awssm.TagResourceInput, optFuncs ...func(*awssm.Options)) (*awssm.TagResourceOutput, error)
 	UntagResource(ctx context.Context, params *awssm.UntagResourceInput, optFuncs ...func(*awssm.Options)) (*awssm.UntagResourceOutput, error)
+	PutResourcePolicy(ctx context.Context, params *awssm.PutResourcePolicyInput, optFuncs ...func(*awssm.Options)) (*awssm.PutResourcePolicyOutput, error)
+	GetResourcePolicy(ctx context.Context, params *awssm.GetResourcePolicyInput, optFuncs ...func(*awssm.Options)) (*awssm.GetResourcePolicyOutput, error)
+	DeleteResourcePolicy(ctx context.Context, params *awssm.DeleteResourcePolicyInput, optFuncs ...func(*awssm.Options)) (*awssm.DeleteResourcePolicyOutput, error)
 }
 
 const (
@@ -100,7 +119,7 @@ const (
 var log = ctrl.Log.WithName("provider").WithName("aws").WithName("secretsmanager")
 
 // New creates a new SecretsManager client.
-func New(_ context.Context, cfg *aws.Config, secretsManagerCfg *esv1.SecretsManager, prefix string, referentAuth bool) (*SecretsManager, error) {
+func New(_ context.Context, cfg *aws.Config, secretsManagerCfg *esv1.SecretsManager, prefix string, referentAuth bool, kube client.Client, namespace string) (*SecretsManager, error) {
 	return &SecretsManager{
 		cfg: cfg,
 		client: awssm.NewFromConfig(*cfg, func(o *awssm.Options) {
@@ -110,6 +129,8 @@ func New(_ context.Context, cfg *aws.Config, secretsManagerCfg *esv1.SecretsMana
 		cache:        make(map[string]*awssm.GetSecretValueOutput),
 		config:       secretsManagerCfg,
 		prefix:       prefix,
+		kube:         kube,
+		namespace:    namespace,
 	}, nil
 }
 
@@ -536,10 +557,35 @@ func (sm *SecretsManager) createSecretWithContext(ctx context.Context, secretNam
 		input.SecretString = aws.String(string(value))
 	}
 
-	_, err = sm.client.CreateSecret(ctx, input)
+	createOutput, err := sm.client.CreateSecret(ctx, input)
 	metrics.ObserveAPICall(constants.ProviderAWSSM, constants.CallAWSSMCreateSecret, err)
+	if err != nil {
+		return err
+	}
 
-	return err
+	// Apply resource policy if specified
+	if mdata.Spec.ResourcePolicy != nil && mdata.Spec.ResourcePolicy.PolicySourceRef != nil {
+		policyJSON, err := sm.resolveResourcePolicy(ctx, mdata.Spec.ResourcePolicy.PolicySourceRef)
+		if err != nil {
+			return fmt.Errorf("failed to resolve resource policy: %w", err)
+		}
+
+		putPolicyInput := &awssm.PutResourcePolicyInput{
+			SecretId:       createOutput.ARN,
+			ResourcePolicy: aws.String(policyJSON),
+		}
+		if mdata.Spec.ResourcePolicy.BlockPublicPolicy != nil {
+			putPolicyInput.BlockPublicPolicy = mdata.Spec.ResourcePolicy.BlockPublicPolicy
+		}
+
+		_, err = sm.client.PutResourcePolicy(ctx, putPolicyInput)
+		metrics.ObserveAPICall(constants.ProviderAWSSM, constants.CallAWSSMPutResourcePolicy, err)
+		if err != nil {
+			return fmt.Errorf("failed to put resource policy: %w", err)
+		}
+	}
+
+	return nil
 }
 
 func (sm *SecretsManager) putSecretValueWithContext(ctx context.Context, secretArn string, awsSecret *awssm.GetSecretValueOutput, psd esv1.PushSecretData, value []byte, tags []types.Tag) error {
@@ -579,7 +625,12 @@ func (sm *SecretsManager) putSecretValueWithContext(ctx context.Context, secretA
 	for _, tag := range tags {
 		currentTags[*tag.Key] = *tag.Value
 	}
-	return sm.patchTags(ctx, psd.GetMetadata(), &secretArn, currentTags)
+	if err := sm.patchTags(ctx, psd.GetMetadata(), &secretArn, currentTags); err != nil {
+		return err
+	}
+
+	// Manage resource policy if specified in metadata
+	return sm.manageResourcePolicy(ctx, psd.GetMetadata(), &secretArn)
 }
 
 func (sm *SecretsManager) patchTags(ctx context.Context, metadata *apiextensionsv1.JSON, secretID *string, tags map[string]string) error {
@@ -750,6 +801,125 @@ func (sm *SecretsManager) constructMetadataWithDefaults(data *apiextensionsv1.JS
 	return meta, nil
 }
 
+// resolveResourcePolicy resolves the policy JSON from the PolicySourceRef.
+func (sm *SecretsManager) resolveResourcePolicy(ctx context.Context, policyRef *PolicySourceRef) (string, error) {
+	if policyRef == nil {
+		return "", errors.New("policySourceRef is nil")
+	}
+
+	switch policyRef.Kind {
+	case "ConfigMap":
+		cm := &corev1.ConfigMap{}
+		if err := sm.kube.Get(ctx, client.ObjectKey{
+			Namespace: sm.namespace,
+			Name:      policyRef.Name,
+		}, cm); err != nil {
+			return "", fmt.Errorf("failed to get ConfigMap %s/%s: %w", sm.namespace, policyRef.Name, err)
+		}
+		policy, ok := cm.Data[policyRef.Key]
+		if !ok {
+			return "", fmt.Errorf("key %s not found in ConfigMap %s/%s", policyRef.Key, sm.namespace, policyRef.Name)
+		}
+		return policy, nil
+
+	case "Secret":
+		secret := &corev1.Secret{}
+		if err := sm.kube.Get(ctx, client.ObjectKey{
+			Namespace: sm.namespace,
+			Name:      policyRef.Name,
+		}, secret); err != nil {
+			return "", fmt.Errorf("failed to get Secret %s/%s: %w", sm.namespace, policyRef.Name, err)
+		}
+		policyBytes, ok := secret.Data[policyRef.Key]
+		if !ok {
+			return "", fmt.Errorf("key %s not found in Secret %s/%s", policyRef.Key, sm.namespace, policyRef.Name)
+		}
+		return string(policyBytes), nil
+
+	default:
+		return "", fmt.Errorf("unsupported PolicySourceRef kind: %s (must be ConfigMap or Secret)", policyRef.Kind)
+	}
+}
+
+// manageResourcePolicy applies or removes the resource policy based on metadata.
+func (sm *SecretsManager) manageResourcePolicy(ctx context.Context, metadata *apiextensionsv1.JSON, secretId *string) error {
+	meta, err := sm.constructMetadataWithDefaults(metadata)
+	if err != nil {
+		return err
+	}
+
+	// Delete policy if policyRef is nil and the policy exists.
+	if meta.Spec.ResourcePolicy == nil {
+		deletePolicyInput := &awssm.DeleteResourcePolicyInput{
+			SecretId: secretId,
+		}
+		_, err = sm.client.DeleteResourcePolicy(ctx, deletePolicyInput)
+		metrics.ObserveAPICall(constants.ProviderAWSSM, constants.CallAWSSMDeleteResourcePolicy, err)
+
+		var nf *types.ResourceNotFoundException
+		if err != nil && !errors.As(err, &nf) {
+			return fmt.Errorf("failed to delete resource policy: %w", err)
+		}
+
+		return nil
+	}
+
+	// Normal flow, is to create the policy.
+	policyJSON, err := sm.resolveResourcePolicy(ctx, meta.Spec.ResourcePolicy.PolicySourceRef)
+	if err != nil {
+		return fmt.Errorf("failed to resolve resource policy: %w", err)
+	}
+
+	getCurrentPolicyInput := &awssm.GetResourcePolicyInput{
+		SecretId: secretId,
+	}
+	currentPolicyOutput, err := sm.client.GetResourcePolicy(ctx, getCurrentPolicyInput)
+	metrics.ObserveAPICall(constants.ProviderAWSSM, constants.CallAWSSMGetResourcePolicy, err)
+
+	var nf *types.ResourceNotFoundException
+	if err != nil && !errors.As(err, &nf) {
+		return fmt.Errorf("failed to get current resource policy: %w", err)
+	}
+
+	currentPolicy := ""
+	if currentPolicyOutput != nil && currentPolicyOutput.ResourcePolicy != nil {
+		currentPolicy = *currentPolicyOutput.ResourcePolicy
+	}
+
+	// convert to maps so we can do a stable comparison.
+	var (
+		currentPolicyMap map[string]any
+		policyJSONMaps   map[string]any
+	)
+
+	if err := json.Unmarshal([]byte(currentPolicy), &currentPolicyMap); err != nil {
+		return fmt.Errorf("failed to unmarshal current resource policy: %w", err)
+	}
+	if err := json.Unmarshal([]byte(policyJSON), &policyJSONMaps); err != nil {
+		return fmt.Errorf("failed to unmarshal current resource policy: %w", err)
+	}
+
+	if maps.Equal(currentPolicyMap, policyJSONMaps) {
+		return nil
+	}
+
+	putPolicyInput := &awssm.PutResourcePolicyInput{
+		SecretId:       secretId,
+		ResourcePolicy: aws.String(policyJSON),
+	}
+	if meta.Spec.ResourcePolicy.BlockPublicPolicy != nil {
+		putPolicyInput.BlockPublicPolicy = meta.Spec.ResourcePolicy.BlockPublicPolicy
+	}
+
+	_, err = sm.client.PutResourcePolicy(ctx, putPolicyInput)
+	metrics.ObserveAPICall(constants.ProviderAWSSM, constants.CallAWSSMPutResourcePolicy, err)
+	if err != nil {
+		return fmt.Errorf("failed to put resource policy: %w", err)
+	}
+
+	return nil
+}
+
 // computeTagsToUpdate compares the current tags with the desired metaTags and returns a slice of ssmTypes.Tag
 // that should be set on the resource. It also returns a boolean indicating if any tag was added or modified.
 func computeTagsToUpdate(tags, metaTags map[string]string) ([]types.Tag, bool) {

+ 20 - 5
pkg/provider/aws/secretsmanager/secretsmanager_test.go

@@ -548,11 +548,12 @@ func TestSetSecret(t *testing.T) {
 			args: args{
 				store: makeValidSecretStore().Spec.Provider.AWS,
 				client: fakesm.Client{
-					GetSecretValueFn: fakesm.NewGetSecretValueFn(secretValueOutput, nil),
-					PutSecretValueFn: fakesm.NewPutSecretValueFn(putSecretOutput, nil),
-					DescribeSecretFn: fakesm.NewDescribeSecretFn(tagSecretOutput, nil),
-					TagResourceFn:    fakesm.NewTagResourceFn(&awssm.TagResourceOutput{}, nil),
-					UntagResourceFn:  fakesm.NewUntagResourceFn(&awssm.UntagResourceOutput{}, nil),
+					GetSecretValueFn:       fakesm.NewGetSecretValueFn(secretValueOutput, nil),
+					PutSecretValueFn:       fakesm.NewPutSecretValueFn(putSecretOutput, nil),
+					DescribeSecretFn:       fakesm.NewDescribeSecretFn(tagSecretOutput, nil),
+					TagResourceFn:          fakesm.NewTagResourceFn(&awssm.TagResourceOutput{}, nil),
+					UntagResourceFn:        fakesm.NewUntagResourceFn(&awssm.UntagResourceOutput{}, nil),
+					DeleteResourcePolicyFn: fakesm.NewDeleteResourcePolicyFn(&awssm.DeleteResourcePolicyOutput{}, nil),
 				},
 				pushSecretData: pushSecretDataWithoutProperty,
 			},
@@ -572,6 +573,7 @@ func TestSetSecret(t *testing.T) {
 					}),
 					TagResourceFn:   fakesm.NewTagResourceFn(&awssm.TagResourceOutput{}, nil),
 					UntagResourceFn: fakesm.NewUntagResourceFn(&awssm.UntagResourceOutput{}, nil),
+					DeleteResourcePolicyFn: fakesm.NewDeleteResourcePolicyFn(&awssm.DeleteResourcePolicyOutput{}, nil),
 				},
 				pushSecretData: pushSecretDataWithoutProperty,
 			},
@@ -591,6 +593,7 @@ func TestSetSecret(t *testing.T) {
 					}),
 					TagResourceFn:   fakesm.NewTagResourceFn(&awssm.TagResourceOutput{}, nil),
 					UntagResourceFn: fakesm.NewUntagResourceFn(&awssm.UntagResourceOutput{}, nil),
+					DeleteResourcePolicyFn: fakesm.NewDeleteResourcePolicyFn(&awssm.DeleteResourcePolicyOutput{}, nil),
 				},
 				pushSecretData: pushSecretDataWithProperty,
 			},
@@ -608,6 +611,7 @@ func TestSetSecret(t *testing.T) {
 					DescribeSecretFn: fakesm.NewDescribeSecretFn(tagSecretOutput, nil),
 					TagResourceFn:    fakesm.NewTagResourceFn(&awssm.TagResourceOutput{}, nil),
 					UntagResourceFn:  fakesm.NewUntagResourceFn(&awssm.UntagResourceOutput{}, nil),
+					DeleteResourcePolicyFn: fakesm.NewDeleteResourcePolicyFn(&awssm.DeleteResourcePolicyOutput{}, nil),
 				},
 				pushSecretData: pushSecretDataWithoutSecretKey,
 			},
@@ -625,6 +629,7 @@ func TestSetSecret(t *testing.T) {
 					DescribeSecretFn: fakesm.NewDescribeSecretFn(tagSecretOutput, nil),
 					TagResourceFn:    fakesm.NewTagResourceFn(&awssm.TagResourceOutput{}, nil),
 					UntagResourceFn:  fakesm.NewUntagResourceFn(&awssm.UntagResourceOutput{}, nil),
+					DeleteResourcePolicyFn: fakesm.NewDeleteResourcePolicyFn(&awssm.DeleteResourcePolicyOutput{}, nil),
 				},
 				pushSecretData: pushSecretDataWithMetadata,
 			},
@@ -665,6 +670,7 @@ func TestSetSecret(t *testing.T) {
 					DescribeSecretFn: fakesm.NewDescribeSecretFn(tagSecretOutput, nil),
 					TagResourceFn:    fakesm.NewTagResourceFn(&awssm.TagResourceOutput{}, nil),
 					UntagResourceFn:  fakesm.NewUntagResourceFn(&awssm.UntagResourceOutput{}, nil),
+					DeleteResourcePolicyFn: fakesm.NewDeleteResourcePolicyFn(&awssm.DeleteResourcePolicyOutput{}, nil),
 				},
 				pushSecretData: fake.PushSecretData{SecretKey: secretKey, RemoteKey: fakeKey, Property: "", Metadata: &apiextensionsv1.JSON{
 					Raw: []byte(`{
@@ -686,6 +692,7 @@ func TestSetSecret(t *testing.T) {
 				client: fakesm.Client{
 					DescribeSecretFn: fakesm.NewDescribeSecretFn(blankDescribeSecretOutput, &getSecretCorrectErr),
 					CreateSecretFn:   fakesm.NewCreateSecretFn(secretOutput, nil),
+					PutResourcePolicyFn: fakesm.NewPutResourcePolicyFn(&awssm.PutResourcePolicyOutput{}, nil),
 				},
 				pushSecretData: pushSecretDataWithoutProperty,
 			},
@@ -721,6 +728,7 @@ func TestSetSecret(t *testing.T) {
 					}),
 					TagResourceFn:   fakesm.NewTagResourceFn(&awssm.TagResourceOutput{}, nil),
 					UntagResourceFn: fakesm.NewUntagResourceFn(&awssm.UntagResourceOutput{}, nil),
+					DeleteResourcePolicyFn: fakesm.NewDeleteResourcePolicyFn(&awssm.DeleteResourcePolicyOutput{}, nil),
 				},
 				pushSecretData: pushSecretDataWithProperty,
 			},
@@ -745,6 +753,7 @@ func TestSetSecret(t *testing.T) {
 					}),
 					TagResourceFn:   fakesm.NewTagResourceFn(&awssm.TagResourceOutput{}, nil),
 					UntagResourceFn: fakesm.NewUntagResourceFn(&awssm.UntagResourceOutput{}, nil),
+					DeleteResourcePolicyFn: fakesm.NewDeleteResourcePolicyFn(&awssm.DeleteResourcePolicyOutput{}, nil),
 				},
 				pushSecretData: pushSecretDataWithProperty,
 			},
@@ -769,6 +778,7 @@ func TestSetSecret(t *testing.T) {
 					}),
 					TagResourceFn:   fakesm.NewTagResourceFn(&awssm.TagResourceOutput{}, nil),
 					UntagResourceFn: fakesm.NewUntagResourceFn(&awssm.UntagResourceOutput{}, nil),
+					DeleteResourcePolicyFn: fakesm.NewDeleteResourcePolicyFn(&awssm.DeleteResourcePolicyOutput{}, nil),
 				},
 				pushSecretData: pushSecretDataWithoutProperty,
 			},
@@ -793,6 +803,7 @@ func TestSetSecret(t *testing.T) {
 					}),
 					TagResourceFn:   fakesm.NewTagResourceFn(&awssm.TagResourceOutput{}, nil),
 					UntagResourceFn: fakesm.NewUntagResourceFn(&awssm.UntagResourceOutput{}, nil),
+					DeleteResourcePolicyFn: fakesm.NewDeleteResourcePolicyFn(&awssm.DeleteResourcePolicyOutput{}, nil),
 				},
 				pushSecretData: pushSecretDataWithProperty,
 			},
@@ -814,6 +825,7 @@ func TestSetSecret(t *testing.T) {
 					}),
 					TagResourceFn:   fakesm.NewTagResourceFn(&awssm.TagResourceOutput{}, nil),
 					UntagResourceFn: fakesm.NewUntagResourceFn(&awssm.UntagResourceOutput{}, nil),
+					DeleteResourcePolicyFn: fakesm.NewDeleteResourcePolicyFn(&awssm.DeleteResourcePolicyOutput{}, nil),
 				},
 				pushSecretData: pushSecretDataWithProperty,
 			},
@@ -835,6 +847,7 @@ func TestSetSecret(t *testing.T) {
 					}),
 					TagResourceFn:   fakesm.NewTagResourceFn(&awssm.TagResourceOutput{}, nil),
 					UntagResourceFn: fakesm.NewUntagResourceFn(&awssm.UntagResourceOutput{}, nil),
+					DeleteResourcePolicyFn: fakesm.NewDeleteResourcePolicyFn(&awssm.DeleteResourcePolicyOutput{}, nil),
 				},
 				pushSecretData: fake.PushSecretData{SecretKey: secretKey, RemoteKey: fakeKey, Property: "fake-property.other-fake-property"},
 			},
@@ -907,6 +920,7 @@ func TestSetSecret(t *testing.T) {
 					DescribeSecretFn: fakesm.NewDescribeSecretFn(tagSecretOutput, nil),
 					TagResourceFn:    fakesm.NewTagResourceFn(&awssm.TagResourceOutput{}, nil),
 					UntagResourceFn:  fakesm.NewUntagResourceFn(&awssm.UntagResourceOutput{}, nil),
+					DeleteResourcePolicyFn: fakesm.NewDeleteResourcePolicyFn(&awssm.DeleteResourcePolicyOutput{}, nil),
 				},
 				pushSecretData: pushSecretDataWithoutProperty,
 			},
@@ -982,6 +996,7 @@ func TestSetSecret(t *testing.T) {
 						assert.Equal(t, []string{"team"}, input.TagKeys)
 						assert.NotContains(t, input.TagKeys, managedBy)
 					}),
+					DeleteResourcePolicyFn: fakesm.NewDeleteResourcePolicyFn(&awssm.DeleteResourcePolicyOutput{}, nil),
 				},
 				pushSecretData: fake.PushSecretData{SecretKey: secretKey, RemoteKey: fakeKey, Property: "", Metadata: &apiextensionsv1.JSON{
 					Raw: []byte(`{