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