Skip to content

Commit

Permalink
Merge pull request #146 from hashicorp/auth-logging
Browse files Browse the repository at this point in the history
Adds logging for authentication flow
  • Loading branch information
gdavison authored Feb 25, 2022
2 parents 54d62fa + ab97718 commit 22cb4e5
Show file tree
Hide file tree
Showing 4 changed files with 154 additions and 23 deletions.
6 changes: 4 additions & 2 deletions aws_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@ func GetAwsConfig(ctx context.Context, c *Config) (aws.Config, error) {
}
}

credentialsProvider, source, err := getCredentialsProvider(ctx, c)
credentialsProvider, initialSource, err := getCredentialsProvider(ctx, c)
if err != nil {
return aws.Config{}, err
}
creds, _ := credentialsProvider.Retrieve(ctx)
log.Printf("[INFO] Retrieved credentials from %q", creds.Source)

var retryer aws.Retryer
retryer = retry.NewStandard()
Expand All @@ -65,7 +67,7 @@ func GetAwsConfig(ctx context.Context, c *Config) (aws.Config, error) {
return retryer
}),
)
if source == ec2rolecreds.ProviderName {
if initialSource == ec2rolecreds.ProviderName {
loadOptions = append(
loadOptions,
config.WithEC2IMDSRegion(),
Expand Down
42 changes: 42 additions & 0 deletions aws_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -845,6 +845,48 @@ aws_secret_access_key = DefaultSharedCredentialsSecretKey
[some-profile]
aws_access_key_id = DefaultSharedCredentialsAccessKey
aws_secret_access_key = DefaultSharedCredentialsSecretKey
`,
},
{
Config: &Config{},
Description: "AWS_ACCESS_KEY_ID overrides AWS_PROFILE",
EnvironmentVariables: map[string]string{
"AWS_ACCESS_KEY_ID": servicemocks.MockEnvAccessKey,
"AWS_SECRET_ACCESS_KEY": servicemocks.MockEnvSecretKey,
"AWS_PROFILE": "SharedCredentialsProfile",
},
SharedCredentialsFile: `
[default]
aws_access_key_id = DefaultSharedCredentialsAccessKey
aws_secret_access_key = DefaultSharedCredentialsSecretKey
[SharedCredentialsProfile]
aws_access_key_id = ProfileSharedCredentialsAccessKey
aws_secret_access_key = ProfileSharedCredentialsSecretKey
`,
MockStsEndpoints: []*servicemocks.MockEndpoint{
servicemocks.MockStsGetCallerIdentityValidEndpoint,
},
ExpectedCredentialsValue: mockdata.MockEnvCredentials,
},
{
Config: &Config{
Region: "us-east-1",
},
Description: "AWS_ACCESS_KEY_ID does not override invalid profile name from envvar",
EnvironmentVariables: map[string]string{
"AWS_ACCESS_KEY_ID": servicemocks.MockEnvAccessKey,
"AWS_SECRET_ACCESS_KEY": servicemocks.MockEnvSecretKey,
"AWS_PROFILE": "no-such-profile",
},
ExpectedError: func(err error) bool {
var e config.SharedConfigProfileNotExistError
return errors.As(err, &e)
},
SharedCredentialsFile: `
[some-profile]
aws_access_key_id = DefaultSharedCredentialsAccessKey
aws_secret_access_key = DefaultSharedCredentialsSecretKey
`,
},
}
Expand Down
87 changes: 66 additions & 21 deletions credentials.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import (
"context"
"fmt"
"log"
"os"
"strings"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
Expand Down Expand Up @@ -33,45 +35,83 @@ func getCredentialsProvider(ctx context.Context, c *Config) (aws.CredentialsProv
return nil, "", err
}

if c.Profile != "" && os.Getenv("AWS_ACCESS_KEY_ID") != "" && os.Getenv("AWS_SECRET_ACCESS_KEY") != "" {
log.Printf(`[WARN] A Profile was specified along with the environment variables "AWS_ACCESS_KEY_ID" and "AWS_SECRET_ACCESS_KEY". ` +
"The Profile is now used instead of the environment variable credentials. This may lead to unexpected behavior.")
}

// The default AWS SDK authentication flow silently ignores invalid Profiles. Pre-validate that the Profile exists
// https://github.com/aws/aws-sdk-go-v2/issues/1591
profile := c.Profile
if profile == "" {
profile = envConfig.SharedConfigProfile
}

sharedCredentialsFiles, err := c.ResolveSharedCredentialsFiles()
if err != nil {
return nil, "", err
}
if len(sharedCredentialsFiles) == 0 {
sharedCredentialsFiles = []string{envConfig.SharedCredentialsFile}
}
if profile != "" {
sharedCredentialsFiles, err := c.ResolveSharedCredentialsFiles()
if err != nil {
return nil, "", err
}
if len(sharedCredentialsFiles) != 0 {
f := make([]string, len(sharedCredentialsFiles))
for i, v := range sharedCredentialsFiles {
f[i] = fmt.Sprintf(`"%s"`, v)
}
log.Printf("[DEBUG] Using shared credentials files from configuration: [%s]", strings.Join(f, ", "))
} else {
if envConfig.SharedCredentialsFile != "" {
log.Printf("[DEBUG] Using shared credentials file environment variables: %q", envConfig.SharedCredentialsFile)
sharedCredentialsFiles = []string{envConfig.SharedCredentialsFile}
}
}

sharedConfigFiles, err := c.ResolveSharedConfigFiles()
if err != nil {
return nil, "", err
}
if len(sharedConfigFiles) == 0 {
sharedConfigFiles = []string{envConfig.SharedConfigFile}
}
sharedConfigFiles, err := c.ResolveSharedConfigFiles()
if err != nil {
return nil, "", err
}
if len(sharedConfigFiles) != 0 {
f := make([]string, len(sharedConfigFiles))
for i, v := range sharedConfigFiles {
f[i] = fmt.Sprintf(`"%s"`, v)
}
log.Printf("[DEBUG] Using shared configuration files from configuration: %v", strings.Join(f, ", "))
} else {
if envConfig.SharedConfigFile != "" {
log.Printf("[DEBUG] Using shared configuration file environment variables: %s", envConfig.SharedConfigFile)
sharedConfigFiles = []string{envConfig.SharedConfigFile}
}
}

// The default AWS SDK authentication flow silently ignores invalid Profiles. Pre-validate that the Profile exists
// https://github.com/aws/aws-sdk-go-v2/issues/1591
if profile != "" {
_, err := config.LoadSharedConfigProfile(ctx, profile, func(opts *config.LoadSharedConfigOptions) {
_, err = config.LoadSharedConfigProfile(ctx, profile, func(opts *config.LoadSharedConfigOptions) {
opts.CredentialsFiles = sharedCredentialsFiles
opts.ConfigFiles = sharedConfigFiles
})
if err != nil {
return nil, "", err
}
}
// We need to validate both the configured and envvar named profiles for validity,
// but to use proper precedence, we only set the configured named profile
if c.Profile != "" {
log.Printf("[DEBUG] Using profile from configuration: %q", c.Profile)
loadOptions = append(
loadOptions,
config.WithSharedConfigProfile(c.Profile),
)

}

if c.AccessKey != "" || c.SecretKey != "" || c.Token != "" {
params := make([]string, 0, 3) //nolint:gomnd
if c.AccessKey != "" {
params = append(params, "access key")
}
if c.SecretKey != "" {
params = append(params, "secret key")
}
if c.Token != "" {
params = append(params, "token")
}
log.Printf("[DEBUG] Using %s from configuration", strings.Join(params, ", "))
loadOptions = append(
loadOptions,
config.WithCredentialsProvider(
Expand All @@ -91,13 +131,19 @@ func getCredentialsProvider(ctx context.Context, c *Config) (aws.CredentialsProv

creds, err := cfg.Credentials.Retrieve(ctx)
if err != nil {
if c.Profile != "" && os.Getenv("AWS_ACCESS_KEY_ID") != "" && os.Getenv("AWS_SECRET_ACCESS_KEY") != "" {
err = fmt.Errorf(`A Profile was specified along with the environment variables "AWS_ACCESS_KEY_ID" and "AWS_SECRET_ACCESS_KEY". The Profile is now used instead of the environment variable credentials.
Error: %w`, err)
}
return nil, "", c.NewNoValidCredentialSourcesError(err)
}

if c.AssumeRole == nil || c.AssumeRole.RoleARN == "" {
return cfg.Credentials, creds.Source, nil
}

log.Printf("[INFO] Retrieved initial credentials from %q", creds.Source)
provider, err := assumeRoleCredentialsProvider(ctx, cfg, c)

return provider, creds.Source, err
Expand All @@ -106,8 +152,7 @@ func getCredentialsProvider(ctx context.Context, c *Config) (aws.CredentialsProv
func assumeRoleCredentialsProvider(ctx context.Context, awsConfig aws.Config, c *Config) (aws.CredentialsProvider, error) {
ar := c.AssumeRole
// When assuming a role, we need to first authenticate the base credentials above, then assume the desired role
log.Printf("[INFO] Attempting to AssumeRole %s (SessionName: %q, ExternalId: %q)",
ar.RoleARN, ar.SessionName, ar.ExternalID)
log.Printf("[INFO] Assuming IAM Role %q (SessionName: %q, ExternalId: %q)", ar.RoleARN, ar.SessionName, ar.ExternalID)

client := stsClient(awsConfig, c)

Expand Down
42 changes: 42 additions & 0 deletions v2/awsv1shim/session_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -890,6 +890,48 @@ aws_secret_access_key = DefaultSharedCredentialsSecretKey
[some-profile]
aws_access_key_id = DefaultSharedCredentialsAccessKey
aws_secret_access_key = DefaultSharedCredentialsSecretKey
`,
},
{
Config: &awsbase.Config{},
Description: "AWS_ACCESS_KEY_ID overrides AWS_PROFILE",
EnvironmentVariables: map[string]string{
"AWS_ACCESS_KEY_ID": servicemocks.MockEnvAccessKey,
"AWS_SECRET_ACCESS_KEY": servicemocks.MockEnvSecretKey,
"AWS_PROFILE": "SharedCredentialsProfile",
},
SharedCredentialsFile: `
[default]
aws_access_key_id = DefaultSharedCredentialsAccessKey
aws_secret_access_key = DefaultSharedCredentialsSecretKey
[SharedCredentialsProfile]
aws_access_key_id = ProfileSharedCredentialsAccessKey
aws_secret_access_key = ProfileSharedCredentialsSecretKey
`,
MockStsEndpoints: []*servicemocks.MockEndpoint{
servicemocks.MockStsGetCallerIdentityValidEndpoint,
},
ExpectedCredentialsValue: mockdata.MockEnvCredentials,
},
{
Config: &awsbase.Config{
Region: "us-east-1",
},
Description: "AWS_ACCESS_KEY_ID does not override invalid profile name from envvar",
EnvironmentVariables: map[string]string{
"AWS_ACCESS_KEY_ID": servicemocks.MockEnvAccessKey,
"AWS_SECRET_ACCESS_KEY": servicemocks.MockEnvSecretKey,
"AWS_PROFILE": "no-such-profile",
},
ExpectedError: func(err error) bool {
var e configv2.SharedConfigProfileNotExistError
return errors.As(err, &e)
},
SharedCredentialsFile: `
[some-profile]
aws_access_key_id = DefaultSharedCredentialsAccessKey
aws_secret_access_key = DefaultSharedCredentialsSecretKey
`,
},
}
Expand Down

0 comments on commit 22cb4e5

Please sign in to comment.