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