2016-04-06 00:42:26 +00:00
package aws
import (
"fmt"
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/credentials"
2016-04-07 18:13:19 +00:00
"github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds"
"github.com/aws/aws-sdk-go/aws/ec2metadata"
2016-04-06 00:42:26 +00:00
"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"
)
2016-04-07 18:13:19 +00:00
// 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
2016-04-14 04:11:17 +00:00
func ( b * backend ) getClientConfig ( s logical . Storage , region string ) ( * aws . Config , error ) {
2016-04-06 00:42:26 +00:00
// Read the configured secret key and access key
config , err := clientConfigEntry ( s )
if err != nil {
return nil , err
}
2016-04-07 18:13:19 +00:00
var providers [ ] credentials . Provider
if config != nil {
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" )
}
2016-04-06 00:42:26 +00:00
}
2016-04-07 18:13:19 +00:00
providers = append ( providers , & credentials . EnvProvider { } )
2016-04-06 00:42:26 +00:00
// Create the credentials required to access the API.
2016-04-07 18:13:19 +00:00
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" )
}
2016-04-06 00:42:26 +00:00
// Create a config that can be used to make the API calls.
return & aws . Config {
Credentials : creds ,
2016-04-07 18:13:19 +00:00
Region : aws . String ( region ) ,
2016-04-06 00:42:26 +00:00
HTTPClient : cleanhttp . DefaultClient ( ) ,
} , nil
}
2016-04-14 04:11:17 +00:00
// flushCachedEC2Clients deletes all the cached ec2 client objects from the backend.
func ( b * backend ) flushCachedEC2Clients ( ) {
b . configMutex . Lock ( )
defer b . configMutex . Unlock ( )
for region , _ := range b . EC2ClientsMap {
delete ( b . EC2ClientsMap , region )
}
}
2016-04-06 00:42:26 +00:00
// clientEC2 creates a client to interact with AWS EC2 API.
2016-04-14 04:11:17 +00:00
func ( b * backend ) clientEC2 ( s logical . Storage , region string , recreate bool ) ( * ec2 . EC2 , error ) {
2016-04-07 18:13:19 +00:00
if ! recreate {
b . configMutex . RLock ( )
2016-04-14 04:11:17 +00:00
if b . EC2ClientsMap [ region ] != nil {
2016-04-07 18:13:19 +00:00
defer b . configMutex . RUnlock ( )
2016-04-14 04:11:17 +00:00
return b . EC2ClientsMap [ region ] , nil
2016-04-07 18:13:19 +00:00
}
b . configMutex . RUnlock ( )
}
b . configMutex . Lock ( )
defer b . configMutex . Unlock ( )
2016-04-14 04:11:17 +00:00
awsConfig , err := b . getClientConfig ( s , region )
2016-04-06 00:42:26 +00:00
if err != nil {
return nil , err
}
2016-04-07 18:13:19 +00:00
2016-04-14 04:11:17 +00:00
b . EC2ClientsMap [ region ] = ec2 . New ( session . New ( awsConfig ) )
return b . EC2ClientsMap [ region ] , nil
2016-04-06 00:42:26 +00:00
}