From 14f6f90621145b9823ef041741c4ea5c66a33fcc Mon Sep 17 00:00:00 2001 From: John Engelman Date: Fri, 6 May 2016 11:52:18 -0500 Subject: [PATCH] Support standard AWS config in the S3 remote backend. (#5270) --- state/remote/s3.go | 38 +++++++++------------ website/source/docs/state/remote/s3.html.md | 3 ++ 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/state/remote/s3.go b/state/remote/s3.go index af322cb6f..230df5fce 100644 --- a/state/remote/s3.go +++ b/state/remote/s3.go @@ -10,12 +10,11 @@ import ( "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/aws/aws-sdk-go/service/s3" "github.com/hashicorp/go-cleanhttp" + "github.com/hashicorp/go-multierror" + terraformAws "github.com/hashicorp/terraform/builtin/providers/aws" ) func s3Factory(conf map[string]string) (Client, error) { @@ -60,29 +59,24 @@ func s3Factory(conf map[string]string) (Client, error) { } kmsKeyID := conf["kms_key_id"] - accessKeyId := conf["access_key"] - secretAccessKey := conf["secret_key"] - - credentialsProvider := credentials.NewChainCredentials([]credentials.Provider{ - &credentials.StaticProvider{Value: credentials.Value{ - AccessKeyID: accessKeyId, - SecretAccessKey: secretAccessKey, - SessionToken: "", - }}, - &credentials.EnvProvider{}, - &credentials.SharedCredentialsProvider{Filename: "", Profile: ""}, - &ec2rolecreds.EC2RoleProvider{Client: ec2metadata.New(session.New())}, - }) - - // Make sure we got some sort of working credentials. - _, err := credentialsProvider.Get() + var errs []error + creds := terraformAws.GetCredentials(conf["access_key"], conf["secret_key"], conf["token"], conf["profile"], conf["shared_credentials_file"]) + // Call Get to check for credential provider. If nothing found, we'll get an + // error, and we can present it nicely to the user + _, err := creds.Get() if err != nil { - return nil, fmt.Errorf("Unable to determine AWS credentials. Set the AWS_ACCESS_KEY_ID and "+ - "AWS_SECRET_ACCESS_KEY environment variables.\n(error was: %s)", err) + if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoCredentialProviders" { + errs = append(errs, fmt.Errorf(`No valid credential sources found for AWS S3 remote. +Please see https://www.terraform.io/docs/state/remote/s3.html for more information on +providing credentials for the AWS S3 remote`)) + } else { + errs = append(errs, fmt.Errorf("Error loading credentials for AWS S3 remote: %s", err)) + } + return nil, &multierror.Error{Errors: errs} } awsConfig := &aws.Config{ - Credentials: credentialsProvider, + Credentials: creds, Endpoint: aws.String(endpoint), Region: aws.String(regionName), HTTPClient: cleanhttp.DefaultClient(), diff --git a/website/source/docs/state/remote/s3.html.md b/website/source/docs/state/remote/s3.html.md index 84ca21323..40be5088f 100644 --- a/website/source/docs/state/remote/s3.html.md +++ b/website/source/docs/state/remote/s3.html.md @@ -56,3 +56,6 @@ The following configuration options / environment variables are supported: * `access_key` / `AWS_ACCESS_KEY_ID` - (Optional) AWS access key * `secret_key` / `AWS_SECRET_ACCESS_KEY` - (Optional) AWS secret key * `kms_key_id` - (Optional) The ARN of a KMS Key to use for encrypting the state. + * `profile` - (Optional) This is the AWS profile name as set in the shared credentials file. + * `shared_credentials_file` - (Optional) This is the path to the shared credentials file. If this is not set and a profile is specified, ~/.aws/credentials will be used. + * `token` - (Optional) Use this to set an MFA token. It can also be sourced from the `AWS_SECURITY_TOKEN` environment variable.