github.com/StackPointCloud/packer@v0.10.2-0.20180716202532-b28098e0f79b/builder/amazon/common/access_config.go (about) 1 package common 2 3 import ( 4 "fmt" 5 "log" 6 "strings" 7 "time" 8 9 "github.com/aws/aws-sdk-go/aws" 10 "github.com/aws/aws-sdk-go/aws/awserr" 11 "github.com/aws/aws-sdk-go/aws/credentials" 12 "github.com/aws/aws-sdk-go/aws/ec2metadata" 13 "github.com/aws/aws-sdk-go/aws/session" 14 "github.com/hashicorp/go-cleanhttp" 15 "github.com/hashicorp/packer/template/interpolate" 16 ) 17 18 // AccessConfig is for common configuration related to AWS access 19 type AccessConfig struct { 20 AccessKey string `mapstructure:"access_key"` 21 CustomEndpointEc2 string `mapstructure:"custom_endpoint_ec2"` 22 MFACode string `mapstructure:"mfa_code"` 23 ProfileName string `mapstructure:"profile"` 24 RawRegion string `mapstructure:"region"` 25 SecretKey string `mapstructure:"secret_key"` 26 SkipValidation bool `mapstructure:"skip_region_validation"` 27 SkipMetadataApiCheck bool `mapstructure:"skip_metadata_api_check"` 28 Token string `mapstructure:"token"` 29 session *session.Session 30 } 31 32 // Config returns a valid aws.Config object for access to AWS services, or 33 // an error if the authentication and region couldn't be resolved 34 func (c *AccessConfig) Session() (*session.Session, error) { 35 if c.session != nil { 36 return c.session, nil 37 } 38 39 config := aws.NewConfig().WithCredentialsChainVerboseErrors(true) 40 41 staticCreds := credentials.NewStaticCredentials(c.AccessKey, c.SecretKey, c.Token) 42 if _, err := staticCreds.Get(); err != credentials.ErrStaticCredentialsEmpty { 43 config.WithCredentials(staticCreds) 44 } 45 46 if c.RawRegion != "" { 47 config = config.WithRegion(c.RawRegion) 48 } else if region := c.metadataRegion(); region != "" { 49 config = config.WithRegion(region) 50 } 51 52 if c.CustomEndpointEc2 != "" { 53 config = config.WithEndpoint(c.CustomEndpointEc2) 54 } 55 56 opts := session.Options{ 57 SharedConfigState: session.SharedConfigEnable, 58 Config: *config, 59 } 60 61 if c.ProfileName != "" { 62 opts.Profile = c.ProfileName 63 } 64 65 if c.MFACode != "" { 66 opts.AssumeRoleTokenProvider = func() (string, error) { 67 return c.MFACode, nil 68 } 69 } 70 71 if sess, err := session.NewSessionWithOptions(opts); err != nil { 72 return nil, err 73 } else if *sess.Config.Region == "" { 74 return nil, fmt.Errorf("Could not find AWS region, make sure it's set.") 75 } else { 76 log.Printf("Found region %s", *sess.Config.Region) 77 c.session = sess 78 79 cp, err := c.session.Config.Credentials.Get() 80 if err != nil { 81 if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoCredentialProviders" { 82 return nil, fmt.Errorf("No valid credential sources found for AWS Builder. " + 83 "Please see https://www.packer.io/docs/builders/amazon.html#specifying-amazon-credentials " + 84 "for more information on providing credentials for the AWS Builder.") 85 } else { 86 return nil, fmt.Errorf("Error loading credentials for AWS Provider: %s", err) 87 } 88 } 89 log.Printf("[INFO] AWS Auth provider used: %q", cp.ProviderName) 90 } 91 return c.session, nil 92 } 93 94 func (c *AccessConfig) SessionRegion() string { 95 if c.session == nil { 96 panic("access config session should be set.") 97 } 98 return aws.StringValue(c.session.Config.Region) 99 } 100 101 func (c *AccessConfig) IsGovCloud() bool { 102 return strings.HasPrefix(c.SessionRegion(), "us-gov-") 103 } 104 105 func (c *AccessConfig) IsChinaCloud() bool { 106 return strings.HasPrefix(c.SessionRegion(), "cn-") 107 } 108 109 // metadataRegion returns the region from the metadata service 110 func (c *AccessConfig) metadataRegion() string { 111 112 client := cleanhttp.DefaultClient() 113 114 // Keep the default timeout (100ms) low as we don't want to wait in non-EC2 environments 115 client.Timeout = 100 * time.Millisecond 116 ec2meta := ec2metadata.New(session.New(), &aws.Config{ 117 HTTPClient: client, 118 }) 119 region, err := ec2meta.Region() 120 if err != nil { 121 log.Println("Error getting region from metadata service, "+ 122 "probably because we're not running on AWS.", err) 123 return "" 124 } 125 return region 126 } 127 128 func (c *AccessConfig) Prepare(ctx *interpolate.Context) []error { 129 var errs []error 130 131 if c.SkipMetadataApiCheck { 132 log.Println("(WARN) skip_metadata_api_check ignored.") 133 } 134 // Either both access and secret key must be set or neither of them should 135 // be. 136 if (len(c.AccessKey) > 0) != (len(c.SecretKey) > 0) { 137 errs = append(errs, 138 fmt.Errorf("`access_key` and `secret_key` must both be either set or not set.")) 139 } 140 141 if c.RawRegion != "" && !c.SkipValidation { 142 if valid := ValidateRegion(c.RawRegion); !valid { 143 errs = append(errs, fmt.Errorf("Unknown region: %s", c.RawRegion)) 144 } 145 } 146 147 return errs 148 }