1
0
Fork 0
mirror of https://github.com/external-secrets/external-secrets.git synced 2024-12-15 17:51:01 +00:00

Add MetadataPolicy=Fetch for AWS Secret Manager (#2025)

* Get all the properties

Signed-off-by: Sebastián Gómez <sebastiangomezcorrea@gmail.com>

* Add secrets to the cache

Signed-off-by: Sebastián Gómez <sebastiangomezcorrea@gmail.com>

* First set of tests

Signed-off-by: Sebastián Gómez <sebastiangomezcorrea@gmail.com>

* Last set of tests added

Signed-off-by: Sebastián Gómez <sebastiangomezcorrea@gmail.com>

* Fixed lint issues

Signed-off-by: Sebastián Gómez <sebastiangomezcorrea@gmail.com>

* Improved Tags to string mechanism

Signed-off-by: Sebastián Gómez <sebastiangomezcorrea@gmail.com>

* Fix lint complain

Signed-off-by: Sebastián Gómez <sebastiangomezcorrea@gmail.com>

---------

Signed-off-by: Sebastián Gómez <sebastiangomezcorrea@gmail.com>
Co-authored-by: Moritz Johner <moolen@users.noreply.github.com>
This commit is contained in:
Sebastián Gómez 2023-02-21 14:55:03 -03:00 committed by GitHub
parent f1f6bf1931
commit 1cfca77b9b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 128 additions and 20 deletions

View file

@ -77,45 +77,91 @@ func New(sess *session.Session, cfg *aws.Config, referentAuth bool) (*SecretsMan
}, nil
}
func (sm *SecretsManager) fetch(_ context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (*awssm.GetSecretValueOutput, error) {
func (sm *SecretsManager) fetch(ctx context.Context, ref esv1beta1.ExternalSecretDataRemoteRef) (*awssm.GetSecretValueOutput, error) {
ver := "AWSCURRENT"
valueFrom := "SECRET"
if ref.Version != "" {
ver = ref.Version
}
log.Info("fetching secret value", "key", ref.Key, "version", ver)
if ref.MetadataPolicy == esv1beta1.ExternalSecretMetadataPolicyFetch {
valueFrom = "TAG"
}
cacheKey := fmt.Sprintf("%s#%s", ref.Key, ver)
log.Info("fetching secret value", "key", ref.Key, "version", ver, "value", valueFrom)
cacheKey := fmt.Sprintf("%s#%s#%s", ref.Key, ver, valueFrom)
if secretOut, found := sm.cache[cacheKey]; found {
log.Info("found secret in cache", "key", ref.Key, "version", ver)
return secretOut, nil
}
var getSecretValueInput *awssm.GetSecretValueInput
if strings.HasPrefix(ver, "uuid/") {
versionID := strings.TrimPrefix(ver, "uuid/")
getSecretValueInput = &awssm.GetSecretValueInput{
SecretId: &ref.Key,
VersionId: &versionID,
var secretOut *awssm.GetSecretValueOutput
var err error
if ref.MetadataPolicy == esv1beta1.ExternalSecretMetadataPolicyFetch {
describeSecretInput := &awssm.DescribeSecretInput{
SecretId: &ref.Key,
}
descOutput, err := sm.client.DescribeSecretWithContext(ctx, describeSecretInput)
if err != nil {
return nil, err
}
log.Info("found metadata secret", "key", ref.Key, "output", descOutput)
jsonTags, err := TagsToJSONString(descOutput.Tags)
if err != nil {
return nil, err
}
secretOut = &awssm.GetSecretValueOutput{
ARN: descOutput.ARN,
CreatedDate: descOutput.CreatedDate,
Name: descOutput.Name,
SecretString: &jsonTags,
VersionId: &ver,
}
} else {
getSecretValueInput = &awssm.GetSecretValueInput{
SecretId: &ref.Key,
VersionStage: &ver,
var getSecretValueInput *awssm.GetSecretValueInput
if strings.HasPrefix(ver, "uuid/") {
versionID := strings.TrimPrefix(ver, "uuid/")
getSecretValueInput = &awssm.GetSecretValueInput{
SecretId: &ref.Key,
VersionId: &versionID,
}
} else {
getSecretValueInput = &awssm.GetSecretValueInput{
SecretId: &ref.Key,
VersionStage: &ver,
}
}
secretOut, err = sm.client.GetSecretValue(getSecretValueInput)
var nf *awssm.ResourceNotFoundException
if errors.As(err, &nf) {
return nil, esv1beta1.NoSecretErr
}
if err != nil {
return nil, err
}
}
secretOut, err := sm.client.GetSecretValue(getSecretValueInput)
var nf *awssm.ResourceNotFoundException
if errors.As(err, &nf) {
return nil, esv1beta1.NoSecretErr
}
if err != nil {
return nil, err
}
sm.cache[cacheKey] = secretOut
return secretOut, nil
}
func TagsToJSONString(tags []*awssm.Tag) (string, error) {
tagMap := make(map[string]string, len(tags))
for _, tag := range tags {
tagMap[*tag.Key] = *tag.Value
}
byteArr, err := json.Marshal(tagMap)
if err != nil {
return "", err
}
return string(byteArr), nil
}
func (sm *SecretsManager) DeleteSecret(ctx context.Context, remoteRef esv1beta1.PushRemoteRef) error {
secretName := remoteRef.GetRemoteKey()
secretValue := awssm.GetSecretValueInput{

View file

@ -46,6 +46,12 @@ type secretsManagerTestCase struct {
}
const unexpectedErrorString = "[%d] unexpected error: %s, expected: '%s'"
const (
tagname1 = "tagname1"
tagvalue1 = "tagvalue1"
tagname2 = "tagname2"
tagvalue2 = "tagvalue2"
)
func makeValidSecretsManagerTestCase() *secretsManagerTestCase {
smtc := secretsManagerTestCase{
@ -175,6 +181,41 @@ func TestSecretsManagerGetSecret(t *testing.T) {
smtc.expectedSecret = "myvalue"
}
fetchMetadata := func(smtc *secretsManagerTestCase) {
smtc.remoteRef.MetadataPolicy = esv1beta1.ExternalSecretMetadataPolicyFetch
describeSecretOutput := &awssm.DescribeSecretOutput{
Tags: getTagSlice(),
}
smtc.fakeClient.DescribeSecretWithContextFn = fakesm.NewDescribeSecretWithContextFn(describeSecretOutput, nil)
jsonTags, _ := TagsToJSONString(getTagSlice())
smtc.apiOutput.SecretString = &jsonTags
smtc.expectedSecret = jsonTags
}
fetchMetadataProperty := func(smtc *secretsManagerTestCase) {
smtc.remoteRef.MetadataPolicy = esv1beta1.ExternalSecretMetadataPolicyFetch
describeSecretOutput := &awssm.DescribeSecretOutput{
Tags: getTagSlice(),
}
smtc.fakeClient.DescribeSecretWithContextFn = fakesm.NewDescribeSecretWithContextFn(describeSecretOutput, nil)
smtc.remoteRef.Property = tagname2
jsonTags, _ := TagsToJSONString(getTagSlice())
smtc.apiOutput.SecretString = &jsonTags
smtc.expectedSecret = tagvalue2
}
failMetadataWrongProperty := func(smtc *secretsManagerTestCase) {
smtc.remoteRef.MetadataPolicy = esv1beta1.ExternalSecretMetadataPolicyFetch
describeSecretOutput := &awssm.DescribeSecretOutput{
Tags: getTagSlice(),
}
smtc.fakeClient.DescribeSecretWithContextFn = fakesm.NewDescribeSecretWithContextFn(describeSecretOutput, nil)
smtc.remoteRef.Property = "fail"
jsonTags, _ := TagsToJSONString(getTagSlice())
smtc.apiOutput.SecretString = &jsonTags
smtc.expectError = "key fail does not exist in secret /baz"
}
successCases := []*secretsManagerTestCase{
makeValidSecretsManagerTestCase(),
makeValidSecretsManagerTestCaseCustom(setSecretString),
@ -188,6 +229,9 @@ func TestSecretsManagerGetSecret(t *testing.T) {
makeValidSecretsManagerTestCaseCustom(setCustomVersionStage),
makeValidSecretsManagerTestCaseCustom(setCustomVersionID),
makeValidSecretsManagerTestCaseCustom(setAPIErr),
makeValidSecretsManagerTestCaseCustom(fetchMetadata),
makeValidSecretsManagerTestCaseCustom(fetchMetadataProperty),
makeValidSecretsManagerTestCaseCustom(failMetadataWrongProperty),
}
for k, v := range successCases {
@ -700,3 +744,21 @@ func makeValidSecretStore() *esv1beta1.SecretStore {
},
}
}
func getTagSlice() []*awssm.Tag {
tagKey1 := tagname1
tagValue1 := tagvalue1
tagKey2 := tagname2
tagValue2 := tagvalue2
return []*awssm.Tag{
{
Key: &tagKey1,
Value: &tagValue1,
},
{
Key: &tagKey2,
Value: &tagValue2,
},
}
}