From 25d7c3bdedb3e8d5f0e248c875650492445e2ecf Mon Sep 17 00:00:00 2001 From: Nick Upton Date: Mon, 24 Feb 2020 11:15:52 -0800 Subject: [PATCH 1/2] Fix order for credentials chain, building upon Dirk Avery's work. * Credential chain validation will now try, in order: - static variables - environment variables - shared credentials file - AWS SDK session-derived credentials (including shared config file) - ECS and EC2 metadata agents * Previous behavior ignored the config file when running in ECS/EC2, because those credentials would prematurely satisfy the contract. This prevented the use of config file options, in particular credentials_source = EcsContainer or EC2InstanceMetadata --- awsauth.go | 62 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/awsauth.go b/awsauth.go index 53116203..199b12b7 100644 --- a/awsauth.go +++ b/awsauth.go @@ -215,24 +215,11 @@ func GetCredentialsFromSession(c *Config) (*awsCredentials.Credentials, error) { return creds, nil } -// GetCredentials gets credentials from the environment, shared credentials, -// or the session (which may include a credential process). GetCredentials also -// validates the credentials and the ability to assume a role or will return an -// error if unsuccessful. -func GetCredentials(c *Config) (*awsCredentials.Credentials, error) { - // build a chain provider, lazy-evaluated by aws-sdk - providers := []awsCredentials.Provider{ - &awsCredentials.StaticProvider{Value: awsCredentials.Value{ - AccessKeyID: c.AccessKey, - SecretAccessKey: c.SecretKey, - SessionToken: c.Token, - }}, - &awsCredentials.EnvProvider{}, - &awsCredentials.SharedCredentialsProvider{ - Filename: c.CredsFilename, - Profile: c.Profile, - }, - } +// GetCredentialsFromMetadata returns credentials derived from and ECS or ECS +// metadata endpoint. +func GetCredentialsFromMetadata(c *Config) (*awsCredentials.Credentials, error) { + log.Printf("[INFO] Attempting to use metadata-derived credentials") + providers := []awsCredentials.Provider{} // Build isolated HTTP client to avoid issues with globally-shared settings client := cleanhttp.DefaultClient() @@ -293,6 +280,40 @@ func GetCredentials(c *Config) (*awsCredentials.Credentials, error) { } } + // Validate the credentials before returning them + creds := awsCredentials.NewChainCredentials(providers) + cp, err := creds.Get() + if err != nil { + if IsAWSErr(err, "NoCredentialProviders", "") { + return nil, ErrNoValidCredentialSources + } + return nil, fmt.Errorf("Error deriving credentials from metadata: %s", err) + } + + log.Printf("[INFO] Successfully derived credentials from metadata") + log.Printf("[INFO] AWS Auth provider used: %q", cp.ProviderName) + return creds, nil +} + +// GetCredentials gets credentials from the environment, shared credentials, +// the session (which may include a credential process), or ECS/EC2 metadata endpoints. +// GetCredentials also validates the credentials and the ability to assume a role +// or will return an error if unsuccessful. +func GetCredentials(c *Config) (*awsCredentials.Credentials, error) { + // build a chain provider, lazy-evaluated by aws-sdk + providers := []awsCredentials.Provider{ + &awsCredentials.StaticProvider{Value: awsCredentials.Value{ + AccessKeyID: c.AccessKey, + SecretAccessKey: c.SecretKey, + SessionToken: c.Token, + }}, + &awsCredentials.EnvProvider{}, + &awsCredentials.SharedCredentialsProvider{ + Filename: c.CredsFilename, + Profile: c.Profile, + }, + } + // Validate the credentials before returning them creds := awsCredentials.NewChainCredentials(providers) cp, err := creds.Get() @@ -300,7 +321,10 @@ func GetCredentials(c *Config) (*awsCredentials.Credentials, error) { if IsAWSErr(err, "NoCredentialProviders", "") { creds, err = GetCredentialsFromSession(c) if err != nil { - return nil, err + creds, err = GetCredentialsFromMetadata(c) + if err != nil { + return nil, err + } } } else { return nil, fmt.Errorf("Error loading credentials for AWS Provider: %s", err) From 8f129f80f0bcbb0c9e01693dd1129a6d0211b5d4 Mon Sep 17 00:00:00 2001 From: Nick Upton Date: Mon, 24 Feb 2020 11:34:34 -0800 Subject: [PATCH 2/2] Add missing profile https://github.com/hashicorp/aws-sdk-go-base/issues/19 --- session.go | 1 + 1 file changed, 1 insertion(+) diff --git a/session.go b/session.go index 92671e13..4fc92d27 100644 --- a/session.go +++ b/session.go @@ -25,6 +25,7 @@ func GetSessionOptions(c *Config) (*session.Options, error) { MaxRetries: aws.Int(0), Region: aws.String(c.Region), }, + Profile: c.Profile, } // get and validate credentials