Skip to content

Commit

Permalink
provider: Authentication updates for Terraform AWS Provider v3.0.0 (#…
Browse files Browse the repository at this point in the history
…14077)

* Update module hashicorp/aws-sdk-go-base to v0.5.0

* provider: Authentication updates for Terraform AWS Provider v3.0.0

Reference: #5018
Reference: #6913
Reference: #7333
Reference: #9236
Reference: #9869
Reference: #9898
Reference: #9962
Reference: #9986
Reference: #10507
Reference: #11429
Reference: #12236
Reference: #12727
Reference: #12815
Reference: #13057

Changes:

```
NOTES

* provider: Credential ordering has changed from static, environment, shared credentials, EC2 metadata, default AWS Go SDK (shared configuration, web identity, ECS, EC2 Metadata) to static, environment, shared credentials, default AWS Go SDK (shared configuration, web identity, ECS, EC2 Metadata)
* provider: The `AWS_METADATA_TIMEOUT` environment variable no longer has any effect as we now depend on the default AWS Go SDK EC2 Metadata client timeout of one second with two retries

ENHANCEMENTS

* provider: Always enable shared configuration file support (no longer require `AWS_SDK_LOAD_CONFIG` environment variable)
* provider: Add `assume_role` configuration block `duration_seconds`, `policy_arns`, `tags`, and `transitive_tag_keys` arguments

BUG FIXES

* provider: Ensure configured STS endpoint is used during `AssumeRole` API calls
* provider: Prefer AWS shared configuration over EC2 metadata credentials by default
* provider: Prefer CodeBuild, ECS, EKS credentials over EC2 metadata credentials by default
```

Output from acceptance testing:

```
--- PASS: TestAccAWSProvider_Region_AwsCommercial (3.89s)
--- PASS: TestAccAWSProvider_Region_AwsGovCloudUs (3.90s)
--- PASS: TestAccAWSProvider_Region_AwsChina (3.99s)
--- PASS: TestAccAWSProvider_IgnoreTags_Keys_None (4.22s)
--- PASS: TestAccAWSProvider_IgnoreTags_KeyPrefixes_None (4.29s)
--- PASS: TestAccAWSProvider_IgnoreTags_KeyPrefixes_One (4.37s)
--- PASS: TestAccAWSProvider_IgnoreTags_KeyPrefixes_Multiple (4.38s)
--- PASS: TestAccAWSProvider_IgnoreTags_Keys_One (4.39s)
--- PASS: TestAccAWSProvider_IgnoreTags_EmptyConfigurationBlock (4.40s)
--- PASS: TestAccAWSProvider_IgnoreTags_Keys_Multiple (4.40s)
--- PASS: TestAccAWSProvider_Endpoints_Deprecated (4.42s)
--- PASS: TestAccAWSProvider_Endpoints (4.53s)
--- PASS: TestAccAWSProvider_AssumeRole_Empty (8.32s)
```

* docs/provider: Add authentication changes section to version 3 upgrade guide and remove pre-3.0 notes

Co-authored-by: Renovate Bot <bot@renovateapp.com>
  • Loading branch information
bflad and renovate-bot authored Jul 13, 2020
1 parent a6d6943 commit 2e86bbd
Show file tree
Hide file tree
Showing 19 changed files with 596 additions and 332 deletions.
57 changes: 33 additions & 24 deletions aws/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,10 +165,14 @@ type Config struct {
Region string
MaxRetries int

AssumeRoleARN string
AssumeRoleExternalID string
AssumeRoleSessionName string
AssumeRolePolicy string
AssumeRoleARN string
AssumeRoleDurationSeconds int
AssumeRoleExternalID string
AssumeRolePolicy string
AssumeRolePolicyARNs []string
AssumeRoleSessionName string
AssumeRoleTags map[string]string
AssumeRoleTransitiveTagKeys []string

AllowedAccountIds []string
ForbiddenAccountIds []string
Expand Down Expand Up @@ -365,26 +369,31 @@ func (c *Config) Client() (interface{}, error) {
}
}

log.Println("[INFO] Building AWS auth structure")
awsbaseConfig := &awsbase.Config{
AccessKey: c.AccessKey,
AssumeRoleARN: c.AssumeRoleARN,
AssumeRoleExternalID: c.AssumeRoleExternalID,
AssumeRolePolicy: c.AssumeRolePolicy,
AssumeRoleSessionName: c.AssumeRoleSessionName,
CredsFilename: c.CredsFilename,
DebugLogging: logging.IsDebugOrHigher(),
IamEndpoint: c.Endpoints["iam"],
Insecure: c.Insecure,
MaxRetries: c.MaxRetries,
Profile: c.Profile,
Region: c.Region,
SecretKey: c.SecretKey,
SkipCredsValidation: c.SkipCredsValidation,
SkipMetadataApiCheck: c.SkipMetadataApiCheck,
SkipRequestingAccountId: c.SkipRequestingAccountId,
StsEndpoint: c.Endpoints["sts"],
Token: c.Token,
AccessKey: c.AccessKey,
AssumeRoleARN: c.AssumeRoleARN,
AssumeRoleDurationSeconds: c.AssumeRoleDurationSeconds,
AssumeRoleExternalID: c.AssumeRoleExternalID,
AssumeRolePolicy: c.AssumeRolePolicy,
AssumeRolePolicyARNs: c.AssumeRolePolicyARNs,
AssumeRoleSessionName: c.AssumeRoleSessionName,
AssumeRoleTags: c.AssumeRoleTags,
AssumeRoleTransitiveTagKeys: c.AssumeRoleTransitiveTagKeys,
CallerDocumentationURL: "https://registry.terraform.io/providers/hashicorp/aws",
CallerName: "Terraform AWS Provider",
CredsFilename: c.CredsFilename,
DebugLogging: logging.IsDebugOrHigher(),
IamEndpoint: c.Endpoints["iam"],
Insecure: c.Insecure,
MaxRetries: c.MaxRetries,
Profile: c.Profile,
Region: c.Region,
SecretKey: c.SecretKey,
SkipCredsValidation: c.SkipCredsValidation,
SkipMetadataApiCheck: c.SkipMetadataApiCheck,
SkipRequestingAccountId: c.SkipRequestingAccountId,
StsEndpoint: c.Endpoints["sts"],
Token: c.Token,
UserAgentProducts: []*awsbase.UserAgentProduct{
{Name: "APN", Version: "1.0"},
{Name: "HashiCorp", Version: "1.0"},
Expand All @@ -395,7 +404,7 @@ func (c *Config) Client() (interface{}, error) {

sess, accountID, partition, err := awsbase.GetSessionWithAccountIDAndPartition(awsbaseConfig)
if err != nil {
return nil, err
return nil, fmt.Errorf("error configuring Terraform AWS Provider: %w", err)
}

if accountID == "" {
Expand Down
138 changes: 91 additions & 47 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/helper/mutexkv"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/terraform"
homedir "github.com/mitchellh/go-homedir"

"github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags"
)
Expand Down Expand Up @@ -1019,18 +1018,6 @@ func init() {
"i.e., http://s3.amazonaws.com/BUCKET/KEY. By default, the S3 client will\n" +
"use virtual hosted bucket addressing when possible\n" +
"(http://BUCKET.s3.amazonaws.com/KEY). Specific to the Amazon S3 service.",

"assume_role_role_arn": "The ARN of an IAM role to assume prior to making API calls.",

"assume_role_session_name": "The session name to use when assuming the role. If omitted," +
" no session name is passed to the AssumeRole call.",

"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_policy": "The permissions applied when assuming a role. You cannot use," +
" this policy to grant further permissions that are in excess to those of the, " +
" role that is being assumed.",
}

endpointServiceNames = []string{
Expand Down Expand Up @@ -1185,6 +1172,7 @@ func providerConfigure(d *schema.ResourceData, terraformVersion string) (interfa
Profile: d.Get("profile").(string),
Token: d.Get("token").(string),
Region: d.Get("region").(string),
CredsFilename: d.Get("shared_credentials_file").(string),
Endpoints: make(map[string]string),
MaxRetries: d.Get("max_retries").(int),
IgnoreTagsConfig: expandProviderIgnoreTags(d.Get("ignore_tags").([]interface{})),
Expand All @@ -1198,32 +1186,68 @@ func providerConfigure(d *schema.ResourceData, terraformVersion string) (interfa
terraformVersion: terraformVersion,
}

// Set CredsFilename, expanding home directory
credsPath, err := homedir.Expand(d.Get("shared_credentials_file").(string))
if err != nil {
return nil, err
}
config.CredsFilename = credsPath

assumeRoleList := d.Get("assume_role").([]interface{})
if len(assumeRoleList) == 1 {
if assumeRoleList[0] != nil {
assumeRole := assumeRoleList[0].(map[string]interface{})
config.AssumeRoleARN = assumeRole["role_arn"].(string)
config.AssumeRoleSessionName = assumeRole["session_name"].(string)
config.AssumeRoleExternalID = assumeRole["external_id"].(string)

if v := assumeRole["policy"].(string); v != "" {
config.AssumeRolePolicy = v
if l, ok := d.Get("assume_role").([]interface{}); ok && len(l) > 0 && l[0] != nil {
m := l[0].(map[string]interface{})

if v, ok := m["duration_seconds"].(int); ok && v != 0 {
config.AssumeRoleDurationSeconds = v
}

if v, ok := m["external_id"].(string); ok && v != "" {
config.AssumeRoleExternalID = v
}

if v, ok := m["policy"].(string); ok && v != "" {
config.AssumeRolePolicy = v
}

if policyARNSet, ok := m["policy_arns"].(*schema.Set); ok && policyARNSet.Len() > 0 {
for _, policyARNRaw := range policyARNSet.List() {
policyARN, ok := policyARNRaw.(string)

if !ok {
continue
}

config.AssumeRolePolicyARNs = append(config.AssumeRolePolicyARNs, policyARN)
}
}

if v, ok := m["role_arn"].(string); ok && v != "" {
config.AssumeRoleARN = v
}

if v, ok := m["session_name"].(string); ok && v != "" {
config.AssumeRoleSessionName = v
}

if tagMapRaw, ok := m["tags"].(map[string]interface{}); ok && len(tagMapRaw) > 0 {
config.AssumeRoleTags = make(map[string]string)

for k, vRaw := range tagMapRaw {
v, ok := vRaw.(string)

if !ok {
continue
}

config.AssumeRoleTags[k] = v
}
}

if transitiveTagKeySet, ok := m["transitive_tag_keys"].(*schema.Set); ok && transitiveTagKeySet.Len() > 0 {
for _, transitiveTagKeyRaw := range transitiveTagKeySet.List() {
transitiveTagKey, ok := transitiveTagKeyRaw.(string)

if !ok {
continue
}

log.Printf("[INFO] assume_role configuration set: (ARN: %q, SessionID: %q, ExternalID: %q, Policy: %q)",
config.AssumeRoleARN, config.AssumeRoleSessionName, config.AssumeRoleExternalID, config.AssumeRolePolicy)
} else {
log.Printf("[INFO] Empty assume_role block read from configuration")
config.AssumeRoleTransitiveTagKeys = append(config.AssumeRoleTransitiveTagKeys, transitiveTagKey)
}
}
} else {
log.Printf("[INFO] No assume_role block read from configuration")

log.Printf("[INFO] assume_role configuration set: (ARN: %q, SessionID: %q, ExternalID: %q)", config.AssumeRoleARN, config.AssumeRoleSessionName, config.AssumeRoleExternalID)
}

endpointsSet := d.Get("endpoints").(*schema.Set)
Expand Down Expand Up @@ -1260,28 +1284,48 @@ func assumeRoleSchema() *schema.Schema {
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"role_arn": {
"duration_seconds": {
Type: schema.TypeInt,
Optional: true,
Description: "Seconds to restrict the assume role session duration.",
},
"external_id": {
Type: schema.TypeString,
Optional: true,
Description: descriptions["assume_role_role_arn"],
Description: "Unique identifier that might be required for assuming a role in another account.",
},

"session_name": {
"policy": {
Type: schema.TypeString,
Optional: true,
Description: descriptions["assume_role_session_name"],
Description: "IAM Policy JSON describing further restricting permissions for the IAM Role being assumed.",
},

"external_id": {
"policy_arns": {
Type: schema.TypeSet,
Optional: true,
Description: "Amazon Resource Names (ARNs) of IAM Policies describing further restricting permissions for the IAM Role being assumed.",
Elem: &schema.Schema{Type: schema.TypeString},
},
"role_arn": {
Type: schema.TypeString,
Optional: true,
Description: descriptions["assume_role_external_id"],
Description: "Amazon Resource Name of an IAM Role to assume prior to making API calls.",
},

"policy": {
"session_name": {
Type: schema.TypeString,
Optional: true,
Description: descriptions["assume_role_policy"],
Description: "Identifier for the assumed role session.",
},
"tags": {
Type: schema.TypeMap,
Optional: true,
Description: "Assume role session tags.",
Elem: &schema.Schema{Type: schema.TypeString},
},
"transitive_tag_keys": {
Type: schema.TypeSet,
Optional: true,
Description: "Assume role session tag keys to pass to any subsequent sessions.",
Elem: &schema.Schema{Type: schema.TypeString},
},
},
},
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require (
github.com/bflad/tfproviderlint v0.14.0
github.com/client9/misspell v0.3.4
github.com/golangci/golangci-lint v1.26.0
github.com/hashicorp/aws-sdk-go-base v0.4.0
github.com/hashicorp/aws-sdk-go-base v0.5.0
github.com/hashicorp/go-cleanhttp v0.5.1
github.com/hashicorp/go-multierror v1.1.0
github.com/hashicorp/go-version v1.2.1
Expand Down
5 changes: 3 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aws/aws-sdk-go v1.15.78/go.mod h1:E3/ieXAlvM0XWO57iftYVDLLvQ824smPP3ATZkfNZeM=
github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
github.com/aws/aws-sdk-go v1.31.9/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/aws/aws-sdk-go v1.32.12 h1:l/djCeLI4ggBFWLlYUGTqkHraoLnVMubNlLXPdEtoYc=
github.com/aws/aws-sdk-go v1.32.12/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
Expand Down Expand Up @@ -217,8 +218,8 @@ github.com/gostaticanalysis/analysisutil v0.0.0-20190318220348-4088753ea4d3/go.m
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
github.com/hashicorp/aws-sdk-go-base v0.4.0 h1:zH9hNUdsS+2G0zJaU85ul8D59BGnZBaKM+KMNPAHGwk=
github.com/hashicorp/aws-sdk-go-base v0.4.0/go.mod h1:eRhlz3c4nhqxFZJAahJEFL7gh6Jyj5rQmQc7F9eHFyQ=
github.com/hashicorp/aws-sdk-go-base v0.5.0 h1:fk7ID0v3PWL/KNL8FvkBPu8Sm93EPUCCmtZCiTXLySE=
github.com/hashicorp/aws-sdk-go-base v0.5.0/go.mod h1:2fRjWDv3jJBeN6mVWFHV6hFTNeFBx2gpDLQaZNxUVAY=
github.com/hashicorp/errwrap v1.0.0 h1:hLrqtEDnRye3+sgx6z4qVLNuviH3MR5aQ0ykNJa/UYA=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-cleanhttp v0.5.0 h1:wvCrVc9TjDls6+YGAF2hAifE1E5U1+b4tH6KdvN3Gig=
Expand Down
7 changes: 7 additions & 0 deletions vendor/github.com/hashicorp/aws-sdk-go-base/.golangci.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

20 changes: 0 additions & 20 deletions vendor/github.com/hashicorp/aws-sdk-go-base/.travis.yml

This file was deleted.

22 changes: 22 additions & 0 deletions vendor/github.com/hashicorp/aws-sdk-go-base/CHANGELOG.md

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 2e86bbd

Please sign in to comment.