From ed67f8f588aacb478cb7603c9c0da9dfb6d57bfe Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Wed, 6 May 2015 20:02:09 -0700 Subject: [PATCH] providers/aws: detect credentials more robustly aws hides its credentials in many places: multiple env vars, config files, ec2 metadata. Terraform currently recognizes only the env vars; to use the other options, you had to put in a dummy empty value for access_key and secret_key. Rather than duplicate all aws checks, ask the aws sdk to fetch credentials earlier. --- builtin/providers/aws/config.go | 13 +++------- builtin/providers/aws/provider.go | 42 ++++++++++++++++++++++--------- 2 files changed, 33 insertions(+), 22 deletions(-) diff --git a/builtin/providers/aws/config.go b/builtin/providers/aws/config.go index 552a0f446..0833adaaf 100644 --- a/builtin/providers/aws/config.go +++ b/builtin/providers/aws/config.go @@ -62,16 +62,9 @@ func (c *Config) Client() (interface{}, error) { client.region = c.Region log.Println("[INFO] Building AWS auth structure") - creds := credentials.NewChainCredentials([]credentials.Provider{ - &credentials.StaticProvider{Value: credentials.Value{ - AccessKeyID: c.AccessKey, - SecretAccessKey: c.SecretKey, - SessionToken: c.Token, - }}, - &credentials.EnvProvider{}, - &credentials.SharedCredentialsProvider{Filename: "", Profile: ""}, - &credentials.EC2RoleProvider{}, - }) + // We fetched all credential sources in Provider. + // If it is available, it is stored in c. + creds := credentials.NewStaticCredentials(c.AccessKey, c.SecretKey, c.Token) awsConfig := &aws.Config{ Credentials: creds, Region: c.Region, diff --git a/builtin/providers/aws/provider.go b/builtin/providers/aws/provider.go index 095e392dd..21791e3cf 100644 --- a/builtin/providers/aws/provider.go +++ b/builtin/providers/aws/provider.go @@ -1,6 +1,9 @@ package aws import ( + "sync" + + "github.com/awslabs/aws-sdk-go/aws/credentials" "github.com/hashicorp/terraform/helper/hashcode" "github.com/hashicorp/terraform/helper/schema" "github.com/hashicorp/terraform/terraform" @@ -11,35 +14,50 @@ func Provider() terraform.ResourceProvider { // TODO: Move the validation to this, requires conditional schemas // TODO: Move the configuration to this, requires validation + // Prepare to handle external sources of credentials. + // Static credentials are intentionally omitted; + // this is used when no static credentials are provided. + creds := credentials.NewChainCredentials([]credentials.Provider{ + &credentials.EnvProvider{}, + &credentials.SharedCredentialsProvider{}, + &credentials.EC2RoleProvider{}, + }) + var credVal credentials.Value + var credErr error + var once sync.Once + getCreds := func() { + credVal, credErr = creds.Get() + } + return &schema.Provider{ Schema: map[string]*schema.Schema{ "access_key": &schema.Schema{ Type: schema.TypeString, Required: true, - DefaultFunc: schema.MultiEnvDefaultFunc([]string{ - "AWS_ACCESS_KEY", - "AWS_ACCESS_KEY_ID", - }, nil), + DefaultFunc: func() (interface{}, error) { + once.Do(getCreds) + return credVal.AccessKeyID, credErr + }, Description: descriptions["access_key"], }, "secret_key": &schema.Schema{ Type: schema.TypeString, Required: true, - DefaultFunc: schema.MultiEnvDefaultFunc([]string{ - "AWS_SECRET_KEY", - "AWS_SECRET_ACCESS_KEY", - }, nil), + DefaultFunc: func() (interface{}, error) { + once.Do(getCreds) + return credVal.SecretAccessKey, credErr + }, Description: descriptions["secret_key"], }, "token": &schema.Schema{ Type: schema.TypeString, Optional: true, - DefaultFunc: schema.MultiEnvDefaultFunc([]string{ - "AWS_SESSION_TOKEN", - "AWS_SECURITY_TOKEN", - }, ""), + DefaultFunc: func() (interface{}, error) { + once.Do(getCreds) + return credVal.SessionToken, credErr + }, Description: descriptions["token"], },