Blame vendor/github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds/ec2_role_provider.go

Packit 63bb0d
package ec2rolecreds
Packit 63bb0d
Packit 63bb0d
import (
Packit 63bb0d
	"bufio"
Packit 63bb0d
	"encoding/json"
Packit 63bb0d
	"fmt"
Packit 63bb0d
	"strings"
Packit 63bb0d
	"time"
Packit 63bb0d
Packit 63bb0d
	"github.com/aws/aws-sdk-go/aws/awserr"
Packit 63bb0d
	"github.com/aws/aws-sdk-go/aws/client"
Packit 63bb0d
	"github.com/aws/aws-sdk-go/aws/credentials"
Packit 63bb0d
	"github.com/aws/aws-sdk-go/aws/ec2metadata"
Packit 63bb0d
	"github.com/aws/aws-sdk-go/aws/request"
Packit 63bb0d
	"github.com/aws/aws-sdk-go/internal/sdkuri"
Packit 63bb0d
)
Packit 63bb0d
Packit 63bb0d
// ProviderName provides a name of EC2Role provider
Packit 63bb0d
const ProviderName = "EC2RoleProvider"
Packit 63bb0d
Packit 63bb0d
// A EC2RoleProvider retrieves credentials from the EC2 service, and keeps track if
Packit 63bb0d
// those credentials are expired.
Packit 63bb0d
//
Packit 63bb0d
// Example how to configure the EC2RoleProvider with custom http Client, Endpoint
Packit 63bb0d
// or ExpiryWindow
Packit 63bb0d
//
Packit 63bb0d
//     p := &ec2rolecreds.EC2RoleProvider{
Packit 63bb0d
//         // Pass in a custom timeout to be used when requesting
Packit 63bb0d
//         // IAM EC2 Role credentials.
Packit 63bb0d
//         Client: ec2metadata.New(sess, aws.Config{
Packit 63bb0d
//             HTTPClient: &http.Client{Timeout: 10 * time.Second},
Packit 63bb0d
//         }),
Packit 63bb0d
//
Packit 63bb0d
//         // Do not use early expiry of credentials. If a non zero value is
Packit 63bb0d
//         // specified the credentials will be expired early
Packit 63bb0d
//         ExpiryWindow: 0,
Packit 63bb0d
//     }
Packit 63bb0d
type EC2RoleProvider struct {
Packit 63bb0d
	credentials.Expiry
Packit 63bb0d
Packit 63bb0d
	// Required EC2Metadata client to use when connecting to EC2 metadata service.
Packit 63bb0d
	Client *ec2metadata.EC2Metadata
Packit 63bb0d
Packit 63bb0d
	// ExpiryWindow will allow the credentials to trigger refreshing prior to
Packit 63bb0d
	// the credentials actually expiring. This is beneficial so race conditions
Packit 63bb0d
	// with expiring credentials do not cause request to fail unexpectedly
Packit 63bb0d
	// due to ExpiredTokenException exceptions.
Packit 63bb0d
	//
Packit 63bb0d
	// So a ExpiryWindow of 10s would cause calls to IsExpired() to return true
Packit 63bb0d
	// 10 seconds before the credentials are actually expired.
Packit 63bb0d
	//
Packit 63bb0d
	// If ExpiryWindow is 0 or less it will be ignored.
Packit 63bb0d
	ExpiryWindow time.Duration
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// NewCredentials returns a pointer to a new Credentials object wrapping
Packit 63bb0d
// the EC2RoleProvider. Takes a ConfigProvider to create a EC2Metadata client.
Packit 63bb0d
// The ConfigProvider is satisfied by the session.Session type.
Packit 63bb0d
func NewCredentials(c client.ConfigProvider, options ...func(*EC2RoleProvider)) *credentials.Credentials {
Packit 63bb0d
	p := &EC2RoleProvider{
Packit 63bb0d
		Client: ec2metadata.New(c),
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	for _, option := range options {
Packit 63bb0d
		option(p)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	return credentials.NewCredentials(p)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// NewCredentialsWithClient returns a pointer to a new Credentials object wrapping
Packit 63bb0d
// the EC2RoleProvider. Takes a EC2Metadata client to use when connecting to EC2
Packit 63bb0d
// metadata service.
Packit 63bb0d
func NewCredentialsWithClient(client *ec2metadata.EC2Metadata, options ...func(*EC2RoleProvider)) *credentials.Credentials {
Packit 63bb0d
	p := &EC2RoleProvider{
Packit 63bb0d
		Client: client,
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	for _, option := range options {
Packit 63bb0d
		option(p)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	return credentials.NewCredentials(p)
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// Retrieve retrieves credentials from the EC2 service.
Packit 63bb0d
// Error will be returned if the request fails, or unable to extract
Packit 63bb0d
// the desired credentials.
Packit 63bb0d
func (m *EC2RoleProvider) Retrieve() (credentials.Value, error) {
Packit 63bb0d
	credsList, err := requestCredList(m.Client)
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return credentials.Value{ProviderName: ProviderName}, err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if len(credsList) == 0 {
Packit 63bb0d
		return credentials.Value{ProviderName: ProviderName}, awserr.New("EmptyEC2RoleList", "empty EC2 Role list", nil)
Packit 63bb0d
	}
Packit 63bb0d
	credsName := credsList[0]
Packit 63bb0d
Packit 63bb0d
	roleCreds, err := requestCred(m.Client, credsName)
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return credentials.Value{ProviderName: ProviderName}, err
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	m.SetExpiration(roleCreds.Expiration, m.ExpiryWindow)
Packit 63bb0d
Packit 63bb0d
	return credentials.Value{
Packit 63bb0d
		AccessKeyID:     roleCreds.AccessKeyID,
Packit 63bb0d
		SecretAccessKey: roleCreds.SecretAccessKey,
Packit 63bb0d
		SessionToken:    roleCreds.Token,
Packit 63bb0d
		ProviderName:    ProviderName,
Packit 63bb0d
	}, nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// A ec2RoleCredRespBody provides the shape for unmarshaling credential
Packit 63bb0d
// request responses.
Packit 63bb0d
type ec2RoleCredRespBody struct {
Packit 63bb0d
	// Success State
Packit 63bb0d
	Expiration      time.Time
Packit 63bb0d
	AccessKeyID     string
Packit 63bb0d
	SecretAccessKey string
Packit 63bb0d
	Token           string
Packit 63bb0d
Packit 63bb0d
	// Error state
Packit 63bb0d
	Code    string
Packit 63bb0d
	Message string
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
const iamSecurityCredsPath = "iam/security-credentials/"
Packit 63bb0d
Packit 63bb0d
// requestCredList requests a list of credentials from the EC2 service.
Packit 63bb0d
// If there are no credentials, or there is an error making or receiving the request
Packit 63bb0d
func requestCredList(client *ec2metadata.EC2Metadata) ([]string, error) {
Packit 63bb0d
	resp, err := client.GetMetadata(iamSecurityCredsPath)
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return nil, awserr.New("EC2RoleRequestError", "no EC2 instance role found", err)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	credsList := []string{}
Packit 63bb0d
	s := bufio.NewScanner(strings.NewReader(resp))
Packit 63bb0d
	for s.Scan() {
Packit 63bb0d
		credsList = append(credsList, s.Text())
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if err := s.Err(); err != nil {
Packit 63bb0d
		return nil, awserr.New(request.ErrCodeSerialization,
Packit 63bb0d
			"failed to read EC2 instance role from metadata service", err)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	return credsList, nil
Packit 63bb0d
}
Packit 63bb0d
Packit 63bb0d
// requestCred requests the credentials for a specific credentials from the EC2 service.
Packit 63bb0d
//
Packit 63bb0d
// If the credentials cannot be found, or there is an error reading the response
Packit 63bb0d
// and error will be returned.
Packit 63bb0d
func requestCred(client *ec2metadata.EC2Metadata, credsName string) (ec2RoleCredRespBody, error) {
Packit 63bb0d
	resp, err := client.GetMetadata(sdkuri.PathJoin(iamSecurityCredsPath, credsName))
Packit 63bb0d
	if err != nil {
Packit 63bb0d
		return ec2RoleCredRespBody{},
Packit 63bb0d
			awserr.New("EC2RoleRequestError",
Packit 63bb0d
				fmt.Sprintf("failed to get %s EC2 instance role credentials", credsName),
Packit 63bb0d
				err)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	respCreds := ec2RoleCredRespBody{}
Packit 63bb0d
	if err := json.NewDecoder(strings.NewReader(resp)).Decode(&respCreds); err != nil {
Packit 63bb0d
		return ec2RoleCredRespBody{},
Packit 63bb0d
			awserr.New(request.ErrCodeSerialization,
Packit 63bb0d
				fmt.Sprintf("failed to decode %s EC2 instance role credentials", credsName),
Packit 63bb0d
				err)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	if respCreds.Code != "Success" {
Packit 63bb0d
		// If an error code was returned something failed requesting the role.
Packit 63bb0d
		return ec2RoleCredRespBody{}, awserr.New(respCreds.Code, respCreds.Message, nil)
Packit 63bb0d
	}
Packit 63bb0d
Packit 63bb0d
	return respCreds, nil
Packit 63bb0d
}