Skip to content

Commit

Permalink
AWS Support Assume Role with MFA
Browse files Browse the repository at this point in the history
This adds initial support for using MFA when assuming a role by adding
`mfa_serial` and `token_code` to the `assumeRole` block in an AWS
provider.
  • Loading branch information
rickard-von-essen-iz committed Oct 13, 2016
1 parent 4211f45 commit 59e8dca
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 3 deletions.
9 changes: 7 additions & 2 deletions builtin/providers/aws/auth_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ func GetCredentials(c *Config) (*awsCredentials.Credentials, error) {

// Otherwise we need to construct and STS client with the main credentials, and verify
// that we can assume the defined role.
log.Printf("[INFO] Attempting to AssumeRole %s (SessionName: %q, ExternalId: %q)",
c.AssumeRoleARN, c.AssumeRoleSessionName, c.AssumeRoleExternalID)
log.Printf("[INFO] Attempting to AssumeRole %s (SessionName: %q, ExternalId: %q, MFA Serial: %q)",
c.AssumeRoleARN, c.AssumeRoleSessionName, c.AssumeRoleExternalID, c.AssumeRoleMFASerial)

creds := awsCredentials.NewChainCredentials(providers)
cp, err := creds.Get()
Expand Down Expand Up @@ -182,11 +182,16 @@ func GetCredentials(c *Config) (*awsCredentials.Credentials, error) {
if c.AssumeRoleExternalID != "" {
assumeRoleProvider.ExternalID = aws.String(c.AssumeRoleExternalID)
}
if c.AssumeRoleMFASerial != "" {
assumeRoleProvider.SerialNumber = aws.String(c.AssumeRoleMFASerial)
assumeRoleProvider.TokenCode = aws.String(c.AssumeRoleTokenCode)
}

providers = []awsCredentials.Provider{assumeRoleProvider}

assumeRoleCreds := awsCredentials.NewChainCredentials(providers)
_, err = assumeRoleCreds.Get()

if err != nil {
if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoCredentialProviders" {
return nil, fmt.Errorf("The role %q cannot be assumed.\n\n"+
Expand Down
2 changes: 2 additions & 0 deletions builtin/providers/aws/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ type Config struct {
AssumeRoleARN string
AssumeRoleExternalID string
AssumeRoleSessionName string
AssumeRoleMFASerial string
AssumeRoleTokenCode string

AllowedAccountIds []interface{}
ForbiddenAccountIds []interface{}
Expand Down
18 changes: 18 additions & 0 deletions builtin/providers/aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,9 @@ func init() {

"assume_role_external_id": "The external ID to use when assuming the role. If omitted," +
" no external ID is passed to the AssumeRole call.",

"assume_role_mfa_serial": "The serial of a MFA device.",
"assume_role_token_code": "The MFA OTP code.",
}
}

Expand Down Expand Up @@ -442,6 +445,8 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
config.AssumeRoleARN = assumeRole["role_arn"].(string)
config.AssumeRoleSessionName = assumeRole["session_name"].(string)
config.AssumeRoleExternalID = assumeRole["external_id"].(string)
config.AssumeRoleMFASerial = assumeRole["mfa_serial"].(string)
config.AssumeRoleTokenCode = assumeRole["token_code"].(string)
log.Printf("[INFO] assume_role configuration set: (ARN: %q, SessionID: %q, ExternalID: %q)",
config.AssumeRoleARN, config.AssumeRoleSessionName, config.AssumeRoleExternalID)
} else {
Expand Down Expand Up @@ -496,6 +501,17 @@ func assumeRoleSchema() *schema.Schema {
Optional: true,
Description: descriptions["assume_role_external_id"],
},

"mfa_serial": {
Type: schema.TypeString,
Optional: true,
Description: descriptions["assume_role_mfa_serial"],
},
"token_code": {
Type: schema.TypeString,
Optional: true,
Description: descriptions["assume_role_token_code"],
},
},
},
Set: assumeRoleToHash,
Expand All @@ -508,6 +524,8 @@ func assumeRoleToHash(v interface{}) int {
buf.WriteString(fmt.Sprintf("%s-", m["role_arn"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["session_name"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["external_id"].(string)))
buf.WriteString(fmt.Sprintf("%s-", m["mfa_serial"].(string)))
buf.WriteString(fmt.Sprintf("%d-", m["token_code"].(string)))
return hashcode.String(buf.String())
}

Expand Down
10 changes: 9 additions & 1 deletion website/source/docs/providers/aws/index.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ provider "aws" {
role_arn = "arn:aws:iam::ACCOUNT_ID:role/ROLE_NAME"
session_name = "SESSION_NAME"
external_id = "EXTERNAL_ID"
mfa_serial = "arn:aws:iam::ACCOUNT_ID:mfa/USERNAME"
token_code = "${var.token_code}"
}
}
```
Expand Down Expand Up @@ -215,7 +217,13 @@ The nested `assume_role` block supports the following:
AssumeRole call.

* `external_id` - (Optional) The external ID to use when making the
AssumeRole call.
AssumeRole call.

* `mfa_serial` - (Optional) The MFA serial to use when making the
AssumeRole call.

* `token_code` - (Optional) The MFA OTP code to use when making the
AssumeRole call. Required if `mfa_serial` is given.

Nested `endpoints` block supports the following:

Expand Down

0 comments on commit 59e8dca

Please sign in to comment.