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  }