From 5bd67bb3b7f9b575f8ff24022f5c01d9a382460c Mon Sep 17 00:00:00 2001 From: Don Kuntz Date: Mon, 30 Apr 2018 16:33:08 -0500 Subject: [PATCH 1/3] Fix AWS session configuration for differences between using a profile and using a role + profile Before, using `unicreds --profile foo` would error out, while `AWS_PROFILE=foo unicreds` would not. This was a mistake, and the correct action is they should both work correctly. This commit will make the --profile flag act the same as using the AWS_PROFILE / AWS_DEFAULT_PROFILE environment variables, and also ensure unicreds continues to work when using role assumption. --- aws_config.go | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/aws_config.go b/aws_config.go index 8d70161..08620a5 100644 --- a/aws_config.go +++ b/aws_config.go @@ -37,27 +37,35 @@ func SetAwsConfig(region, profile *string, role *string) (err error) { func setAwsConfig(region, profile *string, role *string) { log.WithFields(log.Fields{"region": aws.StringValue(region), "profile": aws.StringValue(profile)}).Debug("Configure AWS") - config := aws.Config{Region: region} - // if a profile is supplied then just use the shared credentials provider - // as per docs this will look in $HOME/.aws/credentials if the filename is "" - if aws.StringValue(profile) != "" { - config.Credentials = credentials.NewSharedCredentials("", *profile) - } + sess := getAwsSession(region, profile, role) + + SetDynamoDBSession(sess) + SetKMSSession(sess) +} + +func getAwsSession(region, profile, role *string) *session.Session { + config := aws.Config{Region: region} - // Are we assuming a role? + // If a role is supplied, get credentials from STS Session if aws.StringValue(role) != "" { - // Must request credentials from STS service and replace before passing on - sts_sess := session.Must(session.NewSession(&config)) - log.WithFields(log.Fields{"role": aws.StringValue(role)}).Debug("AssumeRole") - config.Credentials = stscreds.NewCredentials(sts_sess, *role) + // If the role is being assumed through a non-default profile it must be added to the config. + // When an empty string is provided, it uses the default credentials file. + if aws.StringValue(profile) != "" { + config.Credentials = credentials.NewSharedCredentials("", *profile) + } + + sts_session := session.Must(session.NewSession(&config)) + log.WithFields(log.Fields{"role": aws.StringValue(role), "profile": aws.StringValue(profile)}).Debug("AssumeRole") + config.Credentials = stscreds.NewCredentials(sts_session, *role) + + return session.Must(session.NewSession(&config)) } - sess := session.Must(session.NewSessionWithOptions(session.Options{ + // If no role is supplied, use the shared AWS config + return session.Must(session.NewSessionWithOptions(session.Options{ Config: config, SharedConfigState: session.SharedConfigEnable, + Profile: *profile, })) - - SetDynamoDBSession(sess) - SetKMSSession(sess) } From 46e603f60017784b2a940b2222101cd92f3ee452 Mon Sep 17 00:00:00 2001 From: Don Kuntz Date: Mon, 30 Apr 2018 16:52:42 -0500 Subject: [PATCH 2/3] Use shared config session for assuming role Instead of creating a new session just to assume a different role, use the same default session, that uses the shared config files, to assume roles. --- aws_config.go | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/aws_config.go b/aws_config.go index 08620a5..479db92 100644 --- a/aws_config.go +++ b/aws_config.go @@ -5,7 +5,6 @@ import ( "github.com/apex/log" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/credentials" "github.com/aws/aws-sdk-go/aws/credentials/stscreds" "github.com/aws/aws-sdk-go/aws/session" ) @@ -47,25 +46,21 @@ func setAwsConfig(region, profile *string, role *string) { func getAwsSession(region, profile, role *string) *session.Session { config := aws.Config{Region: region} - // If a role is supplied, get credentials from STS Session - if aws.StringValue(role) != "" { - // If the role is being assumed through a non-default profile it must be added to the config. - // When an empty string is provided, it uses the default credentials file. - if aws.StringValue(profile) != "" { - config.Credentials = credentials.NewSharedCredentials("", *profile) - } + // If no role is supplied, use the shared AWS config + sess := session.Must(session.NewSessionWithOptions(session.Options{ + Config: config, + SharedConfigState: session.SharedConfigEnable, + Profile: *profile, + })) - sts_session := session.Must(session.NewSession(&config)) + // If a role is supplied, return a new session using STS-generated credentials + if aws.StringValue(role) != "" { log.WithFields(log.Fields{"role": aws.StringValue(role), "profile": aws.StringValue(profile)}).Debug("AssumeRole") - config.Credentials = stscreds.NewCredentials(sts_session, *role) + config.Credentials = stscreds.NewCredentials(sess, *role) return session.Must(session.NewSession(&config)) } - // If no role is supplied, use the shared AWS config - return session.Must(session.NewSessionWithOptions(session.Options{ - Config: config, - SharedConfigState: session.SharedConfigEnable, - Profile: *profile, - })) + // If no role is assumed, return initial session + return sess } From c2add370e99bc883c01a671b5f6ab499d91b0493 Mon Sep 17 00:00:00 2001 From: Don Kuntz Date: Tue, 1 May 2018 10:14:43 -0500 Subject: [PATCH 3/3] Coerce profile string pointer to string using Amazon's helper When using the raw dereferenced pointer when attempting to get an AWS session, it is possible that profile is a nil pointer, in which case the application panics when trying to dereference it. Using AWS' helper methods instead ensures an empty value is used instead. --- aws_config.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aws_config.go b/aws_config.go index 479db92..230ff70 100644 --- a/aws_config.go +++ b/aws_config.go @@ -34,7 +34,7 @@ func SetAwsConfig(region, profile *string, role *string) (err error) { return nil } -func setAwsConfig(region, profile *string, role *string) { +func setAwsConfig(region, profile, role *string) { log.WithFields(log.Fields{"region": aws.StringValue(region), "profile": aws.StringValue(profile)}).Debug("Configure AWS") sess := getAwsSession(region, profile, role) @@ -50,7 +50,7 @@ func getAwsSession(region, profile, role *string) *session.Session { sess := session.Must(session.NewSessionWithOptions(session.Options{ Config: config, SharedConfigState: session.SharedConfigEnable, - Profile: *profile, + Profile: aws.StringValue(profile), })) // If a role is supplied, return a new session using STS-generated credentials