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