1package awsec2 2 3import ( 4 "fmt" 5 6 "github.com/aws/aws-sdk-go/aws" 7 "github.com/aws/aws-sdk-go/aws/session" 8 "github.com/aws/aws-sdk-go/service/ec2" 9 "github.com/hashicorp/go-cleanhttp" 10 "github.com/hashicorp/vault/helper/awsutil" 11 "github.com/hashicorp/vault/logical" 12) 13 14// getClientConfig creates a aws-sdk-go config, which is used to create client 15// that can interact with AWS API. This builds credentials in the following 16// order of preference: 17// 18// * Static credentials from 'config/client' 19// * Environment variables 20// * Instance metadata role 21func (b *backend) getClientConfig(s logical.Storage, region string) (*aws.Config, error) { 22 credsConfig := &awsutil.CredentialsConfig{ 23 Region: region, 24 } 25 26 // Read the configured secret key and access key 27 config, err := b.nonLockedClientConfigEntry(s) 28 if err != nil { 29 return nil, err 30 } 31 32 endpoint := aws.String("") 33 if config != nil { 34 // Override the default endpoint with the configured endpoint. 35 if config.Endpoint != "" { 36 endpoint = aws.String(config.Endpoint) 37 } 38 39 credsConfig.AccessKey = config.AccessKey 40 credsConfig.SecretKey = config.SecretKey 41 } 42 43 credsConfig.HTTPClient = cleanhttp.DefaultClient() 44 45 creds, err := credsConfig.GenerateCredentialChain() 46 if err != nil { 47 return nil, err 48 } 49 if creds == nil { 50 return nil, fmt.Errorf("could not compile valid credential providers from static config, environemnt, shared, or instance metadata") 51 } 52 53 // Create a config that can be used to make the API calls. 54 return &aws.Config{ 55 Credentials: creds, 56 Region: aws.String(region), 57 HTTPClient: cleanhttp.DefaultClient(), 58 Endpoint: endpoint, 59 }, nil 60} 61 62// flushCachedEC2Clients deletes all the cached ec2 client objects from the backend. 63// If the client credentials configuration is deleted or updated in the backend, all 64// the cached EC2 client objects will be flushed. 65// 66// Write lock should be acquired using b.configMutex.Lock() before calling this method 67// and lock should be released using b.configMutex.Unlock() after the method returns. 68func (b *backend) flushCachedEC2Clients() { 69 // deleting items in map during iteration is safe. 70 for region, _ := range b.EC2ClientsMap { 71 delete(b.EC2ClientsMap, region) 72 } 73} 74 75// clientEC2 creates a client to interact with AWS EC2 API. 76func (b *backend) clientEC2(s logical.Storage, region string) (*ec2.EC2, error) { 77 b.configMutex.RLock() 78 if b.EC2ClientsMap[region] != nil { 79 defer b.configMutex.RUnlock() 80 // If the client object was already created, return it. 81 return b.EC2ClientsMap[region], nil 82 } 83 84 // Release the read lock and acquire the write lock. 85 b.configMutex.RUnlock() 86 b.configMutex.Lock() 87 defer b.configMutex.Unlock() 88 89 // If the client gets created while switching the locks, return it. 90 if b.EC2ClientsMap[region] != nil { 91 return b.EC2ClientsMap[region], nil 92 } 93 94 // Create a AWS config object using a chain of providers. 95 awsConfig, err := b.getClientConfig(s, region) 96 if err != nil { 97 return nil, err 98 } 99 100 // Create a new EC2 client object, cache it and return the same. 101 b.EC2ClientsMap[region] = ec2.New(session.New(awsConfig)) 102 return b.EC2ClientsMap[region], nil 103} 104