github.com/armen/terraform@v0.5.2-0.20150529052519-caa8117a08f1/builtin/providers/aws/config.go (about) 1 package aws 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 8 "github.com/hashicorp/terraform/helper/multierror" 9 10 "github.com/awslabs/aws-sdk-go/aws" 11 "github.com/awslabs/aws-sdk-go/aws/credentials" 12 "github.com/awslabs/aws-sdk-go/service/autoscaling" 13 "github.com/awslabs/aws-sdk-go/service/ec2" 14 "github.com/awslabs/aws-sdk-go/service/elasticache" 15 "github.com/awslabs/aws-sdk-go/service/elb" 16 "github.com/awslabs/aws-sdk-go/service/iam" 17 "github.com/awslabs/aws-sdk-go/service/rds" 18 "github.com/awslabs/aws-sdk-go/service/route53" 19 "github.com/awslabs/aws-sdk-go/service/s3" 20 "github.com/awslabs/aws-sdk-go/service/sqs" 21 "github.com/awslabs/aws-sdk-go/service/sns" 22 ) 23 24 type Config struct { 25 AccessKey string 26 SecretKey string 27 Token string 28 Region string 29 MaxRetries int 30 31 AllowedAccountIds []interface{} 32 ForbiddenAccountIds []interface{} 33 } 34 35 type AWSClient struct { 36 ec2conn *ec2.EC2 37 elbconn *elb.ELB 38 autoscalingconn *autoscaling.AutoScaling 39 s3conn *s3.S3 40 sqsconn *sqs.SQS 41 snsconn *sns.SNS 42 r53conn *route53.Route53 43 region string 44 rdsconn *rds.RDS 45 iamconn *iam.IAM 46 elasticacheconn *elasticache.ElastiCache 47 } 48 49 // Client configures and returns a fully initailized AWSClient 50 func (c *Config) Client() (interface{}, error) { 51 var client AWSClient 52 53 // Get the auth and region. This can fail if keys/regions were not 54 // specified and we're attempting to use the environment. 55 var errs []error 56 57 log.Println("[INFO] Building AWS region structure") 58 err := c.ValidateRegion() 59 if err != nil { 60 errs = append(errs, err) 61 } 62 63 if len(errs) == 0 { 64 // store AWS region in client struct, for region specific operations such as 65 // bucket storage in S3 66 client.region = c.Region 67 68 log.Println("[INFO] Building AWS auth structure") 69 creds := credentials.NewChainCredentials([]credentials.Provider{ 70 &credentials.StaticProvider{Value: credentials.Value{ 71 AccessKeyID: c.AccessKey, 72 SecretAccessKey: c.SecretKey, 73 SessionToken: c.Token, 74 }}, 75 &credentials.EnvProvider{}, 76 &credentials.SharedCredentialsProvider{Filename: "", Profile: ""}, 77 &credentials.EC2RoleProvider{}, 78 }) 79 awsConfig := &aws.Config{ 80 Credentials: creds, 81 Region: c.Region, 82 MaxRetries: c.MaxRetries, 83 } 84 85 log.Println("[INFO] Initializing ELB connection") 86 client.elbconn = elb.New(awsConfig) 87 88 log.Println("[INFO] Initializing S3 connection") 89 client.s3conn = s3.New(awsConfig) 90 91 log.Println("[INFO] Initializing SQS connection") 92 client.sqsconn = sqs.New(awsConfig) 93 94 log.Println("[INFO] Initializing SNS connection") 95 client.snsconn = sns.New(awsConfig) 96 97 log.Println("[INFO] Initializing RDS Connection") 98 client.rdsconn = rds.New(awsConfig) 99 100 log.Println("[INFO] Initializing IAM Connection") 101 client.iamconn = iam.New(awsConfig) 102 103 err := c.ValidateAccountId(client.iamconn) 104 if err != nil { 105 errs = append(errs, err) 106 } 107 108 log.Println("[INFO] Initializing AutoScaling connection") 109 client.autoscalingconn = autoscaling.New(awsConfig) 110 111 log.Println("[INFO] Initializing EC2 Connection") 112 client.ec2conn = ec2.New(awsConfig) 113 114 // aws-sdk-go uses v4 for signing requests, which requires all global 115 // endpoints to use 'us-east-1'. 116 // See http://docs.aws.amazon.com/general/latest/gr/sigv4_changes.html 117 log.Println("[INFO] Initializing Route 53 connection") 118 client.r53conn = route53.New(&aws.Config{ 119 Credentials: creds, 120 Region: "us-east-1", 121 MaxRetries: c.MaxRetries, 122 }) 123 124 log.Println("[INFO] Initializing Elasticache Connection") 125 client.elasticacheconn = elasticache.New(awsConfig) 126 } 127 128 if len(errs) > 0 { 129 return nil, &multierror.Error{Errors: errs} 130 } 131 132 return &client, nil 133 } 134 135 // ValidateRegion returns an error if the configured region is not a 136 // valid aws region and nil otherwise. 137 func (c *Config) ValidateRegion() error { 138 var regions = [11]string{"us-east-1", "us-west-2", "us-west-1", "eu-west-1", 139 "eu-central-1", "ap-southeast-1", "ap-southeast-2", "ap-northeast-1", 140 "sa-east-1", "cn-north-1", "us-gov-west-1"} 141 142 for _, valid := range regions { 143 if c.Region == valid { 144 return nil 145 } 146 } 147 return fmt.Errorf("Not a valid region: %s", c.Region) 148 } 149 150 // ValidateAccountId returns a context-specific error if the configured account 151 // id is explicitly forbidden or not authorised; and nil if it is authorised. 152 func (c *Config) ValidateAccountId(iamconn *iam.IAM) error { 153 if c.AllowedAccountIds == nil && c.ForbiddenAccountIds == nil { 154 return nil 155 } 156 157 log.Printf("[INFO] Validating account ID") 158 159 out, err := iamconn.GetUser(nil) 160 if err != nil { 161 return fmt.Errorf("Failed getting account ID from IAM: %s", err) 162 } 163 164 account_id := strings.Split(*out.User.ARN, ":")[4] 165 166 if c.ForbiddenAccountIds != nil { 167 for _, id := range c.ForbiddenAccountIds { 168 if id == account_id { 169 return fmt.Errorf("Forbidden account ID (%s)", id) 170 } 171 } 172 } 173 174 if c.AllowedAccountIds != nil { 175 for _, id := range c.AllowedAccountIds { 176 if id == account_id { 177 return nil 178 } 179 } 180 return fmt.Errorf("Account ID not allowed (%s)", account_id) 181 } 182 183 return nil 184 }