From b16f2ec64b36753e6d65d85bbb5e732080f5ccd4 Mon Sep 17 00:00:00 2001 From: Matthew Hooker Date: Thu, 15 Mar 2018 09:49:34 -0700 Subject: [PATCH] builder/amazon: Use sdk default cred providers I think we were overcomplicating things. The SDK provides the correct credential chain by default, so let's use that. This patch does a quick check for static credentials and uses those if found, then defaults to the default credential provider chain. This patch also removes the metadata timeout argument. Current versions of the SDK have short timeouts by default, so I don't believe this is needed. --- builder/amazon/common/access_config.go | 68 +++------------------ website/source/docs/builders/amazon.html.md | 8 --- 2 files changed, 7 insertions(+), 69 deletions(-) diff --git a/builder/amazon/common/access_config.go b/builder/amazon/common/access_config.go index 6228f35b2..862a64d21 100644 --- a/builder/amazon/common/access_config.go +++ b/builder/amazon/common/access_config.go @@ -3,14 +3,12 @@ package common import ( "fmt" "log" - "os" "strings" "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/aws/credentials" - "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds" "github.com/aws/aws-sdk-go/aws/ec2metadata" "github.com/aws/aws-sdk-go/aws/session" "github.com/hashicorp/go-cleanhttp" @@ -38,66 +36,13 @@ func (c *AccessConfig) Session() (*session.Session, error) { return c.session, nil } - // build a chain provider, lazy-evaluated by aws-sdk - providers := []credentials.Provider{ - &credentials.StaticProvider{Value: credentials.Value{ - AccessKeyID: c.AccessKey, - SecretAccessKey: c.SecretKey, - SessionToken: c.Token, - }}, - &credentials.EnvProvider{}, - &credentials.SharedCredentialsProvider{ - Filename: "", - Profile: c.ProfileName, - }, - } - - // Build isolated HTTP client to avoid issues with globally-shared settings - client := cleanhttp.DefaultClient() - - // Keep the default timeout (100ms) low as we don't want to wait in non-EC2 environments - client.Timeout = 100 * time.Millisecond - - const userTimeoutEnvVar = "AWS_METADATA_TIMEOUT" - userTimeout := os.Getenv(userTimeoutEnvVar) - if userTimeout != "" { - newTimeout, err := time.ParseDuration(userTimeout) - if err == nil { - if newTimeout.Nanoseconds() > 0 { - client.Timeout = newTimeout - } else { - log.Printf("[WARN] Non-positive value of %s (%s) is meaningless, ignoring", userTimeoutEnvVar, newTimeout.String()) - } - } else { - log.Printf("[WARN] Error converting %s to time.Duration: %s", userTimeoutEnvVar, err) - } - } + config := aws.NewConfig().WithCredentialsChainVerboseErrors(true) - log.Printf("[INFO] Setting AWS metadata API timeout to %s", client.Timeout.String()) - cfg := &aws.Config{ - HTTPClient: client, - } - if !c.SkipMetadataApiCheck { - // Real AWS should reply to a simple metadata request. - // We check it actually does to ensure something else didn't just - // happen to be listening on the same IP:Port - metadataClient := ec2metadata.New(session.New(cfg)) - if metadataClient.Available() { - providers = append(providers, &ec2rolecreds.EC2RoleProvider{ - Client: metadataClient, - }) - log.Print("[INFO] AWS EC2 instance detected via default metadata" + - " API endpoint, EC2RoleProvider added to the auth chain") - } else { - log.Printf("[INFO] Ignoring AWS metadata API endpoint " + - "as it doesn't return any instance-id") - } + staticCreds := credentials.NewStaticCredentials(c.AccessKey, c.SecretKey, c.Token) + if _, err := staticCreds.Get(); err != credentials.ErrStaticCredentialsEmpty { + config.WithCredentials(staticCreds) } - creds := credentials.NewChainCredentials(providers) - - config := aws.NewConfig().WithCredentialsChainVerboseErrors(true) - if c.RawRegion != "" { config = config.WithRegion(c.RawRegion) } else if region := c.metadataRegion(); region != "" { @@ -123,8 +68,6 @@ func (c *AccessConfig) Session() (*session.Session, error) { } } - config = config.WithCredentials(creds) - if sess, err := session.NewSessionWithOptions(opts); err != nil { return nil, err } else if *sess.Config.Region == "" { @@ -185,6 +128,9 @@ func (c *AccessConfig) metadataRegion() string { func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error { var errs []error + if c.SkipMetadataApiCheck { + log.Println("(WARN) skip_metadata_api_check ignored.") + } // Either both access and secret key must be set or neither of them should // be. if (len(c.AccessKey) > 0) != (len(c.SecretKey) > 0) { diff --git a/website/source/docs/builders/amazon.html.md b/website/source/docs/builders/amazon.html.md index 21dad780a..8af3f101f 100644 --- a/website/source/docs/builders/amazon.html.md +++ b/website/source/docs/builders/amazon.html.md @@ -123,14 +123,6 @@ This is a preferred approach over any other when running in EC2 as you can avoid hard coding credentials. Instead these are leased on-the-fly by Packer, which reduces the chance of leakage. -The default deadline for the EC2 metadata API endpoint is 100 milliseconds, -which can be overidden by setting the `AWS_METADATA_TIMEOUT` environment -variable. The variable expects a positive golang Time.Duration string, which is -a sequence of decimal numbers and a unit suffix; valid suffixes are `ns` -(nanoseconds), `us` (microseconds), `ms` (milliseconds), `s` (seconds), `m` -(minutes), and `h` (hours). Examples of valid inputs: `100ms`, `250ms`, `1s`, -`2.5s`, `2.5m`, `1m30s`. - The following policy document provides the minimal set permissions necessary for Packer to work: