Browse Source

fix: implement parameterstore versions (#2352)

Signed-off-by: Moritz Johner <beller.moritz@googlemail.com>
Moritz Johner 2 years ago
parent
commit
5fb8758278

+ 1 - 0
e2e/suites/provider/cases/aws/parameterstore/parameterstore.go

@@ -61,6 +61,7 @@ var _ = Describe("[aws] ", Label("aws", "parameterstore"), func() {
 		framework.Compose(withStaticAuth, f, FindByNameWithPath, useStaticAuth),
 		framework.Compose(withStaticAuth, f, FindByNameWithPath, useStaticAuth),
 		framework.Compose(withStaticAuth, f, FindByTag, useStaticAuth),
 		framework.Compose(withStaticAuth, f, FindByTag, useStaticAuth),
 		framework.Compose(withStaticAuth, f, FindByTagWithPath, useStaticAuth),
 		framework.Compose(withStaticAuth, f, FindByTagWithPath, useStaticAuth),
+		framework.Compose(withStaticAuth, f, VersionedParameter(prov), useStaticAuth),
 	)
 	)
 })
 })
 
 

+ 12 - 5
e2e/suites/provider/cases/aws/parameterstore/provider.go

@@ -101,12 +101,19 @@ func (s *Provider) CreateSecret(key string, val framework.SecretEntry) {
 			Value: aws.String(v),
 			Value: aws.String(v),
 		})
 		})
 	}
 	}
+	// tags and overwrite can't be used together
+	// overwrite is needed for the version test
+	overwrite := false
+	if len(val.Tags) == 0 {
+		overwrite = true
+	}
 	_, err := s.client.PutParameter(&ssm.PutParameterInput{
 	_, err := s.client.PutParameter(&ssm.PutParameterInput{
-		Name:     aws.String(key),
-		Value:    aws.String(val.Value),
-		DataType: aws.String("text"),
-		Type:     aws.String("String"),
-		Tags:     pmTags,
+		Name:      aws.String(key),
+		Value:     aws.String(val.Value),
+		DataType:  aws.String("text"),
+		Type:      aws.String("String"),
+		Overwrite: aws.Bool(overwrite),
+		Tags:      pmTags,
 	})
 	})
 	Expect(err).ToNot(HaveOccurred())
 	Expect(err).ToNot(HaveOccurred())
 }
 }

+ 61 - 0
e2e/suites/provider/cases/aws/parameterstore/version_secret.go

@@ -0,0 +1,61 @@
+/*
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+	http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+limitations under the License.
+*/
+package aws
+
+import (
+	"fmt"
+
+	v1 "k8s.io/api/core/v1"
+
+	"github.com/external-secrets/external-secrets-e2e/framework"
+	esapi "github.com/external-secrets/external-secrets/apis/externalsecrets/v1beta1"
+)
+
+// This case creates one secret secrets with multiple versions
+// the value contains the version number
+func VersionedParameter(prov *Provider) func(f *framework.Framework) (string, func(*framework.TestCase)) {
+	return func(f *framework.Framework) (string, func(*framework.TestCase)) {
+		return "[common] should read versioned secrets", func(tc *framework.TestCase) {
+			const namePrefix = "/e2e/versioned/%s/%s"
+			secretKeyOne := fmt.Sprintf(namePrefix, f.Namespace.Name, "one")
+			versions := []int{1, 2, 3, 4, 5}
+			valueStr := "value%d"
+
+			tc.ExpectedSecret = &v1.Secret{
+				Type: v1.SecretTypeOpaque,
+				Data: map[string][]byte{}, // filled below
+			}
+
+			tc.ExternalSecret.Spec.Data = make([]esapi.ExternalSecretData, len(versions))
+
+			// create many versions
+			i := 0
+			for _, v := range versions {
+				secretKey := fmt.Sprintf("v%d", v)
+				val := fmt.Sprintf(valueStr, v)
+				prov.CreateSecret(secretKeyOne, framework.SecretEntry{
+					Value: val,
+				})
+				tc.ExpectedSecret.Data[secretKey] = []byte(val)
+				tc.ExternalSecret.Spec.Data[i] = esapi.ExternalSecretData{
+					SecretKey: secretKey,
+					RemoteRef: esapi.ExternalSecretDataRemoteRef{
+						Key:     secretKeyOne,
+						Version: fmt.Sprintf("%d", v),
+					},
+				}
+				i++
+			}
+		}
+	}
+}

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

@@ -422,7 +422,7 @@ func (pm *ParameterStore) GetSecret(ctx context.Context, ref esv1beta1.ExternalS
 func (pm *ParameterStore) getParameterTags(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (*ssm.GetParameterOutput, error) {
 func (pm *ParameterStore) getParameterTags(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (*ssm.GetParameterOutput, error) {
 	param := ssm.GetParameterOutput{
 	param := ssm.GetParameterOutput{
 		Parameter: &ssm.Parameter{
 		Parameter: &ssm.Parameter{
-			Name: &ref.Key,
+			Name: parameterNameWithVersion(ref),
 		},
 		},
 	}
 	}
 	tags, err := pm.getTagsByName(ctx, &param)
 	tags, err := pm.getTagsByName(ctx, &param)
@@ -443,7 +443,7 @@ func (pm *ParameterStore) getParameterTags(ctx context.Context, ref esv1beta1.Ex
 
 
 func (pm *ParameterStore) getParameterValue(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (*ssm.GetParameterOutput, error) {
 func (pm *ParameterStore) getParameterValue(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (*ssm.GetParameterOutput, error) {
 	out, err := pm.client.GetParameterWithContext(ctx, &ssm.GetParameterInput{
 	out, err := pm.client.GetParameterWithContext(ctx, &ssm.GetParameterInput{
-		Name:           &ref.Key,
+		Name:           parameterNameWithVersion(ref),
 		WithDecryption: aws.Bool(true),
 		WithDecryption: aws.Bool(true),
 	})
 	})
 
 
@@ -474,6 +474,15 @@ func (pm *ParameterStore) GetSecretMap(ctx context.Context, ref esv1beta1.Extern
 	return secretData, nil
 	return secretData, nil
 }
 }
 
 
+func parameterNameWithVersion(ref esv1beta1.ExternalSecretDataRemoteRef) *string {
+	name := ref.Key
+	if ref.Version != "" {
+		// see docs: https://docs.aws.amazon.com/systems-manager/latest/userguide/sysman-paramstore-versions.html#reference-parameter-version
+		name += ":" + ref.Version
+	}
+	return &name
+}
+
 func (pm *ParameterStore) Close(_ context.Context) error {
 func (pm *ParameterStore) Close(_ context.Context) error {
 	return nil
 	return nil
 }
 }