]> git.immae.eu Git - github/fretlink/terraform-provider-statuscake.git/blob - vendor/github.com/aws/aws-sdk-go/aws/session/session.go
Merge branch 'master' of /Users/jake/terraform
[github/fretlink/terraform-provider-statuscake.git] / vendor / github.com / aws / aws-sdk-go / aws / session / session.go
1 package session
2
3 import (
4 "crypto/tls"
5 "crypto/x509"
6 "fmt"
7 "io"
8 "io/ioutil"
9 "net/http"
10 "os"
11
12 "github.com/aws/aws-sdk-go/aws"
13 "github.com/aws/aws-sdk-go/aws/awserr"
14 "github.com/aws/aws-sdk-go/aws/client"
15 "github.com/aws/aws-sdk-go/aws/corehandlers"
16 "github.com/aws/aws-sdk-go/aws/credentials"
17 "github.com/aws/aws-sdk-go/aws/credentials/stscreds"
18 "github.com/aws/aws-sdk-go/aws/defaults"
19 "github.com/aws/aws-sdk-go/aws/endpoints"
20 "github.com/aws/aws-sdk-go/aws/request"
21 )
22
23 // A Session provides a central location to create service clients from and
24 // store configurations and request handlers for those services.
25 //
26 // Sessions are safe to create service clients concurrently, but it is not safe
27 // to mutate the Session concurrently.
28 //
29 // The Session satisfies the service client's client.ClientConfigProvider.
30 type Session struct {
31 Config *aws.Config
32 Handlers request.Handlers
33 }
34
35 // New creates a new instance of the handlers merging in the provided configs
36 // on top of the SDK's default configurations. Once the Session is created it
37 // can be mutated to modify the Config or Handlers. The Session is safe to be
38 // read concurrently, but it should not be written to concurrently.
39 //
40 // If the AWS_SDK_LOAD_CONFIG environment is set to a truthy value, the New
41 // method could now encounter an error when loading the configuration. When
42 // The environment variable is set, and an error occurs, New will return a
43 // session that will fail all requests reporting the error that occurred while
44 // loading the session. Use NewSession to get the error when creating the
45 // session.
46 //
47 // If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value
48 // the shared config file (~/.aws/config) will also be loaded, in addition to
49 // the shared credentials file (~/.aws/credentials). Values set in both the
50 // shared config, and shared credentials will be taken from the shared
51 // credentials file.
52 //
53 // Deprecated: Use NewSession functions to create sessions instead. NewSession
54 // has the same functionality as New except an error can be returned when the
55 // func is called instead of waiting to receive an error until a request is made.
56 func New(cfgs ...*aws.Config) *Session {
57 // load initial config from environment
58 envCfg := loadEnvConfig()
59
60 if envCfg.EnableSharedConfig {
61 s, err := newSession(Options{}, envCfg, cfgs...)
62 if err != nil {
63 // Old session.New expected all errors to be discovered when
64 // a request is made, and would report the errors then. This
65 // needs to be replicated if an error occurs while creating
66 // the session.
67 msg := "failed to create session with AWS_SDK_LOAD_CONFIG enabled. " +
68 "Use session.NewSession to handle errors occurring during session creation."
69
70 // Session creation failed, need to report the error and prevent
71 // any requests from succeeding.
72 s = &Session{Config: defaults.Config()}
73 s.Config.MergeIn(cfgs...)
74 s.Config.Logger.Log("ERROR:", msg, "Error:", err)
75 s.Handlers.Validate.PushBack(func(r *request.Request) {
76 r.Error = err
77 })
78 }
79 return s
80 }
81
82 return deprecatedNewSession(cfgs...)
83 }
84
85 // NewSession returns a new Session created from SDK defaults, config files,
86 // environment, and user provided config files. Once the Session is created
87 // it can be mutated to modify the Config or Handlers. The Session is safe to
88 // be read concurrently, but it should not be written to concurrently.
89 //
90 // If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value
91 // the shared config file (~/.aws/config) will also be loaded in addition to
92 // the shared credentials file (~/.aws/credentials). Values set in both the
93 // shared config, and shared credentials will be taken from the shared
94 // credentials file. Enabling the Shared Config will also allow the Session
95 // to be built with retrieving credentials with AssumeRole set in the config.
96 //
97 // See the NewSessionWithOptions func for information on how to override or
98 // control through code how the Session will be created. Such as specifying the
99 // config profile, and controlling if shared config is enabled or not.
100 func NewSession(cfgs ...*aws.Config) (*Session, error) {
101 opts := Options{}
102 opts.Config.MergeIn(cfgs...)
103
104 return NewSessionWithOptions(opts)
105 }
106
107 // SharedConfigState provides the ability to optionally override the state
108 // of the session's creation based on the shared config being enabled or
109 // disabled.
110 type SharedConfigState int
111
112 const (
113 // SharedConfigStateFromEnv does not override any state of the
114 // AWS_SDK_LOAD_CONFIG env var. It is the default value of the
115 // SharedConfigState type.
116 SharedConfigStateFromEnv SharedConfigState = iota
117
118 // SharedConfigDisable overrides the AWS_SDK_LOAD_CONFIG env var value
119 // and disables the shared config functionality.
120 SharedConfigDisable
121
122 // SharedConfigEnable overrides the AWS_SDK_LOAD_CONFIG env var value
123 // and enables the shared config functionality.
124 SharedConfigEnable
125 )
126
127 // Options provides the means to control how a Session is created and what
128 // configuration values will be loaded.
129 //
130 type Options struct {
131 // Provides config values for the SDK to use when creating service clients
132 // and making API requests to services. Any value set in with this field
133 // will override the associated value provided by the SDK defaults,
134 // environment or config files where relevant.
135 //
136 // If not set, configuration values from from SDK defaults, environment,
137 // config will be used.
138 Config aws.Config
139
140 // Overrides the config profile the Session should be created from. If not
141 // set the value of the environment variable will be loaded (AWS_PROFILE,
142 // or AWS_DEFAULT_PROFILE if the Shared Config is enabled).
143 //
144 // If not set and environment variables are not set the "default"
145 // (DefaultSharedConfigProfile) will be used as the profile to load the
146 // session config from.
147 Profile string
148
149 // Instructs how the Session will be created based on the AWS_SDK_LOAD_CONFIG
150 // environment variable. By default a Session will be created using the
151 // value provided by the AWS_SDK_LOAD_CONFIG environment variable.
152 //
153 // Setting this value to SharedConfigEnable or SharedConfigDisable
154 // will allow you to override the AWS_SDK_LOAD_CONFIG environment variable
155 // and enable or disable the shared config functionality.
156 SharedConfigState SharedConfigState
157
158 // When the SDK's shared config is configured to assume a role with MFA
159 // this option is required in order to provide the mechanism that will
160 // retrieve the MFA token. There is no default value for this field. If
161 // it is not set an error will be returned when creating the session.
162 //
163 // This token provider will be called when ever the assumed role's
164 // credentials need to be refreshed. Within the context of service clients
165 // all sharing the same session the SDK will ensure calls to the token
166 // provider are atomic. When sharing a token provider across multiple
167 // sessions additional synchronization logic is needed to ensure the
168 // token providers do not introduce race conditions. It is recommend to
169 // share the session where possible.
170 //
171 // stscreds.StdinTokenProvider is a basic implementation that will prompt
172 // from stdin for the MFA token code.
173 //
174 // This field is only used if the shared configuration is enabled, and
175 // the config enables assume role wit MFA via the mfa_serial field.
176 AssumeRoleTokenProvider func() (string, error)
177
178 // Reader for a custom Credentials Authority (CA) bundle in PEM format that
179 // the SDK will use instead of the default system's root CA bundle. Use this
180 // only if you want to replace the CA bundle the SDK uses for TLS requests.
181 //
182 // Enabling this option will attempt to merge the Transport into the SDK's HTTP
183 // client. If the client's Transport is not a http.Transport an error will be
184 // returned. If the Transport's TLS config is set this option will cause the SDK
185 // to overwrite the Transport's TLS config's RootCAs value. If the CA
186 // bundle reader contains multiple certificates all of them will be loaded.
187 //
188 // The Session option CustomCABundle is also available when creating sessions
189 // to also enable this feature. CustomCABundle session option field has priority
190 // over the AWS_CA_BUNDLE environment variable, and will be used if both are set.
191 CustomCABundle io.Reader
192 }
193
194 // NewSessionWithOptions returns a new Session created from SDK defaults, config files,
195 // environment, and user provided config files. This func uses the Options
196 // values to configure how the Session is created.
197 //
198 // If the AWS_SDK_LOAD_CONFIG environment variable is set to a truthy value
199 // the shared config file (~/.aws/config) will also be loaded in addition to
200 // the shared credentials file (~/.aws/credentials). Values set in both the
201 // shared config, and shared credentials will be taken from the shared
202 // credentials file. Enabling the Shared Config will also allow the Session
203 // to be built with retrieving credentials with AssumeRole set in the config.
204 //
205 // // Equivalent to session.New
206 // sess := session.Must(session.NewSessionWithOptions(session.Options{}))
207 //
208 // // Specify profile to load for the session's config
209 // sess := session.Must(session.NewSessionWithOptions(session.Options{
210 // Profile: "profile_name",
211 // }))
212 //
213 // // Specify profile for config and region for requests
214 // sess := session.Must(session.NewSessionWithOptions(session.Options{
215 // Config: aws.Config{Region: aws.String("us-east-1")},
216 // Profile: "profile_name",
217 // }))
218 //
219 // // Force enable Shared Config support
220 // sess := session.Must(session.NewSessionWithOptions(session.Options{
221 // SharedConfigState: session.SharedConfigEnable,
222 // }))
223 func NewSessionWithOptions(opts Options) (*Session, error) {
224 var envCfg envConfig
225 if opts.SharedConfigState == SharedConfigEnable {
226 envCfg = loadSharedEnvConfig()
227 } else {
228 envCfg = loadEnvConfig()
229 }
230
231 if len(opts.Profile) > 0 {
232 envCfg.Profile = opts.Profile
233 }
234
235 switch opts.SharedConfigState {
236 case SharedConfigDisable:
237 envCfg.EnableSharedConfig = false
238 case SharedConfigEnable:
239 envCfg.EnableSharedConfig = true
240 }
241
242 // Only use AWS_CA_BUNDLE if session option is not provided.
243 if len(envCfg.CustomCABundle) != 0 && opts.CustomCABundle == nil {
244 f, err := os.Open(envCfg.CustomCABundle)
245 if err != nil {
246 return nil, awserr.New("LoadCustomCABundleError",
247 "failed to open custom CA bundle PEM file", err)
248 }
249 defer f.Close()
250 opts.CustomCABundle = f
251 }
252
253 return newSession(opts, envCfg, &opts.Config)
254 }
255
256 // Must is a helper function to ensure the Session is valid and there was no
257 // error when calling a NewSession function.
258 //
259 // This helper is intended to be used in variable initialization to load the
260 // Session and configuration at startup. Such as:
261 //
262 // var sess = session.Must(session.NewSession())
263 func Must(sess *Session, err error) *Session {
264 if err != nil {
265 panic(err)
266 }
267
268 return sess
269 }
270
271 func deprecatedNewSession(cfgs ...*aws.Config) *Session {
272 cfg := defaults.Config()
273 handlers := defaults.Handlers()
274
275 // Apply the passed in configs so the configuration can be applied to the
276 // default credential chain
277 cfg.MergeIn(cfgs...)
278 if cfg.EndpointResolver == nil {
279 // An endpoint resolver is required for a session to be able to provide
280 // endpoints for service client configurations.
281 cfg.EndpointResolver = endpoints.DefaultResolver()
282 }
283 cfg.Credentials = defaults.CredChain(cfg, handlers)
284
285 // Reapply any passed in configs to override credentials if set
286 cfg.MergeIn(cfgs...)
287
288 s := &Session{
289 Config: cfg,
290 Handlers: handlers,
291 }
292
293 initHandlers(s)
294
295 return s
296 }
297
298 func newSession(opts Options, envCfg envConfig, cfgs ...*aws.Config) (*Session, error) {
299 cfg := defaults.Config()
300 handlers := defaults.Handlers()
301
302 // Get a merged version of the user provided config to determine if
303 // credentials were.
304 userCfg := &aws.Config{}
305 userCfg.MergeIn(cfgs...)
306
307 // Order config files will be loaded in with later files overwriting
308 // previous config file values.
309 cfgFiles := []string{envCfg.SharedConfigFile, envCfg.SharedCredentialsFile}
310 if !envCfg.EnableSharedConfig {
311 // The shared config file (~/.aws/config) is only loaded if instructed
312 // to load via the envConfig.EnableSharedConfig (AWS_SDK_LOAD_CONFIG).
313 cfgFiles = cfgFiles[1:]
314 }
315
316 // Load additional config from file(s)
317 sharedCfg, err := loadSharedConfig(envCfg.Profile, cfgFiles)
318 if err != nil {
319 return nil, err
320 }
321
322 if err := mergeConfigSrcs(cfg, userCfg, envCfg, sharedCfg, handlers, opts); err != nil {
323 return nil, err
324 }
325
326 s := &Session{
327 Config: cfg,
328 Handlers: handlers,
329 }
330
331 initHandlers(s)
332
333 // Setup HTTP client with custom cert bundle if enabled
334 if opts.CustomCABundle != nil {
335 if err := loadCustomCABundle(s, opts.CustomCABundle); err != nil {
336 return nil, err
337 }
338 }
339
340 return s, nil
341 }
342
343 func loadCustomCABundle(s *Session, bundle io.Reader) error {
344 var t *http.Transport
345 switch v := s.Config.HTTPClient.Transport.(type) {
346 case *http.Transport:
347 t = v
348 default:
349 if s.Config.HTTPClient.Transport != nil {
350 return awserr.New("LoadCustomCABundleError",
351 "unable to load custom CA bundle, HTTPClient's transport unsupported type", nil)
352 }
353 }
354 if t == nil {
355 t = &http.Transport{}
356 }
357
358 p, err := loadCertPool(bundle)
359 if err != nil {
360 return err
361 }
362 if t.TLSClientConfig == nil {
363 t.TLSClientConfig = &tls.Config{}
364 }
365 t.TLSClientConfig.RootCAs = p
366
367 s.Config.HTTPClient.Transport = t
368
369 return nil
370 }
371
372 func loadCertPool(r io.Reader) (*x509.CertPool, error) {
373 b, err := ioutil.ReadAll(r)
374 if err != nil {
375 return nil, awserr.New("LoadCustomCABundleError",
376 "failed to read custom CA bundle PEM file", err)
377 }
378
379 p := x509.NewCertPool()
380 if !p.AppendCertsFromPEM(b) {
381 return nil, awserr.New("LoadCustomCABundleError",
382 "failed to load custom CA bundle PEM file", err)
383 }
384
385 return p, nil
386 }
387
388 func mergeConfigSrcs(cfg, userCfg *aws.Config, envCfg envConfig, sharedCfg sharedConfig, handlers request.Handlers, sessOpts Options) error {
389 // Merge in user provided configuration
390 cfg.MergeIn(userCfg)
391
392 // Region if not already set by user
393 if len(aws.StringValue(cfg.Region)) == 0 {
394 if len(envCfg.Region) > 0 {
395 cfg.WithRegion(envCfg.Region)
396 } else if envCfg.EnableSharedConfig && len(sharedCfg.Region) > 0 {
397 cfg.WithRegion(sharedCfg.Region)
398 }
399 }
400
401 // Configure credentials if not already set
402 if cfg.Credentials == credentials.AnonymousCredentials && userCfg.Credentials == nil {
403 if len(envCfg.Creds.AccessKeyID) > 0 {
404 cfg.Credentials = credentials.NewStaticCredentialsFromCreds(
405 envCfg.Creds,
406 )
407 } else if envCfg.EnableSharedConfig && len(sharedCfg.AssumeRole.RoleARN) > 0 && sharedCfg.AssumeRoleSource != nil {
408 cfgCp := *cfg
409 cfgCp.Credentials = credentials.NewStaticCredentialsFromCreds(
410 sharedCfg.AssumeRoleSource.Creds,
411 )
412 if len(sharedCfg.AssumeRole.MFASerial) > 0 && sessOpts.AssumeRoleTokenProvider == nil {
413 // AssumeRole Token provider is required if doing Assume Role
414 // with MFA.
415 return AssumeRoleTokenProviderNotSetError{}
416 }
417 cfg.Credentials = stscreds.NewCredentials(
418 &Session{
419 Config: &cfgCp,
420 Handlers: handlers.Copy(),
421 },
422 sharedCfg.AssumeRole.RoleARN,
423 func(opt *stscreds.AssumeRoleProvider) {
424 opt.RoleSessionName = sharedCfg.AssumeRole.RoleSessionName
425
426 // Assume role with external ID
427 if len(sharedCfg.AssumeRole.ExternalID) > 0 {
428 opt.ExternalID = aws.String(sharedCfg.AssumeRole.ExternalID)
429 }
430
431 // Assume role with MFA
432 if len(sharedCfg.AssumeRole.MFASerial) > 0 {
433 opt.SerialNumber = aws.String(sharedCfg.AssumeRole.MFASerial)
434 opt.TokenProvider = sessOpts.AssumeRoleTokenProvider
435 }
436 },
437 )
438 } else if len(sharedCfg.Creds.AccessKeyID) > 0 {
439 cfg.Credentials = credentials.NewStaticCredentialsFromCreds(
440 sharedCfg.Creds,
441 )
442 } else {
443 // Fallback to default credentials provider, include mock errors
444 // for the credential chain so user can identify why credentials
445 // failed to be retrieved.
446 cfg.Credentials = credentials.NewCredentials(&credentials.ChainProvider{
447 VerboseErrors: aws.BoolValue(cfg.CredentialsChainVerboseErrors),
448 Providers: []credentials.Provider{
449 &credProviderError{Err: awserr.New("EnvAccessKeyNotFound", "failed to find credentials in the environment.", nil)},
450 &credProviderError{Err: awserr.New("SharedCredsLoad", fmt.Sprintf("failed to load profile, %s.", envCfg.Profile), nil)},
451 defaults.RemoteCredProvider(*cfg, handlers),
452 },
453 })
454 }
455 }
456
457 return nil
458 }
459
460 // AssumeRoleTokenProviderNotSetError is an error returned when creating a session when the
461 // MFAToken option is not set when shared config is configured load assume a
462 // role with an MFA token.
463 type AssumeRoleTokenProviderNotSetError struct{}
464
465 // Code is the short id of the error.
466 func (e AssumeRoleTokenProviderNotSetError) Code() string {
467 return "AssumeRoleTokenProviderNotSetError"
468 }
469
470 // Message is the description of the error
471 func (e AssumeRoleTokenProviderNotSetError) Message() string {
472 return fmt.Sprintf("assume role with MFA enabled, but AssumeRoleTokenProvider session option not set.")
473 }
474
475 // OrigErr is the underlying error that caused the failure.
476 func (e AssumeRoleTokenProviderNotSetError) OrigErr() error {
477 return nil
478 }
479
480 // Error satisfies the error interface.
481 func (e AssumeRoleTokenProviderNotSetError) Error() string {
482 return awserr.SprintError(e.Code(), e.Message(), "", nil)
483 }
484
485 type credProviderError struct {
486 Err error
487 }
488
489 var emptyCreds = credentials.Value{}
490
491 func (c credProviderError) Retrieve() (credentials.Value, error) {
492 return credentials.Value{}, c.Err
493 }
494 func (c credProviderError) IsExpired() bool {
495 return true
496 }
497
498 func initHandlers(s *Session) {
499 // Add the Validate parameter handler if it is not disabled.
500 s.Handlers.Validate.Remove(corehandlers.ValidateParametersHandler)
501 if !aws.BoolValue(s.Config.DisableParamValidation) {
502 s.Handlers.Validate.PushBackNamed(corehandlers.ValidateParametersHandler)
503 }
504 }
505
506 // Copy creates and returns a copy of the current Session, coping the config
507 // and handlers. If any additional configs are provided they will be merged
508 // on top of the Session's copied config.
509 //
510 // // Create a copy of the current Session, configured for the us-west-2 region.
511 // sess.Copy(&aws.Config{Region: aws.String("us-west-2")})
512 func (s *Session) Copy(cfgs ...*aws.Config) *Session {
513 newSession := &Session{
514 Config: s.Config.Copy(cfgs...),
515 Handlers: s.Handlers.Copy(),
516 }
517
518 initHandlers(newSession)
519
520 return newSession
521 }
522
523 // ClientConfig satisfies the client.ConfigProvider interface and is used to
524 // configure the service client instances. Passing the Session to the service
525 // client's constructor (New) will use this method to configure the client.
526 func (s *Session) ClientConfig(serviceName string, cfgs ...*aws.Config) client.Config {
527 // Backwards compatibility, the error will be eaten if user calls ClientConfig
528 // directly. All SDK services will use ClientconfigWithError.
529 cfg, _ := s.clientConfigWithErr(serviceName, cfgs...)
530
531 return cfg
532 }
533
534 func (s *Session) clientConfigWithErr(serviceName string, cfgs ...*aws.Config) (client.Config, error) {
535 s = s.Copy(cfgs...)
536
537 var resolved endpoints.ResolvedEndpoint
538 var err error
539
540 region := aws.StringValue(s.Config.Region)
541
542 if endpoint := aws.StringValue(s.Config.Endpoint); len(endpoint) != 0 {
543 resolved.URL = endpoints.AddScheme(endpoint, aws.BoolValue(s.Config.DisableSSL))
544 resolved.SigningRegion = region
545 } else {
546 resolved, err = s.Config.EndpointResolver.EndpointFor(
547 serviceName, region,
548 func(opt *endpoints.Options) {
549 opt.DisableSSL = aws.BoolValue(s.Config.DisableSSL)
550 opt.UseDualStack = aws.BoolValue(s.Config.UseDualStack)
551
552 // Support the condition where the service is modeled but its
553 // endpoint metadata is not available.
554 opt.ResolveUnknownService = true
555 },
556 )
557 }
558
559 return client.Config{
560 Config: s.Config,
561 Handlers: s.Handlers,
562 Endpoint: resolved.URL,
563 SigningRegion: resolved.SigningRegion,
564 SigningName: resolved.SigningName,
565 }, err
566 }
567
568 // ClientConfigNoResolveEndpoint is the same as ClientConfig with the exception
569 // that the EndpointResolver will not be used to resolve the endpoint. The only
570 // endpoint set must come from the aws.Config.Endpoint field.
571 func (s *Session) ClientConfigNoResolveEndpoint(cfgs ...*aws.Config) client.Config {
572 s = s.Copy(cfgs...)
573
574 var resolved endpoints.ResolvedEndpoint
575
576 region := aws.StringValue(s.Config.Region)
577
578 if ep := aws.StringValue(s.Config.Endpoint); len(ep) > 0 {
579 resolved.URL = endpoints.AddScheme(ep, aws.BoolValue(s.Config.DisableSSL))
580 resolved.SigningRegion = region
581 }
582
583 return client.Config{
584 Config: s.Config,
585 Handlers: s.Handlers,
586 Endpoint: resolved.URL,
587 SigningRegion: resolved.SigningRegion,
588 SigningName: resolved.SigningName,
589 }
590 }