Skip to content

Commit

Permalink
resource/aws_iam_access_key: Add ses_smtp_password_v4 attribute (#11144)
Browse files Browse the repository at this point in the history
Output from acceptance testing:

```
--- PASS: TestSesSmtpPasswordFromSecretKeySigV4 (0.00s)
--- PASS: TestSesSmtpPasswordFromSecretKeySigV2 (0.00s)
--- PASS: TestAccAWSAccessKey_basic (11.20s)
--- PASS: TestAccAWSAccessKey_encrypted (11.31s)
--- PASS: TestAccAWSAccessKey_inactive (18.44s)
```
  • Loading branch information
n3ph authored Feb 20, 2020
1 parent 3ae8e39 commit a30eb3e
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 7 deletions.
62 changes: 59 additions & 3 deletions aws/resource_aws_iam_access_key.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ func resourceAwsIamAccessKey() *schema.Resource {
Sensitive: true,
},
"ses_smtp_password": {
Type: schema.TypeString,
Computed: true,
Sensitive: true,
Deprecated: "AWS SigV2 for SES SMTP passwords isy deprecated.\nUse 'ses_smtp_password_v4' for region-specific AWS SigV4 signed SES SMTP password instead.",
},
"ses_smtp_password_v4": {
Type: schema.TypeString,
Computed: true,
Sensitive: true,
Expand Down Expand Up @@ -105,12 +111,20 @@ func resourceAwsIamAccessKeyCreate(d *schema.ResourceData, meta interface{}) err
}
}

sesSMTPPassword, err := sesSmtpPasswordFromSecretKey(createResp.AccessKey.SecretAccessKey)
// AWS SigV2
sesSMTPPassword, err := sesSmtpPasswordFromSecretKeySigV2(createResp.AccessKey.SecretAccessKey)
if err != nil {
return fmt.Errorf("error getting SES SMTP Password from Secret Access Key: %s", err)
return fmt.Errorf("error getting SES SigV2 SMTP Password from Secret Access Key: %s", err)
}
d.Set("ses_smtp_password", sesSMTPPassword)

// AWS SigV4
sesSMTPPasswordV4, err := sesSmtpPasswordFromSecretKeySigV4(createResp.AccessKey.SecretAccessKey, meta.(*AWSClient).region)
if err != nil {
return fmt.Errorf("error getting SES SigV4 SMTP Password from Secret Access Key: %s", err)
}
d.Set("ses_smtp_password_v4", sesSMTPPasswordV4)

return resourceAwsIamAccessKeyReadResult(d, &iam.AccessKeyMetadata{
AccessKeyId: createResp.AccessKey.AccessKeyId,
CreateDate: createResp.AccessKey.CreateDate,
Expand Down Expand Up @@ -197,7 +211,49 @@ func resourceAwsIamAccessKeyStatusUpdate(iamconn *iam.IAM, d *schema.ResourceDat
return nil
}

func sesSmtpPasswordFromSecretKey(key *string) (string, error) {
func hmacSignature(key []byte, value []byte) ([]byte, error) {
h := hmac.New(sha256.New, key)
if _, err := h.Write(value); err != nil {
return []byte(""), err
}
return h.Sum(nil), nil
}

func sesSmtpPasswordFromSecretKeySigV4(key *string, region string) (string, error) {
if key == nil {
return "", nil
}
version := byte(0x04)
date := []byte("11111111")
service := []byte("ses")
terminal := []byte("aws4_request")
message := []byte("SendRawEmail")

rawSig, err := hmacSignature([]byte("AWS4"+*key), date)
if err != nil {
return "", err
}

if rawSig, err = hmacSignature(rawSig, []byte(region)); err != nil {
return "", err
}
if rawSig, err = hmacSignature(rawSig, service); err != nil {
return "", err
}
if rawSig, err = hmacSignature(rawSig, terminal); err != nil {
return "", err
}
if rawSig, err = hmacSignature(rawSig, message); err != nil {
return "", err
}

versionedSig := make([]byte, 0, len(rawSig)+1)
versionedSig = append(versionedSig, version)
versionedSig = append(versionedSig, rawSig...)
return base64.StdEncoding.EncodeToString(versionedSig), nil
}

func sesSmtpPasswordFromSecretKeySigV2(key *string) (string, error) {
if key == nil {
return "", nil
}
Expand Down
27 changes: 25 additions & 2 deletions aws/resource_aws_iam_access_key_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,30 @@ resource "aws_iam_access_key" "a_key" {
`, rName)
}

func TestSesSmtpPasswordFromSecretKey(t *testing.T) {
func TestSesSmtpPasswordFromSecretKeySigV4(t *testing.T) {
cases := []struct {
Region string
Input string
Expected string
}{
{"eu-central-1", "some+secret+key", "BMXhUYlu5Z3gSXVQORxlVa7XPaz91aGWdfHxvkOZdWZ2"},
{"eu-central-1", "another+secret+key", "BBbphbrQmrKMx42d1N6+C7VINYEBGI5v9VsZeTxwskfh"},
{"us-west-1", "some+secret+key", "BH+jbMzper5WwlwUar9E1ySBqHa9whi0GPo+sJ0mVYJj"},
{"us-west-1", "another+secret+key", "BKVmjjMDFk/qqw8EROW99bjCS65PF8WKvK5bSr4Y6EqF"},
}

for _, tc := range cases {
actual, err := sesSmtpPasswordFromSecretKeySigV4(&tc.Input, tc.Region)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
if actual != tc.Expected {
t.Fatalf("%q: expected %q, got %q", tc.Input, tc.Expected, actual)
}
}
}

func TestSesSmtpPasswordFromSecretKeySigV2(t *testing.T) {
cases := []struct {
Input string
Expected string
Expand All @@ -244,7 +267,7 @@ func TestSesSmtpPasswordFromSecretKey(t *testing.T) {
}

for _, tc := range cases {
actual, err := sesSmtpPasswordFromSecretKey(&tc.Input)
actual, err := sesSmtpPasswordFromSecretKeySigV2(&tc.Input)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
Expand Down
22 changes: 20 additions & 2 deletions website/docs/r/iam_access_key.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,21 @@ output "secret" {
}
```

```hcl
resource "aws_iam_user" "test" {
name = "test"
path = "/test/"
}
resource "aws_iam_access_key" "test" {
user = aws_iam_user.test.name
}
output "aws_iam_smtp_password_v4" {
value = aws_iam_access_key.test.ses_smtp_password_v4
}
```

## Argument Reference

The following arguments are supported:
Expand Down Expand Up @@ -75,6 +90,9 @@ the use of the secret key in automation.
* `encrypted_secret` - The encrypted secret, base64 encoded, if `pgp_key` was specified.
~> **NOTE:** The encrypted secret may be decrypted using the command line,
for example: `terraform output encrypted_secret | base64 --decode | keybase pgp decrypt`.
* `ses_smtp_password` - The secret access key converted into an SES SMTP
password by applying [AWS's documented conversion
* `ses_smtp_password` - **DEPRECATED** The secret access key converted into an SES SMTP
password by applying AWS's SigV2 conversion algorithm
* `ses_smtp_password_v4` - The secret access key converted into an SES SMTP
password by applying [AWS's documented Sigv4 conversion
algorithm](https://docs.aws.amazon.com/ses/latest/DeveloperGuide/smtp-credentials.html#smtp-credentials-convert).
As SigV4 is region specific, valid Provider regions are `ap-south-1`, `ap-southeast-2`, `eu-central-1`, `eu-west-1`, `us-east-1` and `us-west-2`. See current [AWS SES regions](https://docs.aws.amazon.com/general/latest/gr/rande.html#ses_region)

0 comments on commit a30eb3e

Please sign in to comment.