diff options
Diffstat (limited to 'Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/credentials.go')
-rw-r--r-- | Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/credentials.go | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/credentials.go b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/credentials.go new file mode 100644 index 000000000..4490c674a --- /dev/null +++ b/Godeps/_workspace/src/github.com/awslabs/aws-sdk-go/aws/credentials.go @@ -0,0 +1,288 @@ +package aws + +import ( + "bufio" + "encoding/json" + "errors" + "fmt" + "net/http" + "os" + "path/filepath" + "sync" + "time" + + "github.com/vaughan0/go-ini" +) + +var currentTime = time.Now + +// Credentials are used to authenticate and authorize calls that you make to +// AWS. +type Credentials struct { + AccessKeyID string + SecretAccessKey string + SessionToken string +} + +// A CredentialsProvider is a provider of credentials. +type CredentialsProvider interface { + // Credentials returns a set of credentials (or an error if no credentials + // could be provided). + Credentials() (*Credentials, error) +} + +var ( + // ErrAccessKeyIDNotFound is returned when the AWS Access Key ID can't be + // found in the process's environment. + ErrAccessKeyIDNotFound = fmt.Errorf("AWS_ACCESS_KEY_ID or AWS_ACCESS_KEY not found in environment") + // ErrSecretAccessKeyNotFound is returned when the AWS Secret Access Key + // can't be found in the process's environment. + ErrSecretAccessKeyNotFound = fmt.Errorf("AWS_SECRET_ACCESS_KEY or AWS_SECRET_KEY not found in environment") +) + +type DefaultCredentialsProvider struct { +} + +func (p *DefaultCredentialsProvider) Credentials() (*Credentials, error) { + env, err := EnvCreds() + if err == nil { + return env.Credentials() + } + + profile, err := ProfileCreds("", "", 10*time.Minute) + if err == nil { + profileCreds, err := profile.Credentials() + if err == nil { + return profileCreds, nil + } + } + + return IAMCreds().Credentials() +} + +func DefaultCreds() CredentialsProvider { + return &DefaultCredentialsProvider{} +} + +// DetectCreds returns a CredentialsProvider based on the available information. +// +// If the access key ID and secret access key are provided, it returns a basic +// provider. +// +// If credentials are available via environment variables, it returns an +// environment provider. +// +// If a profile configuration file is available in the default location and has +// a default profile configured, it returns a profile provider. +// +// Otherwise, it returns an IAM instance provider. +func DetectCreds(accessKeyID, secretAccessKey, sessionToken string) CredentialsProvider { + if accessKeyID != "" && secretAccessKey != "" { + return Creds(accessKeyID, secretAccessKey, sessionToken) + } + + env, err := EnvCreds() + if err == nil { + return env + } + + profile, err := ProfileCreds("", "", 10*time.Minute) + if err != nil { + return IAMCreds() + } + + _, err = profile.Credentials() + if err != nil { + return IAMCreds() + } + + return profile +} + +// EnvCreds returns a static provider of AWS credentials from the process's +// environment, or an error if none are found. +func EnvCreds() (CredentialsProvider, error) { + id := os.Getenv("AWS_ACCESS_KEY_ID") + if id == "" { + id = os.Getenv("AWS_ACCESS_KEY") + } + + secret := os.Getenv("AWS_SECRET_ACCESS_KEY") + if secret == "" { + secret = os.Getenv("AWS_SECRET_KEY") + } + + if id == "" { + return nil, ErrAccessKeyIDNotFound + } + + if secret == "" { + return nil, ErrSecretAccessKeyNotFound + } + + return Creds(id, secret, os.Getenv("AWS_SESSION_TOKEN")), nil +} + +// Creds returns a static provider of credentials. +func Creds(accessKeyID, secretAccessKey, sessionToken string) CredentialsProvider { + return staticCredentialsProvider{ + creds: Credentials{ + AccessKeyID: accessKeyID, + SecretAccessKey: secretAccessKey, + SessionToken: sessionToken, + }, + } +} + +// IAMCreds returns a provider which pulls credentials from the local EC2 +// instance's IAM roles. +func IAMCreds() CredentialsProvider { + return &iamProvider{} +} + +// ProfileCreds returns a provider which pulls credentials from the profile +// configuration file. +func ProfileCreds(filename, profile string, expiry time.Duration) (CredentialsProvider, error) { + if filename == "" { + homeDir := os.Getenv("HOME") // *nix + if homeDir == "" { // Windows + homeDir = os.Getenv("USERPROFILE") + } + if homeDir == "" { + return nil, errors.New("User home directory not found.") + } + + filename = filepath.Join(homeDir, ".aws", "credentials") + } + + if profile == "" { + profile = "default" + } + + return &profileProvider{ + filename: filename, + profile: profile, + expiry: expiry, + }, nil +} + +type profileProvider struct { + filename string + profile string + expiry time.Duration + + creds Credentials + m sync.Mutex + expiration time.Time +} + +func (p *profileProvider) Credentials() (*Credentials, error) { + p.m.Lock() + defer p.m.Unlock() + + if p.expiration.After(currentTime()) { + return &p.creds, nil + } + + config, err := ini.LoadFile(p.filename) + if err != nil { + return nil, err + } + profile := config.Section(p.profile) + + accessKeyID, ok := profile["aws_access_key_id"] + if !ok { + return nil, fmt.Errorf("profile %s in %s did not contain aws_access_key_id", p.profile, p.filename) + } + + secretAccessKey, ok := profile["aws_secret_access_key"] + if !ok { + return nil, fmt.Errorf("profile %s in %s did not contain aws_secret_access_key", p.profile, p.filename) + } + + sessionToken := profile["aws_session_token"] + + p.creds = Credentials{ + AccessKeyID: accessKeyID, + SecretAccessKey: secretAccessKey, + SessionToken: sessionToken, + } + p.expiration = currentTime().Add(p.expiry) + + return &p.creds, nil +} + +type iamProvider struct { + creds Credentials + m sync.Mutex + expiration time.Time +} + +var metadataCredentialsEndpoint = "http://169.254.169.254/latest/meta-data/iam/security-credentials/" + +// IAMClient is the HTTP client used to query the metadata endpoint for IAM +// credentials. +var IAMClient = http.Client{ + Timeout: 1 * time.Second, +} + +func (p *iamProvider) Credentials() (*Credentials, error) { + p.m.Lock() + defer p.m.Unlock() + + if p.expiration.After(currentTime()) { + return &p.creds, nil + } + + var body struct { + Expiration time.Time + AccessKeyID string + SecretAccessKey string + Token string + } + + resp, err := IAMClient.Get(metadataCredentialsEndpoint) + if err != nil { + return nil, fmt.Errorf("listing IAM credentials") + } + defer func() { + _ = resp.Body.Close() + }() + + // Take the first line of the body of the metadata endpoint + s := bufio.NewScanner(resp.Body) + if !s.Scan() { + return nil, fmt.Errorf("unable to find default IAM credentials") + } else if s.Err() != nil { + return nil, fmt.Errorf("%s listing IAM credentials", s.Err()) + } + + resp, err = IAMClient.Get(metadataCredentialsEndpoint + s.Text()) + if err != nil { + return nil, fmt.Errorf("getting %s IAM credentials", s.Text()) + } + defer func() { + _ = resp.Body.Close() + }() + + if err := json.NewDecoder(resp.Body).Decode(&body); err != nil { + return nil, fmt.Errorf("decoding %s IAM credentials", s.Text()) + } + + p.creds = Credentials{ + AccessKeyID: body.AccessKeyID, + SecretAccessKey: body.SecretAccessKey, + SessionToken: body.Token, + } + p.expiration = body.Expiration + + return &p.creds, nil +} + +type staticCredentialsProvider struct { + creds Credentials +} + +func (p staticCredentialsProvider) Credentials() (*Credentials, error) { + return &p.creds, nil +} |