Skip to content

Commit

Permalink
provider/aws: Refactor logic for getting credentials providers
Browse files Browse the repository at this point in the history
  • Loading branch information
radeksimko committed Feb 7, 2016
1 parent 81947d4 commit eeea864
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 32 deletions.
58 changes: 27 additions & 31 deletions builtin/providers/aws/auth_helpers.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package aws

import (
"fmt"
"log"
"net/http"
"os"
"strings"
"time"
Expand All @@ -12,12 +12,25 @@ import (
"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/hashicorp/go-cleanhttp"
)

const DefaultMetadataEndpoint = "http://169.254.169.254:80/latest"

// This function is responsible for reading credentials from the
// environment in the case that they're not explicitly specified
// in the Terraform configuration.
func getCreds(key, secret, token, profile, credsfile string) *awsCredentials.Credentials {
// Build isolated HTTP client to avoid issues with globally-shared settings
client := cleanhttp.DefaultClient()

// Keep the timeout low as we don't want to wait in non-EC2 environments
client.Timeout = 100 * time.Millisecond
cfg := &aws.Config{
Endpoint: aws.String(getMetadataEndpoint()),
HTTPClient: client,
}

// build a chain provider, lazy-evaulated by aws-sdk
providers := []awsCredentials.Provider{
&awsCredentials.StaticProvider{Value: awsCredentials.Value{
Expand All @@ -30,39 +43,22 @@ func getCreds(key, secret, token, profile, credsfile string) *awsCredentials.Cre
Filename: credsfile,
Profile: profile,
},
&ec2rolecreds.EC2RoleProvider{
Client: ec2metadata.New(session.New(cfg)),
},
}

// We only look in the EC2 metadata API if we can connect
// to the metadata service within a reasonable amount of time
metadataURL := os.Getenv("AWS_METADATA_URL")
if metadataURL == "" {
metadataURL = "http://169.254.169.254:80/latest"
}
c := http.Client{
Timeout: 100 * time.Millisecond,
}
return awsCredentials.NewChainCredentials(providers)
}

r, err := c.Get(metadataURL)
// Flag to determine if we should add the EC2Meta data provider. Default false
var useIAM bool
if err == nil {
// AWS will add a "Server: EC2ws" header value for the metadata request. We
// check the headers for this value to ensure something else didn't just
// happent to be listening on that IP:Port
if r.Header["Server"] != nil && strings.Contains(r.Header["Server"][0], "EC2") {
useIAM = true
}
// getMetadataEndpoint returns metadata endpoint URL
// including the version path
func getMetadataEndpoint() string {
endpoint := os.Getenv("AWS_METADATA_ENDPOINT")
if endpoint != "" {
log.Printf("[DEBUG] Using custom metadata endpoint: %q", endpoint)
return endpoint
}

if useIAM {
log.Printf("[DEBUG] EC2 Metadata service found, adding EC2 Role Credential Provider")
providers = append(providers, &ec2rolecreds.EC2RoleProvider{
Client: ec2metadata.New(session.New(&aws.Config{
Endpoint: aws.String(metadataURL),
})),
})
} else {
log.Printf("[DEBUG] EC2 Metadata service not found, not adding EC2 Role Credential Provider")
}
return awsCredentials.NewChainCredentials(providers)
return DefaultMetadataEndpoint
}
24 changes: 23 additions & 1 deletion builtin/providers/aws/auth_helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,28 @@ func TestAWSConfig_shouldIgnoreIAM(t *testing.T) {
}
}

func TestAWSConfig_shouldCatchEC2RoleProvider(t *testing.T) {
resetEnv := unsetEnv(t)
defer resetEnv()
// capture the test server's close method, to call after the test returns
ts := awsEnv(t)
defer ts()

creds := getCreds("", "", "", "", "")
if creds == nil {
t.Fatalf("Expected an EC2Role creds provider to be returned")
}
v, err := creds.Get()
if err != nil {
t.Fatalf("Expected no error when getting creds: %s", err)
}
expectedProvider := "EC2RoleProvider"
if v.ProviderName != expectedProvider {
t.Fatal("Expected provider name to be %q, %q given",
expectedProvider, v.ProviderName)
}
}

var credentialsFileContents = `[myprofile]
aws_access_key_id = accesskey
aws_secret_access_key = secretkey
Expand Down Expand Up @@ -331,7 +353,7 @@ func awsEnv(t *testing.T) func() {
}
}))

os.Setenv("AWS_METADATA_URL", ts.URL+"/latest")
os.Setenv("AWS_METADATA_ENDPOINT", ts.URL+"/latest")
return ts.Close
}

Expand Down

0 comments on commit eeea864

Please sign in to comment.