session.go 25 KB

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