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