Skip to content

Commit

Permalink
Merge pull request #4254 from hashicorp/b-aws-auth-refactor
Browse files Browse the repository at this point in the history
provider/aws: WIP Refactor AWS Authentication chain
  • Loading branch information
catsby committed Dec 16, 2015
2 parents 3365cd2 + adf4178 commit 54e4432
Show file tree
Hide file tree
Showing 3 changed files with 373 additions and 91 deletions.
70 changes: 65 additions & 5 deletions builtin/providers/aws/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@ package aws
import (
"fmt"
"log"
"net/http"
"os"
"strings"
"time"

"github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/go-multierror"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/credentials"
awsCredentials "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/autoscaling"
"github.com/aws/aws-sdk-go/service/cloudformation"
Expand Down Expand Up @@ -104,9 +109,14 @@ func (c *Config) Client() (interface{}, error) {
client.region = c.Region

log.Println("[INFO] Building AWS auth structure")
// We fetched all credential sources in Provider. If they are
// available, they'll already be in c. See Provider definition.
creds := credentials.NewStaticCredentials(c.AccessKey, c.SecretKey, c.Token)
creds := getCreds(c.AccessKey, c.SecretKey, c.Token)
// 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 {
errs = append(errs, fmt.Errorf("Error loading credentials for AWS Provider: %s", err))
return nil, &multierror.Error{Errors: errs}
}
awsConfig := &aws.Config{
Credentials: creds,
Region: aws.String(c.Region),
Expand All @@ -118,7 +128,7 @@ func (c *Config) Client() (interface{}, error) {
sess := session.New(awsConfig)
client.iamconn = iam.New(sess)

err := c.ValidateCredentials(client.iamconn)
err = c.ValidateCredentials(client.iamconn)
if err != nil {
errs = append(errs, err)
}
Expand Down Expand Up @@ -316,3 +326,53 @@ func (c *Config) ValidateAccountId(iamconn *iam.IAM) error {

return nil
}

// 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 string) *awsCredentials.Credentials {
// build a chain provider, lazy-evaulated by aws-sdk
providers := []awsCredentials.Provider{
&awsCredentials.StaticProvider{Value: awsCredentials.Value{
AccessKeyID: key,
SecretAccessKey: secret,
SessionToken: token,
}},
&awsCredentials.EnvProvider{},
&awsCredentials.SharedCredentialsProvider{},
}

// 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,
}

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
}
}

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)
}
Loading

0 comments on commit 54e4432

Please sign in to comment.