Browse Source

Support PushSecret Property for AWS SM (#2623)

* Support PushSecret Property for AWS SM

Signed-off-by: Ben Bertrands <public@bb-it.dev>

* Support PushSecret Property for AWS SM: leverage the VersionId field to prevent a "LostUpdate" concurrency problem

Signed-off-by: Ben Bertrands <public@bb-it.dev>

* Support PushSecret Property for AWS SM: errors.Join doesn't exist in go 1.19

Signed-off-by: Ben Bertrands <public@bb-it.dev>

* Support PushSecret Property for AWS SM: use an incrementing uuid for the secret version

Signed-off-by: Ben Bertrands <public@bb-it.dev>

---------

Signed-off-by: Ben Bertrands <public@bb-it.dev>
Signed-off-by: Ben Bertrands <8938515+benbertrands@users.noreply.github.com>
Ben Bertrands 2 years ago
parent
commit
cfb629c020

+ 52 - 4
pkg/provider/aws/secretsmanager/fake/fake.go

@@ -15,6 +15,7 @@ limitations under the License.
 package fake
 
 import (
+	"bytes"
 	"fmt"
 
 	"github.com/aws/aws-sdk-go/aws"
@@ -44,8 +45,17 @@ func (sm Client) CreateSecretWithContext(ctx aws.Context, input *awssm.CreateSec
 	return sm.CreateSecretWithContextFn(ctx, input, options...)
 }
 
-func NewCreateSecretWithContextFn(output *awssm.CreateSecretOutput, err error) CreateSecretWithContextFn {
-	return func(ctx aws.Context, input *awssm.CreateSecretInput, options ...request.Option) (*awssm.CreateSecretOutput, error) {
+func NewCreateSecretWithContextFn(output *awssm.CreateSecretOutput, err error, expectedSecretBinary ...[]byte) CreateSecretWithContextFn {
+	return func(ctx aws.Context, actualInput *awssm.CreateSecretInput, options ...request.Option) (*awssm.CreateSecretOutput, error) {
+		if *actualInput.ClientRequestToken != "00000000-0000-0000-0000-000000000001" {
+			return nil, fmt.Errorf("expected the version to be 1 at creation")
+		}
+		if len(expectedSecretBinary) == 1 {
+			if bytes.Equal(actualInput.SecretBinary, expectedSecretBinary[0]) {
+				return output, err
+			}
+			return nil, fmt.Errorf("expected secret to be '%s' but was '%s'", string(expectedSecretBinary[0]), string(actualInput.SecretBinary))
+		}
 		return output, err
 	}
 }
@@ -73,8 +83,46 @@ func (sm Client) PutSecretValueWithContext(ctx aws.Context, input *awssm.PutSecr
 	return sm.PutSecretValueWithContextFn(ctx, input, options...)
 }
 
-func NewPutSecretValueWithContextFn(output *awssm.PutSecretValueOutput, err error) PutSecretValueWithContextFn {
-	return func(aws.Context, *awssm.PutSecretValueInput, ...request.Option) (*awssm.PutSecretValueOutput, error) {
+type ExpectedPutSecretValueInput struct {
+	SecretBinary []byte
+	Version      *string
+}
+
+func (e ExpectedPutSecretValueInput) assertEquals(actualInput *awssm.PutSecretValueInput) error {
+	errSecretBinary := e.assertSecretBinary(actualInput)
+	if errSecretBinary != nil {
+		return errSecretBinary
+	}
+	errSecretVersion := e.assertVersion(actualInput)
+	if errSecretVersion != nil {
+		return errSecretVersion
+	}
+
+	return nil
+}
+
+func (e ExpectedPutSecretValueInput) assertSecretBinary(actualInput *awssm.PutSecretValueInput) error {
+	if e.SecretBinary != nil && !bytes.Equal(actualInput.SecretBinary, e.SecretBinary) {
+		return fmt.Errorf("expected secret to be '%s' but was '%s'", string(e.SecretBinary), string(actualInput.SecretBinary))
+	}
+	return nil
+}
+
+func (e ExpectedPutSecretValueInput) assertVersion(actualInput *awssm.PutSecretValueInput) error {
+	if e.Version != nil && (*actualInput.ClientRequestToken != *e.Version) {
+		return fmt.Errorf("expected version to be '%s', but was '%s'", *e.Version, *actualInput.ClientRequestToken)
+	}
+	return nil
+}
+
+func NewPutSecretValueWithContextFn(output *awssm.PutSecretValueOutput, err error, expectedInput ...ExpectedPutSecretValueInput) PutSecretValueWithContextFn {
+	return func(actualContext aws.Context, actualInput *awssm.PutSecretValueInput, actualOptions ...request.Option) (*awssm.PutSecretValueOutput, error) {
+		if len(expectedInput) == 1 {
+			assertErr := expectedInput[0].assertEquals(actualInput)
+			if assertErr != nil {
+				return nil, assertErr
+			}
+		}
 		return output, err
 	}
 }

+ 88 - 16
pkg/provider/aws/secretsmanager/secretsmanager.go

@@ -20,6 +20,7 @@ import (
 	"encoding/json"
 	"errors"
 	"fmt"
+	"math/big"
 	"strings"
 
 	"github.com/aws/aws-sdk-go/aws"
@@ -27,7 +28,9 @@ import (
 	"github.com/aws/aws-sdk-go/aws/request"
 	"github.com/aws/aws-sdk-go/aws/session"
 	awssm "github.com/aws/aws-sdk-go/service/secretsmanager"
+	"github.com/google/uuid"
 	"github.com/tidwall/gjson"
+	"github.com/tidwall/sjson"
 	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
 	utilpointer "k8s.io/utils/ptr"
 	ctrl "sigs.k8s.io/controller-runtime"
@@ -66,6 +69,7 @@ const (
 	errUnexpectedFindOperator = "unexpected find operator"
 	managedBy                 = "managed-by"
 	externalSecrets           = "external-secrets"
+	initialVersion            = "00000000-0000-0000-0000-000000000001"
 )
 
 var log = ctrl.Log.WithName("provider").WithName("aws").WithName("secretsmanager")
@@ -198,11 +202,6 @@ func (sm *SecretsManager) PushSecret(ctx context.Context, value []byte, _ *apiex
 			Value: &externalSecrets,
 		},
 	}
-	secretRequest := awssm.CreateSecretInput{
-		Name:         &secretName,
-		SecretBinary: value,
-		Tags:         externalSecretsTag,
-	}
 
 	secretValue := awssm.GetSecretValueInput{
 		SecretId: &secretName,
@@ -214,12 +213,28 @@ func (sm *SecretsManager) PushSecret(ctx context.Context, value []byte, _ *apiex
 
 	awsSecret, err := sm.client.GetSecretValueWithContext(ctx, &secretValue)
 	metrics.ObserveAPICall(constants.ProviderAWSSM, constants.CallAWSSMGetSecretValue, err)
+
+	if remoteRef.GetProperty() != "" {
+		currentSecret := sm.retrievePayload(awsSecret)
+		if currentSecret != "" && !gjson.Valid(currentSecret) {
+			return errors.New("PushSecret for aws secrets manager with a remoteRef property requires a json secret")
+		}
+		value, _ = sjson.SetBytes([]byte(currentSecret), remoteRef.GetProperty(), value)
+	}
+
 	var aerr awserr.Error
 	if err != nil {
 		if ok := errors.As(err, &aerr); !ok {
 			return err
 		}
 		if aerr.Code() == awssm.ErrCodeResourceNotFoundException {
+			secretVersion := initialVersion
+			secretRequest := awssm.CreateSecretInput{
+				Name:               &secretName,
+				SecretBinary:       value,
+				Tags:               externalSecretsTag,
+				ClientRequestToken: &secretVersion,
+			}
 			_, err = sm.client.CreateSecretWithContext(ctx, &secretRequest)
 			metrics.ObserveAPICall(constants.ProviderAWSSM, constants.CallAWSSMCreateSecret, err)
 			return err
@@ -237,15 +252,56 @@ func (sm *SecretsManager) PushSecret(ctx context.Context, value []byte, _ *apiex
 	if awsSecret != nil && bytes.Equal(awsSecret.SecretBinary, value) {
 		return nil
 	}
+
+	newVersionNumber, err := bumpVersionNumber(awsSecret.VersionId)
+	if err != nil {
+		return err
+	}
 	input := &awssm.PutSecretValueInput{
-		SecretId:     awsSecret.ARN,
-		SecretBinary: value,
+		SecretId:           awsSecret.ARN,
+		SecretBinary:       value,
+		ClientRequestToken: newVersionNumber,
 	}
 	_, err = sm.client.PutSecretValueWithContext(ctx, input)
 	metrics.ObserveAPICall(constants.ProviderAWSSM, constants.CallAWSSMPutSecretValue, err)
 	return err
 }
 
+func padOrTrim(b []byte) []byte {
+	l := len(b)
+	size := 16
+	if l == size {
+		return b
+	}
+	if l > size {
+		return b[l-size:]
+	}
+	tmp := make([]byte, size)
+	copy(tmp[size-l:], b)
+	return tmp
+}
+
+func bumpVersionNumber(id *string) (*string, error) {
+	if id == nil {
+		output := initialVersion
+		return &output, nil
+	}
+	n := new(big.Int)
+	oldVersion, ok := n.SetString(strings.ReplaceAll(*id, "-", ""), 16)
+	if !ok {
+		return nil, fmt.Errorf("expected secret version in AWS SSM to be a UUID but got '%s'", *id)
+	}
+	newVersionRaw := oldVersion.Add(oldVersion, big.NewInt(1)).Bytes()
+
+	newVersion, err := uuid.FromBytes(padOrTrim(newVersionRaw))
+	if err != nil {
+		return nil, err
+	}
+
+	s := newVersion.String()
+	return &s, nil
+}
+
 func isManagedByESO(data *awssm.DescribeSecretOutput) bool {
 	managedBy := managedBy
 	externalSecrets := externalSecrets
@@ -401,6 +457,21 @@ func (sm *SecretsManager) GetSecret(ctx context.Context, ref esv1beta1.ExternalS
 		}
 		return nil, fmt.Errorf("invalid secret received. no secret string nor binary for key: %s", ref.Key)
 	}
+	val := sm.mapSecretToGjson(secretOut, ref.Property)
+	if !val.Exists() {
+		return nil, fmt.Errorf("key %s does not exist in secret %s", ref.Property, ref.Key)
+	}
+	return []byte(val.String()), nil
+}
+
+func (sm *SecretsManager) mapSecretToGjson(secretOut *awssm.GetSecretValueOutput, property string) gjson.Result {
+	payload := sm.retrievePayload(secretOut)
+	refProperty := sm.escapeDotsIfRequired(property, payload)
+	val := gjson.Get(payload, refProperty)
+	return val
+}
+
+func (sm *SecretsManager) retrievePayload(secretOut *awssm.GetSecretValueOutput) string {
 	var payload string
 	if secretOut.SecretString != nil {
 		payload = *secretOut.SecretString
@@ -408,20 +479,21 @@ func (sm *SecretsManager) GetSecret(ctx context.Context, ref esv1beta1.ExternalS
 	if secretOut.SecretBinary != nil {
 		payload = string(secretOut.SecretBinary)
 	}
+	return payload
+}
+
+func (sm *SecretsManager) escapeDotsIfRequired(currentRefProperty, payload string) string {
 	// We need to search if a given key with a . exists before using gjson operations.
-	idx := strings.Index(ref.Property, ".")
+	idx := strings.Index(currentRefProperty, ".")
+	refProperty := currentRefProperty
 	if idx > -1 {
-		refProperty := strings.ReplaceAll(ref.Property, ".", "\\.")
+		refProperty = strings.ReplaceAll(currentRefProperty, ".", "\\.")
 		val := gjson.Get(payload, refProperty)
-		if val.Exists() {
-			return []byte(val.String()), nil
+		if !val.Exists() {
+			refProperty = currentRefProperty
 		}
 	}
-	val := gjson.Get(payload, ref.Property)
-	if !val.Exists() {
-		return nil, fmt.Errorf("key %s does not exist in secret %s", ref.Property, ref.Key)
-	}
-	return []byte(val.String()), nil
+	return refProperty
 }
 
 // GetSecretMap returns multiple k/v pairs from the provider.

+ 194 - 7
pkg/provider/aws/secretsmanager/secretsmanager_test.go

@@ -366,7 +366,8 @@ func ErrorContains(out error, want string) bool {
 }
 
 type fakeRef struct {
-	key string
+	key      string
+	property string
 }
 
 func (f fakeRef) GetRemoteKey() string {
@@ -374,7 +375,7 @@ func (f fakeRef) GetRemoteKey() string {
 }
 
 func (f fakeRef) GetProperty() string {
-	return ""
+	return f.property
 }
 
 func TestSetSecret(t *testing.T) {
@@ -416,24 +417,57 @@ func TestSetSecret(t *testing.T) {
 		Tags: externalSecretsTagFaulty,
 	}
 
+	initialVersion := "00000000-0000-0000-0000-000000000001"
+	defaultVersion := "00000000-0000-0000-0000-000000000002"
+	defaultUpdatedVersion := "00000000-0000-0000-0000-000000000003"
+	randomUUIDVersion := "c2812e8d-84ce-4858-abec-7163d8ab312b"
+	randomUUIDVersionIncremented := "c2812e8d-84ce-4858-abec-7163d8ab312c"
+	unparsableVersion := "IAM UNPARSABLE"
+
 	secretValueOutput := &awssm.GetSecretValueOutput{
-		ARN: &arn,
+		ARN:       &arn,
+		VersionId: &defaultVersion,
 	}
 
 	secretValueOutput2 := &awssm.GetSecretValueOutput{
 		ARN:          &arn,
 		SecretBinary: secretValue,
+		VersionId:    &defaultVersion,
+	}
+
+	type params struct {
+		s       string
+		b       []byte
+		version *string
 	}
+	secretValueOutputFrom := func(params params) *awssm.GetSecretValueOutput {
+		var version *string
+		if params.version == nil {
+			version = &defaultVersion
+		} else {
+			version = params.version
+		}
 
+		return &awssm.GetSecretValueOutput{
+			ARN:          &arn,
+			SecretString: &params.s,
+			SecretBinary: params.b,
+			VersionId:    version,
+		}
+	}
 	blankSecretValueOutput := &awssm.GetSecretValueOutput{}
 
 	putSecretOutput := &awssm.PutSecretValueOutput{
 		ARN: &arn,
 	}
 
+	remoteRefWithoutProperty := fakeRef{key: "fake-key", property: ""}
+	remoteRefWithProperty := fakeRef{key: "fake-key", property: "other-fake-property"}
+
 	type args struct {
-		store  *esv1beta1.AWSProvider
-		client fakesm.Client
+		store     *esv1beta1.AWSProvider
+		client    fakesm.Client
+		remoteRef fakeRef
 	}
 
 	type want struct {
@@ -454,6 +488,7 @@ func TestSetSecret(t *testing.T) {
 					PutSecretValueWithContextFn: fakesm.NewPutSecretValueWithContextFn(putSecretOutput, nil),
 					DescribeSecretWithContextFn: fakesm.NewDescribeSecretWithContextFn(tagSecretOutput, nil),
 				},
+				remoteRef: remoteRefWithoutProperty,
 			},
 			want: want{
 				err: nil,
@@ -467,11 +502,157 @@ func TestSetSecret(t *testing.T) {
 					GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(blankSecretValueOutput, &getSecretCorrectErr),
 					CreateSecretWithContextFn:   fakesm.NewCreateSecretWithContextFn(secretOutput, nil),
 				},
+				remoteRef: remoteRefWithoutProperty,
+			},
+			want: want{
+				err: nil,
+			},
+		},
+		"SetSecretWithPropertySucceedsWithNewSecret": {
+			reason: "if a new secret is pushed to aws sm and a remoteRef property is specified, create a json secret with the remoteRef property as a key",
+			args: args{
+				store: makeValidSecretStore().Spec.Provider.AWS,
+				client: fakesm.Client{
+					GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(blankSecretValueOutput, &getSecretCorrectErr),
+					CreateSecretWithContextFn:   fakesm.NewCreateSecretWithContextFn(secretOutput, nil, []byte(`{"other-fake-property":"fake-value"}`)),
+				},
+				remoteRef: remoteRefWithProperty,
+			},
+			want: want{
+				err: nil,
+			},
+		},
+		"SetSecretWithPropertySucceedsWithExistingSecretAndNewPropertyBinary": {
+			reason: "when a remoteRef property is specified, this property will be added to the sm secret if it is currently absent (sm secret is binary)",
+			args: args{
+				store: makeValidSecretStore().Spec.Provider.AWS,
+				client: fakesm.Client{
+					GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(secretValueOutputFrom(params{b: []byte((`{"fake-property":"fake-value"}`))}), nil),
+					DescribeSecretWithContextFn: fakesm.NewDescribeSecretWithContextFn(tagSecretOutput, nil),
+					PutSecretValueWithContextFn: fakesm.NewPutSecretValueWithContextFn(putSecretOutput, nil, fakesm.ExpectedPutSecretValueInput{
+						SecretBinary: []byte(`{"fake-property":"fake-value","other-fake-property":"fake-value"}`),
+						Version:      &defaultUpdatedVersion,
+					}),
+				},
+				remoteRef: remoteRefWithProperty,
+			},
+			want: want{
+				err: nil,
+			},
+		},
+		"SetSecretWithPropertySucceedsWithExistingSecretAndRandomUUIDVersion": {
+			reason: "When a secret version is not specified, the client sets a random uuid by default. We should treat a version that can't be parsed to an int as not having a version",
+			args: args{
+				store: makeValidSecretStore().Spec.Provider.AWS,
+				client: fakesm.Client{
+					GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(secretValueOutputFrom(params{
+						b:       []byte((`{"fake-property":"fake-value"}`)),
+						version: &randomUUIDVersion,
+					}), nil),
+					DescribeSecretWithContextFn: fakesm.NewDescribeSecretWithContextFn(tagSecretOutput, nil),
+					PutSecretValueWithContextFn: fakesm.NewPutSecretValueWithContextFn(putSecretOutput, nil, fakesm.ExpectedPutSecretValueInput{
+						SecretBinary: []byte(`{"fake-property":"fake-value","other-fake-property":"fake-value"}`),
+						Version:      &randomUUIDVersionIncremented,
+					}),
+				},
+				remoteRef: remoteRefWithProperty,
 			},
 			want: want{
 				err: nil,
 			},
 		},
+		"SetSecretWithPropertySucceedsWithExistingSecretAndVersionThatCantBeParsed": {
+			reason: "A manually set secret version doesn't have to be a UUID, we only support UUID secret versions though",
+			args: args{
+				store: makeValidSecretStore().Spec.Provider.AWS,
+				client: fakesm.Client{
+					GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(secretValueOutputFrom(params{
+						b:       []byte((`{"fake-property":"fake-value"}`)),
+						version: &unparsableVersion,
+					}), nil),
+					DescribeSecretWithContextFn: fakesm.NewDescribeSecretWithContextFn(tagSecretOutput, nil),
+					PutSecretValueWithContextFn: fakesm.NewPutSecretValueWithContextFn(putSecretOutput, nil, fakesm.ExpectedPutSecretValueInput{
+						SecretBinary: []byte(`{"fake-property":"fake-value","other-fake-property":"fake-value"}`),
+						Version:      &initialVersion,
+					}),
+				},
+				remoteRef: remoteRefWithProperty,
+			},
+			want: want{
+				err: fmt.Errorf("expected secret version in AWS SSM to be a UUID but got '%s'", unparsableVersion),
+			},
+		},
+		"SetSecretWithPropertySucceedsWithExistingSecretAndAbsentVersion": {
+			reason: "When a secret version is not specified, set it to 1",
+			args: args{
+				store: makeValidSecretStore().Spec.Provider.AWS,
+				client: fakesm.Client{
+					GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(&awssm.GetSecretValueOutput{
+						ARN:          &arn,
+						SecretBinary: []byte((`{"fake-property":"fake-value"}`)),
+					}, nil),
+					DescribeSecretWithContextFn: fakesm.NewDescribeSecretWithContextFn(tagSecretOutput, nil),
+					PutSecretValueWithContextFn: fakesm.NewPutSecretValueWithContextFn(putSecretOutput, nil, fakesm.ExpectedPutSecretValueInput{
+						SecretBinary: []byte(`{"fake-property":"fake-value","other-fake-property":"fake-value"}`),
+						Version:      &initialVersion,
+					}),
+				},
+				remoteRef: remoteRefWithProperty,
+			},
+			want: want{
+				err: nil,
+			},
+		},
+		"SetSecretWithPropertySucceedsWithExistingSecretAndNewPropertyString": {
+			reason: "when a remoteRef property is specified, this property will be added to the sm secret if it is currently absent (sm secret is a string)",
+			args: args{
+				store: makeValidSecretStore().Spec.Provider.AWS,
+				client: fakesm.Client{
+					GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(secretValueOutputFrom(params{s: `{"fake-property":"fake-value"}`}), nil),
+					DescribeSecretWithContextFn: fakesm.NewDescribeSecretWithContextFn(tagSecretOutput, nil),
+					PutSecretValueWithContextFn: fakesm.NewPutSecretValueWithContextFn(putSecretOutput, nil, fakesm.ExpectedPutSecretValueInput{
+						SecretBinary: []byte(`{"fake-property":"fake-value","other-fake-property":"fake-value"}`),
+						Version:      &defaultUpdatedVersion,
+					}),
+				},
+				remoteRef: remoteRefWithProperty,
+			},
+			want: want{
+				err: nil,
+			},
+		},
+		"SetSecretWithPropertySucceedsWithExistingSecretAndNewPropertyWithDot": {
+			reason: "when a remoteRef property is specified, this property will be added to the sm secret if it is currently absent (remoteRef property is a sub-object)",
+			args: args{
+				store: makeValidSecretStore().Spec.Provider.AWS,
+				client: fakesm.Client{
+					GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(secretValueOutputFrom(params{s: `{"fake-property":{"fake-property":"fake-value"}}`}), nil),
+					DescribeSecretWithContextFn: fakesm.NewDescribeSecretWithContextFn(tagSecretOutput, nil),
+					PutSecretValueWithContextFn: fakesm.NewPutSecretValueWithContextFn(putSecretOutput, nil, fakesm.ExpectedPutSecretValueInput{
+						SecretBinary: []byte(`{"fake-property":{"fake-property":"fake-value","other-fake-property":"fake-value"}}`),
+						Version:      &defaultUpdatedVersion,
+					}),
+				},
+				remoteRef: fakeRef{key: "fake-key", property: "fake-property.other-fake-property"},
+			},
+			want: want{
+				err: nil,
+			},
+		},
+		"SetSecretWithPropertyFailsExistingNonJsonSecret": {
+			reason: "setting a remoteRef property is only supported for json secrets",
+			args: args{
+				store: makeValidSecretStore().Spec.Provider.AWS,
+				client: fakesm.Client{
+					GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(secretValueOutputFrom(params{s: `non-json-secret`}), nil),
+					DescribeSecretWithContextFn: fakesm.NewDescribeSecretWithContextFn(tagSecretOutput, nil),
+				},
+				remoteRef: remoteRefWithProperty,
+			},
+			want: want{
+				err: errors.New("PushSecret for aws secrets manager with a remoteRef property requires a json secret"),
+			},
+		},
 		"SetSecretCreateSecretFails": {
 			reason: "CreateSecretWithContext returns an error if it fails",
 			args: args{
@@ -480,6 +661,7 @@ func TestSetSecret(t *testing.T) {
 					GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(blankSecretValueOutput, &getSecretCorrectErr),
 					CreateSecretWithContextFn:   fakesm.NewCreateSecretWithContextFn(nil, noPermission),
 				},
+				remoteRef: remoteRefWithoutProperty,
 			},
 			want: want{
 				err: noPermission,
@@ -492,6 +674,7 @@ func TestSetSecret(t *testing.T) {
 				client: fakesm.Client{
 					GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(blankSecretValueOutput, noPermission),
 				},
+				remoteRef: remoteRefWithoutProperty,
 			},
 			want: want{
 				err: noPermission,
@@ -505,6 +688,7 @@ func TestSetSecret(t *testing.T) {
 					GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(secretValueOutput2, nil),
 					DescribeSecretWithContextFn: fakesm.NewDescribeSecretWithContextFn(tagSecretOutput, nil),
 				},
+				remoteRef: remoteRefWithoutProperty,
 			},
 			want: want{
 				err: nil,
@@ -519,6 +703,7 @@ func TestSetSecret(t *testing.T) {
 					PutSecretValueWithContextFn: fakesm.NewPutSecretValueWithContextFn(nil, noPermission),
 					DescribeSecretWithContextFn: fakesm.NewDescribeSecretWithContextFn(tagSecretOutput, nil),
 				},
+				remoteRef: remoteRefWithoutProperty,
 			},
 			want: want{
 				err: noPermission,
@@ -531,6 +716,7 @@ func TestSetSecret(t *testing.T) {
 				client: fakesm.Client{
 					GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(blankSecretValueOutput, &getSecretWrongErr),
 				},
+				remoteRef: remoteRefWithoutProperty,
 			},
 			want: want{
 				err: &getSecretWrongErr,
@@ -544,6 +730,7 @@ func TestSetSecret(t *testing.T) {
 					GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(secretValueOutput, nil),
 					DescribeSecretWithContextFn: fakesm.NewDescribeSecretWithContextFn(nil, noPermission),
 				},
+				remoteRef: remoteRefWithoutProperty,
 			},
 			want: want{
 				err: noPermission,
@@ -557,6 +744,7 @@ func TestSetSecret(t *testing.T) {
 					GetSecretValueWithContextFn: fakesm.NewGetSecretValueWithContextFn(secretValueOutput, nil),
 					DescribeSecretWithContextFn: fakesm.NewDescribeSecretWithContextFn(tagSecretOutputFaulty, nil),
 				},
+				remoteRef: remoteRefWithoutProperty,
 			},
 			want: want{
 				err: fmt.Errorf("secret not managed by external-secrets"),
@@ -566,11 +754,10 @@ func TestSetSecret(t *testing.T) {
 
 	for name, tc := range tests {
 		t.Run(name, func(t *testing.T) {
-			ref := fakeRef{key: "fake-key"}
 			sm := SecretsManager{
 				client: &tc.args.client,
 			}
-			err := sm.PushSecret(context.Background(), []byte("fake-value"), nil, ref)
+			err := sm.PushSecret(context.Background(), []byte("fake-value"), nil, tc.args.remoteRef)
 
 			// Error nil XOR tc.want.err nil
 			if ((err == nil) || (tc.want.err == nil)) && !((err == nil) && (tc.want.err == nil)) {