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:
parent
f1f6bf1931
commit
1cfca77b9b
2 changed files with 128 additions and 20 deletions
|
@ -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{
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue