Skip to content
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 32 additions & 19 deletions aws/aws_kms/aws_kms.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
package aws_kms

import (
"context"
"encoding/base64"
"fmt"
"github.com/libopenstorage/secrets/aws/utils"
"os"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/kms"
"github.com/libopenstorage/secrets/aws/utils"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/kms"
"github.com/aws/aws-sdk-go-v2/service/kms/types"
"github.com/libopenstorage/secrets"
sc "github.com/libopenstorage/secrets/aws/credentials"
"github.com/libopenstorage/secrets/pkg/store"
Expand All @@ -28,9 +30,8 @@ const (
)

type awsKmsSecrets struct {
client *kms.KMS
creds *credentials.Credentials
sess *session.Session
client *kms.Client
creds *aws.Credentials
cmk string
asc sc.AWSCredentials
ps store.PersistenceStore
Expand Down Expand Up @@ -84,22 +85,34 @@ func New(
if err != nil {
return nil, fmt.Errorf("Failed to get credentials: %v", err)
}
config := &aws.Config{
Credentials: creds,
Region: &region,
credProv := credentialsToProvider(creds)
config := aws.Config{
Credentials: credProv,
Region: region,
}
sess := session.New(config)
kmsClient := kms.New(sess)

kmsClient := kms.NewFromConfig(config)

return &awsKmsSecrets{
client: kmsClient,
sess: sess,
creds: creds,
cmk: cmk,
asc: asc,
ps: ps,
}, nil
}

func credentialsToProvider(creds *aws.Credentials) aws.CredentialsProvider {
return credentials.StaticCredentialsProvider{
Value: aws.Credentials{
AccessKeyID: creds.AccessKeyID,
SecretAccessKey: creds.SecretAccessKey,
SessionToken: creds.SessionToken,
Source: creds.Source,
},
}
}

func (a *awsKmsSecrets) String() string {
return Name
}
Expand Down Expand Up @@ -139,10 +152,10 @@ func (a *awsKmsSecrets) GetSecret(
decodedCipherBlob = cipherBlob
}
input := &kms.DecryptInput{
EncryptionContext: getAWSKeyContext(keyContext),
EncryptionContext: keyContext,
CiphertextBlob: decodedCipherBlob,
}
output, err := a.client.Decrypt(input)
output, err := a.client.Decrypt(context.TODO(), input)
if err != nil {
return nil, secrets.NoVersion, err
}
Expand Down Expand Up @@ -203,11 +216,11 @@ func (a *awsKmsSecrets) PutSecret(
keySpec := "AES_256"
input := &kms.GenerateDataKeyInput{
KeyId: &a.cmk,
EncryptionContext: getAWSKeyContext(keyContext),
KeySpec: &keySpec,
EncryptionContext: keyContext,
KeySpec: types.DataKeySpec(keySpec),
}

output, err := a.client.GenerateDataKey(input)
output, err := a.client.GenerateDataKey(context.TODO(), input)
if err != nil {
return secrets.NoVersion, err
}
Expand Down
4 changes: 4 additions & 0 deletions aws/aws_kms/aws_kms_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package aws_kms
import (
"os"
"testing"
"time"

"github.com/libopenstorage/secrets"
"github.com/libopenstorage/secrets/aws/utils"
Expand Down Expand Up @@ -164,6 +165,9 @@ func (a *awsSecretTest) TestDeleteSecret(t *testing.T) error {
err := a.s.DeleteSecret(secretIdWithData, nil)
assert.NoError(t, err, "Expected DeleteSecret to succeed")

// Add a delay to allow time for deletion to propagate
time.Sleep(time.Second * 90)

// Get of a deleted key should fail
_, _, err = a.s.GetSecret(secretIdWithData, nil)
assert.EqualError(t, secrets.ErrInvalidSecretId, err.Error(), "Unexpected error on GetSecret after delete")
Expand Down
66 changes: 40 additions & 26 deletions aws/aws_secrets_manager/aws_scm.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,16 @@ package aws_secrets_manager
import (
"context"
"encoding/json"
"errors"
"fmt"
"os"
"strconv"
"strings"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/secretsmanager"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/credentials"
"github.com/aws/aws-sdk-go-v2/service/secretsmanager"
"github.com/aws/smithy-go"
"github.com/libopenstorage/secrets"
sc "github.com/libopenstorage/secrets/aws/credentials"
"github.com/libopenstorage/secrets/aws/utils"
Expand All @@ -26,7 +27,7 @@ const (

// AWSSecretsMgr is backend for secrets.SecretStore.
type AWSSecretsMgr struct {
scm *secretsmanager.SecretsManager
scm *secretsmanager.Client
}

// New creates new instance of AWSSecretsMgr with provided configuration.
Expand All @@ -39,7 +40,7 @@ func New(

awsConfig, ok := secretConfig[utils.AwsConfigKey]
if ok {
awsConfig, ok := awsConfig.(*aws.Config)
awsConfig, ok := awsConfig.(aws.Config)
if !ok {
return nil, utils.ErrAWSConfigWrongType
}
Expand Down Expand Up @@ -68,21 +69,30 @@ func New(
if err != nil {
return nil, fmt.Errorf("failed to get credentials: %v", err)
}
config := &aws.Config{
Credentials: creds,
Region: &region,
credProv := CredentialsToProvider(creds)
config := aws.Config{
Credentials: credProv,
Region: region,
}

return NewFromAWSConfig(config)
}

// NewFromAWSConfig creates new instance of AWSSecretsMgr with provided AWS configuration (aws.Config).
func NewFromAWSConfig(config *aws.Config) (*AWSSecretsMgr, error) {
sess, err := session.NewSession(config)
if err != nil {
return nil, fmt.Errorf("failed to create a session: %v", err)
// credentialsToProvider converts a aws.Credential object to a aws.CredentialProvider object
func CredentialsToProvider(creds *aws.Credentials) aws.CredentialsProvider {
return credentials.StaticCredentialsProvider{
Value: aws.Credentials{
AccessKeyID: creds.AccessKeyID,
SecretAccessKey: creds.SecretAccessKey,
SessionToken: creds.SessionToken,
Source: creds.Source,
},
}
scm := secretsmanager.New(sess)
}

// NewFromAWSConfig creates new instance of AWSSecretsMgr with provided AWS configuration (aws.Config).
func NewFromAWSConfig(config aws.Config) (*AWSSecretsMgr, error) {
scm := secretsmanager.NewFromConfig(config)
return &AWSSecretsMgr{
scm: scm,
}, nil
Expand Down Expand Up @@ -175,15 +185,17 @@ func (a *AWSSecretsMgr) Rencrypt(
}

func (a *AWSSecretsMgr) get(secretID string) (map[string]interface{}, secrets.Version, error) {
secretValueOutput, err := a.scm.GetSecretValue(&secretsmanager.GetSecretValueInput{
secretValueOutput, err := a.scm.GetSecretValue(context.TODO(), &secretsmanager.GetSecretValueInput{
SecretId: aws.String(secretID),
})
if err != nil {
if aerr, ok := err.(awserr.Error); ok {
if aerr.Code() == secretsmanager.ErrCodeResourceNotFoundException {
var apiErr smithy.APIError
if errors.As(err, &apiErr) {
// aerr, ok := err.(awserr.Error); ok {
if apiErr.ErrorCode() == "ResourceNotFoundException" {
return nil, secrets.NoVersion, secrets.ErrInvalidSecretId
} else if aerr.Code() == secretsmanager.ErrCodeInvalidRequestException &&
strings.Contains(aerr.Error(), "marked for deletion") {
} else if apiErr.ErrorCode() == "InvalidRequestException" &&
strings.Contains(apiErr.ErrorCode(), "Marked for deletion") {
return nil, secrets.NoVersion, secrets.ErrInvalidSecretId
}
}
Expand Down Expand Up @@ -214,12 +226,12 @@ func (a *AWSSecretsMgr) put(
return secrets.NoVersion, fmt.Errorf("failed to marshal secret data: %v", err)
}
// Check if there already exists a key.
_, err = a.scm.GetSecretValue(&secretsmanager.GetSecretValueInput{
_, err = a.scm.GetSecretValue(context.TODO(), &secretsmanager.GetSecretValueInput{
SecretId: aws.String(secretID),
})
if err == nil {
// Update the existing secret
secretValueOutput, putErr := a.scm.PutSecretValue(&secretsmanager.PutSecretValueInput{
secretValueOutput, putErr := a.scm.PutSecretValue(context.TODO(), &secretsmanager.PutSecretValueInput{
SecretId: aws.String(secretID),
SecretString: aws.String(string(secretBytes)),
})
Expand All @@ -231,10 +243,12 @@ func (a *AWSSecretsMgr) put(
}
return secrets.Version(*secretValueOutput.VersionId), nil
} else {
if aerr, ok := err.(awserr.Error); ok {
if aerr.Code() == secretsmanager.ErrCodeResourceNotFoundException {
// if aerr, ok := err.(awserr.Error); ok {
var apiErr smithy.APIError
if errors.As(err, &apiErr) {
if apiErr.ErrorCode() == "ResourceNotFoundException" {
// Create a new secret
secretValueOutput, createErr := a.scm.CreateSecret(&secretsmanager.CreateSecretInput{
secretValueOutput, createErr := a.scm.CreateSecret(context.TODO(), &secretsmanager.CreateSecretInput{
SecretString: aws.String(string(secretBytes)),
Name: aws.String(secretID),
})
Expand Down Expand Up @@ -278,7 +292,7 @@ func (a *AWSSecretsMgr) delete(
}
}

_, err := a.scm.DeleteSecret(deleteSecretInput)
_, err := a.scm.DeleteSecret(context.TODO(), deleteSecretInput)
if err != nil {
return &secrets.ErrProviderInternal{Reason: err.Error(), Provider: Name}
}
Expand Down
14 changes: 12 additions & 2 deletions aws/aws_secrets_manager/aws_scm_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package aws_secrets_manager
import (
"os"
"testing"
"time"

"github.com/libopenstorage/secrets"
"github.com/libopenstorage/secrets/aws/utils"
Expand Down Expand Up @@ -107,18 +108,27 @@ func (a *awsSecretTest) TestListSecrets(t *testing.T) error {

func (a *awsSecretTest) TestDeleteSecret(t *testing.T) error {
// Delete of a key that exists should succeed
err := a.s.DeleteSecret(a.secretIdWithData, nil)
keyContext := make(map[string]string)
keyContext[SecretRetentionPeriodInDaysKey] = "7"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you ad a retention period then the subsequent GetSecret check is going to fail ? The integration tests are failing for SecretsManager. Can you check?


err := a.s.DeleteSecret(a.secretIdWithData, keyContext)
assert.NoError(t, err, "Expected DeleteSecret to succeed")

// Add a delay to allow time for deletion to propagate
time.Sleep(time.Second * 200)

// Get of a deleted key should fail
_, version, err := a.s.GetSecret(a.secretIdWithData, nil)
assert.EqualError(t, secrets.ErrInvalidSecretId, err.Error(), "Unexpected error on GetSecret after delete")
assert.Equal(t, version, secrets.NoVersion)

// Delete of a key that exists should succeed
err = a.s.DeleteSecret(a.secretIdWithoutData, nil)
err = a.s.DeleteSecret(a.secretIdWithoutData, keyContext)
assert.NoError(t, err, "Expected DeleteSecret to succeed")

// Add a delay to allow time for deletion to propagate
time.Sleep(time.Second * 200)

// GetSecret using a secretId without data
_, version, err = a.s.GetSecret(a.secretIdWithoutData, nil)
assert.EqualError(t, secrets.ErrInvalidSecretId, err.Error(), "Unexpected error on GetSecret after delete")
Expand Down
Loading