|
|
|
|
@ -3,14 +3,12 @@ package common
|
|
|
|
|
import (
|
|
|
|
|
"fmt"
|
|
|
|
|
"log"
|
|
|
|
|
"os"
|
|
|
|
|
"strings"
|
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
"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/hashicorp/go-cleanhttp"
|
|
|
|
|
@ -38,66 +36,13 @@ func (c *AccessConfig) Session() (*session.Session, error) {
|
|
|
|
|
return c.session, nil
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// build a chain provider, lazy-evaluated by aws-sdk
|
|
|
|
|
providers := []credentials.Provider{
|
|
|
|
|
&credentials.StaticProvider{Value: credentials.Value{
|
|
|
|
|
AccessKeyID: c.AccessKey,
|
|
|
|
|
SecretAccessKey: c.SecretKey,
|
|
|
|
|
SessionToken: c.Token,
|
|
|
|
|
}},
|
|
|
|
|
&credentials.EnvProvider{},
|
|
|
|
|
&credentials.SharedCredentialsProvider{
|
|
|
|
|
Filename: "",
|
|
|
|
|
Profile: c.ProfileName,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Build isolated HTTP client to avoid issues with globally-shared settings
|
|
|
|
|
client := cleanhttp.DefaultClient()
|
|
|
|
|
|
|
|
|
|
// Keep the default timeout (100ms) low as we don't want to wait in non-EC2 environments
|
|
|
|
|
client.Timeout = 100 * time.Millisecond
|
|
|
|
|
|
|
|
|
|
const userTimeoutEnvVar = "AWS_METADATA_TIMEOUT"
|
|
|
|
|
userTimeout := os.Getenv(userTimeoutEnvVar)
|
|
|
|
|
if userTimeout != "" {
|
|
|
|
|
newTimeout, err := time.ParseDuration(userTimeout)
|
|
|
|
|
if err == nil {
|
|
|
|
|
if newTimeout.Nanoseconds() > 0 {
|
|
|
|
|
client.Timeout = newTimeout
|
|
|
|
|
} else {
|
|
|
|
|
log.Printf("[WARN] Non-positive value of %s (%s) is meaningless, ignoring", userTimeoutEnvVar, newTimeout.String())
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
log.Printf("[WARN] Error converting %s to time.Duration: %s", userTimeoutEnvVar, err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
config := aws.NewConfig().WithCredentialsChainVerboseErrors(true)
|
|
|
|
|
|
|
|
|
|
log.Printf("[INFO] Setting AWS metadata API timeout to %s", client.Timeout.String())
|
|
|
|
|
cfg := &aws.Config{
|
|
|
|
|
HTTPClient: client,
|
|
|
|
|
}
|
|
|
|
|
if !c.SkipMetadataApiCheck {
|
|
|
|
|
// Real AWS should reply to a simple metadata request.
|
|
|
|
|
// We check it actually does to ensure something else didn't just
|
|
|
|
|
// happen to be listening on the same IP:Port
|
|
|
|
|
metadataClient := ec2metadata.New(session.New(cfg))
|
|
|
|
|
if metadataClient.Available() {
|
|
|
|
|
providers = append(providers, &ec2rolecreds.EC2RoleProvider{
|
|
|
|
|
Client: metadataClient,
|
|
|
|
|
})
|
|
|
|
|
log.Print("[INFO] AWS EC2 instance detected via default metadata" +
|
|
|
|
|
" API endpoint, EC2RoleProvider added to the auth chain")
|
|
|
|
|
} else {
|
|
|
|
|
log.Printf("[INFO] Ignoring AWS metadata API endpoint " +
|
|
|
|
|
"as it doesn't return any instance-id")
|
|
|
|
|
}
|
|
|
|
|
staticCreds := credentials.NewStaticCredentials(c.AccessKey, c.SecretKey, c.Token)
|
|
|
|
|
if _, err := staticCreds.Get(); err != credentials.ErrStaticCredentialsEmpty {
|
|
|
|
|
config.WithCredentials(staticCreds)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
creds := credentials.NewChainCredentials(providers)
|
|
|
|
|
|
|
|
|
|
config := aws.NewConfig().WithMaxRetries(11).WithCredentialsChainVerboseErrors(true)
|
|
|
|
|
|
|
|
|
|
if c.RawRegion != "" {
|
|
|
|
|
config = config.WithRegion(c.RawRegion)
|
|
|
|
|
} else if region := c.metadataRegion(); region != "" {
|
|
|
|
|
@ -123,8 +68,6 @@ func (c *AccessConfig) Session() (*session.Session, error) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
config = config.WithCredentials(creds)
|
|
|
|
|
|
|
|
|
|
if sess, err := session.NewSessionWithOptions(opts); err != nil {
|
|
|
|
|
return nil, err
|
|
|
|
|
} else if *sess.Config.Region == "" {
|
|
|
|
|
@ -185,6 +128,9 @@ func (c *AccessConfig) metadataRegion() string {
|
|
|
|
|
func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error {
|
|
|
|
|
var errs []error
|
|
|
|
|
|
|
|
|
|
if c.SkipMetadataApiCheck {
|
|
|
|
|
log.Println("(WARN) skip_metadata_api_check ignored.")
|
|
|
|
|
}
|
|
|
|
|
// Either both access and secret key must be set or neither of them should
|
|
|
|
|
// be.
|
|
|
|
|
if (len(c.AccessKey) > 0) != (len(c.SecretKey) > 0) {
|
|
|
|
|
|