open-vault/builtin/credential/aws/client.go

100 lines
2.8 KiB
Go
Raw Normal View History

package aws
import (
"fmt"
"os"
"github.com/aws/aws-sdk-go/aws"
"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/ec2"
"github.com/hashicorp/go-cleanhttp"
"github.com/hashicorp/vault/logical"
)
// getClientConfig creates a aws-sdk-go config, which is used to create client
// that can interact with AWS API. This builds credentials in the following
// order of preference:
//
// * Static credentials from 'config/client'
// * Environment variables
// * Instance metadata role
func (b *backend) getClientConfig(s logical.Storage) (*aws.Config, error) {
// Read the configured secret key and access key
config, err := clientConfigEntry(s)
if err != nil {
return nil, err
}
var providers []credentials.Provider
region := os.Getenv("AWS_REGION")
if config != nil {
if config.Region != "" {
region = config.Region
}
switch {
case config.AccessKey != "" && config.SecretKey != "":
providers = append(providers, &credentials.StaticProvider{
Value: credentials.Value{
AccessKeyID: config.AccessKey,
SecretAccessKey: config.SecretKey,
}})
case config.AccessKey == "" && config.AccessKey == "":
// Attempt to get credentials from the IAM instance role below
default: // Have one or the other but not both and not neither
return nil, fmt.Errorf(
"static AWS client credentials haven't been properly configured (the access key or secret key were provided but not both); configure or remove them at the 'config/client' endpoint")
}
}
providers = append(providers, &credentials.EnvProvider{})
// Create the credentials required to access the API.
providers = append(providers, &ec2rolecreds.EC2RoleProvider{
Client: ec2metadata.New(session.New(&aws.Config{
Region: aws.String(region),
HTTPClient: cleanhttp.DefaultClient(),
})),
ExpiryWindow: 15,
})
creds := credentials.NewChainCredentials(providers)
if creds == nil {
return nil, fmt.Errorf("could not compile valid credential providers from static config, environemnt, or instance metadata")
}
// Create a config that can be used to make the API calls.
return &aws.Config{
Credentials: creds,
Region: aws.String(region),
HTTPClient: cleanhttp.DefaultClient(),
}, nil
}
// clientEC2 creates a client to interact with AWS EC2 API.
func (b *backend) clientEC2(s logical.Storage, recreate bool) (*ec2.EC2, error) {
if !recreate {
b.configMutex.RLock()
if b.ec2Client != nil {
defer b.configMutex.RUnlock()
return b.ec2Client, nil
}
b.configMutex.RUnlock()
}
b.configMutex.Lock()
defer b.configMutex.Unlock()
awsConfig, err := b.getClientConfig(s)
if err != nil {
return nil, err
}
b.ec2Client = ec2.New(session.New(awsConfig))
return b.ec2Client, nil
}