resolve_credentials.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627
  1. package config
  2. import (
  3. "context"
  4. "fmt"
  5. "io/ioutil"
  6. "net"
  7. "net/url"
  8. "os"
  9. "time"
  10. "github.com/aws/aws-sdk-go-v2/aws"
  11. "github.com/aws/aws-sdk-go-v2/credentials"
  12. "github.com/aws/aws-sdk-go-v2/credentials/ec2rolecreds"
  13. "github.com/aws/aws-sdk-go-v2/credentials/endpointcreds"
  14. "github.com/aws/aws-sdk-go-v2/credentials/processcreds"
  15. "github.com/aws/aws-sdk-go-v2/credentials/ssocreds"
  16. "github.com/aws/aws-sdk-go-v2/credentials/stscreds"
  17. "github.com/aws/aws-sdk-go-v2/feature/ec2/imds"
  18. "github.com/aws/aws-sdk-go-v2/service/sso"
  19. "github.com/aws/aws-sdk-go-v2/service/ssooidc"
  20. "github.com/aws/aws-sdk-go-v2/service/sts"
  21. )
  22. const (
  23. // valid credential source values
  24. credSourceEc2Metadata = "Ec2InstanceMetadata"
  25. credSourceEnvironment = "Environment"
  26. credSourceECSContainer = "EcsContainer"
  27. httpProviderAuthFileEnvVar = "AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE"
  28. )
  29. // direct representation of the IPv4 address for the ECS container
  30. // "169.254.170.2"
  31. var ecsContainerIPv4 net.IP = []byte{
  32. 169, 254, 170, 2,
  33. }
  34. // direct representation of the IPv4 address for the EKS container
  35. // "169.254.170.23"
  36. var eksContainerIPv4 net.IP = []byte{
  37. 169, 254, 170, 23,
  38. }
  39. // direct representation of the IPv6 address for the EKS container
  40. // "fd00:ec2::23"
  41. var eksContainerIPv6 net.IP = []byte{
  42. 0xFD, 0, 0xE, 0xC2,
  43. 0, 0, 0, 0,
  44. 0, 0, 0, 0,
  45. 0, 0, 0, 0x23,
  46. }
  47. var (
  48. ecsContainerEndpoint = "http://169.254.170.2" // not constant to allow for swapping during unit-testing
  49. )
  50. // resolveCredentials extracts a credential provider from slice of config
  51. // sources.
  52. //
  53. // If an explicit credential provider is not found the resolver will fallback
  54. // to resolving credentials by extracting a credential provider from EnvConfig
  55. // and SharedConfig.
  56. func resolveCredentials(ctx context.Context, cfg *aws.Config, configs configs) error {
  57. found, err := resolveCredentialProvider(ctx, cfg, configs)
  58. if found || err != nil {
  59. return err
  60. }
  61. return resolveCredentialChain(ctx, cfg, configs)
  62. }
  63. // resolveCredentialProvider extracts the first instance of Credentials from the
  64. // config slices.
  65. //
  66. // The resolved CredentialProvider will be wrapped in a cache to ensure the
  67. // credentials are only refreshed when needed. This also protects the
  68. // credential provider to be used concurrently.
  69. //
  70. // Config providers used:
  71. // * credentialsProviderProvider
  72. func resolveCredentialProvider(ctx context.Context, cfg *aws.Config, configs configs) (bool, error) {
  73. credProvider, found, err := getCredentialsProvider(ctx, configs)
  74. if !found || err != nil {
  75. return false, err
  76. }
  77. cfg.Credentials, err = wrapWithCredentialsCache(ctx, configs, credProvider)
  78. if err != nil {
  79. return false, err
  80. }
  81. return true, nil
  82. }
  83. // resolveCredentialChain resolves a credential provider chain using EnvConfig
  84. // and SharedConfig if present in the slice of provided configs.
  85. //
  86. // The resolved CredentialProvider will be wrapped in a cache to ensure the
  87. // credentials are only refreshed when needed. This also protects the
  88. // credential provider to be used concurrently.
  89. func resolveCredentialChain(ctx context.Context, cfg *aws.Config, configs configs) (err error) {
  90. envConfig, sharedConfig, other := getAWSConfigSources(configs)
  91. // When checking if a profile was specified programmatically we should only consider the "other"
  92. // configuration sources that have been provided. This ensures we correctly honor the expected credential
  93. // hierarchy.
  94. _, sharedProfileSet, err := getSharedConfigProfile(ctx, other)
  95. if err != nil {
  96. return err
  97. }
  98. switch {
  99. case sharedProfileSet:
  100. ctx, err = resolveCredsFromProfile(ctx, cfg, envConfig, sharedConfig, other)
  101. case envConfig.Credentials.HasKeys():
  102. ctx = addCredentialSource(ctx, aws.CredentialSourceEnvVars)
  103. cfg.Credentials = credentials.StaticCredentialsProvider{Value: envConfig.Credentials, Source: getCredentialSources(ctx)}
  104. case len(envConfig.WebIdentityTokenFilePath) > 0:
  105. ctx = addCredentialSource(ctx, aws.CredentialSourceEnvVarsSTSWebIDToken)
  106. err = assumeWebIdentity(ctx, cfg, envConfig.WebIdentityTokenFilePath, envConfig.RoleARN, envConfig.RoleSessionName, configs)
  107. default:
  108. ctx, err = resolveCredsFromProfile(ctx, cfg, envConfig, sharedConfig, other)
  109. }
  110. if err != nil {
  111. return err
  112. }
  113. // Wrap the resolved provider in a cache so the SDK will cache credentials.
  114. cfg.Credentials, err = wrapWithCredentialsCache(ctx, configs, cfg.Credentials)
  115. if err != nil {
  116. return err
  117. }
  118. return nil
  119. }
  120. func resolveCredsFromProfile(ctx context.Context, cfg *aws.Config, envConfig *EnvConfig, sharedConfig *SharedConfig, configs configs) (ctx2 context.Context, err error) {
  121. switch {
  122. case sharedConfig.Source != nil:
  123. ctx = addCredentialSource(ctx, aws.CredentialSourceProfileSourceProfile)
  124. // Assume IAM role with credentials source from a different profile.
  125. ctx, err = resolveCredsFromProfile(ctx, cfg, envConfig, sharedConfig.Source, configs)
  126. case sharedConfig.Credentials.HasKeys():
  127. // Static Credentials from Shared Config/Credentials file.
  128. ctx = addCredentialSource(ctx, aws.CredentialSourceProfile)
  129. cfg.Credentials = credentials.StaticCredentialsProvider{
  130. Value: sharedConfig.Credentials,
  131. Source: getCredentialSources(ctx),
  132. }
  133. case len(sharedConfig.CredentialSource) != 0:
  134. ctx = addCredentialSource(ctx, aws.CredentialSourceProfileNamedProvider)
  135. ctx, err = resolveCredsFromSource(ctx, cfg, envConfig, sharedConfig, configs)
  136. case len(sharedConfig.WebIdentityTokenFile) != 0:
  137. // Credentials from Assume Web Identity token require an IAM Role, and
  138. // that roll will be assumed. May be wrapped with another assume role
  139. // via SourceProfile.
  140. ctx = addCredentialSource(ctx, aws.CredentialSourceProfileSTSWebIDToken)
  141. return ctx, assumeWebIdentity(ctx, cfg, sharedConfig.WebIdentityTokenFile, sharedConfig.RoleARN, sharedConfig.RoleSessionName, configs)
  142. case sharedConfig.hasSSOConfiguration():
  143. if sharedConfig.hasLegacySSOConfiguration() {
  144. ctx = addCredentialSource(ctx, aws.CredentialSourceProfileSSOLegacy)
  145. ctx = addCredentialSource(ctx, aws.CredentialSourceSSOLegacy)
  146. } else {
  147. ctx = addCredentialSource(ctx, aws.CredentialSourceSSO)
  148. }
  149. if sharedConfig.SSOSession != nil {
  150. ctx = addCredentialSource(ctx, aws.CredentialSourceProfileSSO)
  151. }
  152. err = resolveSSOCredentials(ctx, cfg, sharedConfig, configs)
  153. case len(sharedConfig.CredentialProcess) != 0:
  154. // Get credentials from CredentialProcess
  155. ctx = addCredentialSource(ctx, aws.CredentialSourceProfileProcess)
  156. ctx = addCredentialSource(ctx, aws.CredentialSourceProcess)
  157. err = processCredentials(ctx, cfg, sharedConfig, configs)
  158. case len(envConfig.ContainerCredentialsRelativePath) != 0:
  159. ctx = addCredentialSource(ctx, aws.CredentialSourceHTTP)
  160. err = resolveHTTPCredProvider(ctx, cfg, ecsContainerURI(envConfig.ContainerCredentialsRelativePath), envConfig.ContainerAuthorizationToken, configs)
  161. case len(envConfig.ContainerCredentialsEndpoint) != 0:
  162. ctx = addCredentialSource(ctx, aws.CredentialSourceHTTP)
  163. err = resolveLocalHTTPCredProvider(ctx, cfg, envConfig.ContainerCredentialsEndpoint, envConfig.ContainerAuthorizationToken, configs)
  164. default:
  165. ctx = addCredentialSource(ctx, aws.CredentialSourceIMDS)
  166. err = resolveEC2RoleCredentials(ctx, cfg, configs)
  167. }
  168. if err != nil {
  169. return ctx, err
  170. }
  171. if len(sharedConfig.RoleARN) > 0 {
  172. return ctx, credsFromAssumeRole(ctx, cfg, sharedConfig, configs)
  173. }
  174. return ctx, nil
  175. }
  176. func resolveSSOCredentials(ctx context.Context, cfg *aws.Config, sharedConfig *SharedConfig, configs configs) error {
  177. if err := sharedConfig.validateSSOConfiguration(); err != nil {
  178. return err
  179. }
  180. var options []func(*ssocreds.Options)
  181. v, found, err := getSSOProviderOptions(ctx, configs)
  182. if err != nil {
  183. return err
  184. }
  185. if found {
  186. options = append(options, v)
  187. }
  188. cfgCopy := cfg.Copy()
  189. options = append(options, func(o *ssocreds.Options) {
  190. o.CredentialSources = getCredentialSources(ctx)
  191. })
  192. if sharedConfig.SSOSession != nil {
  193. ssoTokenProviderOptionsFn, found, err := getSSOTokenProviderOptions(ctx, configs)
  194. if err != nil {
  195. return fmt.Errorf("failed to get SSOTokenProviderOptions from config sources, %w", err)
  196. }
  197. var optFns []func(*ssocreds.SSOTokenProviderOptions)
  198. if found {
  199. optFns = append(optFns, ssoTokenProviderOptionsFn)
  200. }
  201. cfgCopy.Region = sharedConfig.SSOSession.SSORegion
  202. cachedPath, err := ssocreds.StandardCachedTokenFilepath(sharedConfig.SSOSession.Name)
  203. if err != nil {
  204. return err
  205. }
  206. oidcClient := ssooidc.NewFromConfig(cfgCopy)
  207. tokenProvider := ssocreds.NewSSOTokenProvider(oidcClient, cachedPath, optFns...)
  208. options = append(options, func(o *ssocreds.Options) {
  209. o.SSOTokenProvider = tokenProvider
  210. o.CachedTokenFilepath = cachedPath
  211. })
  212. } else {
  213. cfgCopy.Region = sharedConfig.SSORegion
  214. }
  215. cfg.Credentials = ssocreds.New(sso.NewFromConfig(cfgCopy), sharedConfig.SSOAccountID, sharedConfig.SSORoleName, sharedConfig.SSOStartURL, options...)
  216. return nil
  217. }
  218. func ecsContainerURI(path string) string {
  219. return fmt.Sprintf("%s%s", ecsContainerEndpoint, path)
  220. }
  221. func processCredentials(ctx context.Context, cfg *aws.Config, sharedConfig *SharedConfig, configs configs) error {
  222. var opts []func(*processcreds.Options)
  223. options, found, err := getProcessCredentialOptions(ctx, configs)
  224. if err != nil {
  225. return err
  226. }
  227. if found {
  228. opts = append(opts, options)
  229. }
  230. opts = append(opts, func(o *processcreds.Options) {
  231. o.CredentialSources = getCredentialSources(ctx)
  232. })
  233. cfg.Credentials = processcreds.NewProvider(sharedConfig.CredentialProcess, opts...)
  234. return nil
  235. }
  236. // isAllowedHost allows host to be loopback or known ECS/EKS container IPs
  237. //
  238. // host can either be an IP address OR an unresolved hostname - resolution will
  239. // be automatically performed in the latter case
  240. func isAllowedHost(host string) (bool, error) {
  241. if ip := net.ParseIP(host); ip != nil {
  242. return isIPAllowed(ip), nil
  243. }
  244. addrs, err := lookupHostFn(host)
  245. if err != nil {
  246. return false, err
  247. }
  248. for _, addr := range addrs {
  249. if ip := net.ParseIP(addr); ip == nil || !isIPAllowed(ip) {
  250. return false, nil
  251. }
  252. }
  253. return true, nil
  254. }
  255. func isIPAllowed(ip net.IP) bool {
  256. return ip.IsLoopback() ||
  257. ip.Equal(ecsContainerIPv4) ||
  258. ip.Equal(eksContainerIPv4) ||
  259. ip.Equal(eksContainerIPv6)
  260. }
  261. func resolveLocalHTTPCredProvider(ctx context.Context, cfg *aws.Config, endpointURL, authToken string, configs configs) error {
  262. var resolveErr error
  263. parsed, err := url.Parse(endpointURL)
  264. if err != nil {
  265. resolveErr = fmt.Errorf("invalid URL, %w", err)
  266. } else {
  267. host := parsed.Hostname()
  268. if len(host) == 0 {
  269. resolveErr = fmt.Errorf("unable to parse host from local HTTP cred provider URL")
  270. } else if parsed.Scheme == "http" {
  271. if isAllowedHost, allowHostErr := isAllowedHost(host); allowHostErr != nil {
  272. resolveErr = fmt.Errorf("failed to resolve host %q, %v", host, allowHostErr)
  273. } else if !isAllowedHost {
  274. resolveErr = fmt.Errorf("invalid endpoint host, %q, only loopback/ecs/eks hosts are allowed", host)
  275. }
  276. }
  277. }
  278. if resolveErr != nil {
  279. return resolveErr
  280. }
  281. return resolveHTTPCredProvider(ctx, cfg, endpointURL, authToken, configs)
  282. }
  283. func resolveHTTPCredProvider(ctx context.Context, cfg *aws.Config, url, authToken string, configs configs) error {
  284. optFns := []func(*endpointcreds.Options){
  285. func(options *endpointcreds.Options) {
  286. if len(authToken) != 0 {
  287. options.AuthorizationToken = authToken
  288. }
  289. if authFilePath := os.Getenv(httpProviderAuthFileEnvVar); authFilePath != "" {
  290. options.AuthorizationTokenProvider = endpointcreds.TokenProviderFunc(func() (string, error) {
  291. var contents []byte
  292. var err error
  293. if contents, err = ioutil.ReadFile(authFilePath); err != nil {
  294. return "", fmt.Errorf("failed to read authorization token from %v: %v", authFilePath, err)
  295. }
  296. return string(contents), nil
  297. })
  298. }
  299. options.APIOptions = cfg.APIOptions
  300. if cfg.Retryer != nil {
  301. options.Retryer = cfg.Retryer()
  302. }
  303. options.CredentialSources = getCredentialSources(ctx)
  304. },
  305. }
  306. optFn, found, err := getEndpointCredentialProviderOptions(ctx, configs)
  307. if err != nil {
  308. return err
  309. }
  310. if found {
  311. optFns = append(optFns, optFn)
  312. }
  313. provider := endpointcreds.New(url, optFns...)
  314. cfg.Credentials, err = wrapWithCredentialsCache(ctx, configs, provider, func(options *aws.CredentialsCacheOptions) {
  315. options.ExpiryWindow = 5 * time.Minute
  316. })
  317. if err != nil {
  318. return err
  319. }
  320. return nil
  321. }
  322. func resolveCredsFromSource(ctx context.Context, cfg *aws.Config, envConfig *EnvConfig, sharedCfg *SharedConfig, configs configs) (context.Context, error) {
  323. switch sharedCfg.CredentialSource {
  324. case credSourceEc2Metadata:
  325. ctx = addCredentialSource(ctx, aws.CredentialSourceIMDS)
  326. return ctx, resolveEC2RoleCredentials(ctx, cfg, configs)
  327. case credSourceEnvironment:
  328. ctx = addCredentialSource(ctx, aws.CredentialSourceHTTP)
  329. cfg.Credentials = credentials.StaticCredentialsProvider{Value: envConfig.Credentials, Source: getCredentialSources(ctx)}
  330. case credSourceECSContainer:
  331. ctx = addCredentialSource(ctx, aws.CredentialSourceHTTP)
  332. if len(envConfig.ContainerCredentialsRelativePath) != 0 {
  333. return ctx, resolveHTTPCredProvider(ctx, cfg, ecsContainerURI(envConfig.ContainerCredentialsRelativePath), envConfig.ContainerAuthorizationToken, configs)
  334. }
  335. if len(envConfig.ContainerCredentialsEndpoint) != 0 {
  336. return ctx, resolveLocalHTTPCredProvider(ctx, cfg, envConfig.ContainerCredentialsEndpoint, envConfig.ContainerAuthorizationToken, configs)
  337. }
  338. return ctx, fmt.Errorf("EcsContainer was specified as the credential_source, but neither 'AWS_CONTAINER_CREDENTIALS_RELATIVE_URI' or AWS_CONTAINER_CREDENTIALS_FULL_URI' was set")
  339. default:
  340. return ctx, fmt.Errorf("credential_source values must be EcsContainer, Ec2InstanceMetadata, or Environment")
  341. }
  342. return ctx, nil
  343. }
  344. func resolveEC2RoleCredentials(ctx context.Context, cfg *aws.Config, configs configs) error {
  345. optFns := make([]func(*ec2rolecreds.Options), 0, 2)
  346. optFn, found, err := getEC2RoleCredentialProviderOptions(ctx, configs)
  347. if err != nil {
  348. return err
  349. }
  350. if found {
  351. optFns = append(optFns, optFn)
  352. }
  353. optFns = append(optFns, func(o *ec2rolecreds.Options) {
  354. // Only define a client from config if not already defined.
  355. if o.Client == nil {
  356. o.Client = imds.NewFromConfig(*cfg)
  357. }
  358. o.CredentialSources = getCredentialSources(ctx)
  359. })
  360. provider := ec2rolecreds.New(optFns...)
  361. cfg.Credentials, err = wrapWithCredentialsCache(ctx, configs, provider)
  362. if err != nil {
  363. return err
  364. }
  365. return nil
  366. }
  367. func getAWSConfigSources(cfgs configs) (*EnvConfig, *SharedConfig, configs) {
  368. var (
  369. envConfig *EnvConfig
  370. sharedConfig *SharedConfig
  371. other configs
  372. )
  373. for i := range cfgs {
  374. switch c := cfgs[i].(type) {
  375. case EnvConfig:
  376. if envConfig == nil {
  377. envConfig = &c
  378. }
  379. case *EnvConfig:
  380. if envConfig == nil {
  381. envConfig = c
  382. }
  383. case SharedConfig:
  384. if sharedConfig == nil {
  385. sharedConfig = &c
  386. }
  387. case *SharedConfig:
  388. if envConfig == nil {
  389. sharedConfig = c
  390. }
  391. default:
  392. other = append(other, c)
  393. }
  394. }
  395. if envConfig == nil {
  396. envConfig = &EnvConfig{}
  397. }
  398. if sharedConfig == nil {
  399. sharedConfig = &SharedConfig{}
  400. }
  401. return envConfig, sharedConfig, other
  402. }
  403. // AssumeRoleTokenProviderNotSetError is an error returned when creating a
  404. // session when the MFAToken option is not set when shared config is configured
  405. // load assume a role with an MFA token.
  406. type AssumeRoleTokenProviderNotSetError struct{}
  407. // Error is the error message
  408. func (e AssumeRoleTokenProviderNotSetError) Error() string {
  409. return fmt.Sprintf("assume role with MFA enabled, but AssumeRoleTokenProvider session option not set.")
  410. }
  411. func assumeWebIdentity(ctx context.Context, cfg *aws.Config, filepath string, roleARN, sessionName string, configs configs) error {
  412. if len(filepath) == 0 {
  413. return fmt.Errorf("token file path is not set")
  414. }
  415. optFns := []func(*stscreds.WebIdentityRoleOptions){
  416. func(options *stscreds.WebIdentityRoleOptions) {
  417. options.RoleSessionName = sessionName
  418. },
  419. }
  420. optFn, found, err := getWebIdentityCredentialProviderOptions(ctx, configs)
  421. if err != nil {
  422. return err
  423. }
  424. if found {
  425. optFns = append(optFns, optFn)
  426. }
  427. opts := stscreds.WebIdentityRoleOptions{
  428. RoleARN: roleARN,
  429. }
  430. optFns = append(optFns, func(options *stscreds.WebIdentityRoleOptions) {
  431. options.CredentialSources = getCredentialSources(ctx)
  432. })
  433. for _, fn := range optFns {
  434. fn(&opts)
  435. }
  436. if len(opts.RoleARN) == 0 {
  437. return fmt.Errorf("role ARN is not set")
  438. }
  439. client := opts.Client
  440. if client == nil {
  441. client = sts.NewFromConfig(*cfg)
  442. }
  443. provider := stscreds.NewWebIdentityRoleProvider(client, roleARN, stscreds.IdentityTokenFile(filepath), optFns...)
  444. cfg.Credentials = provider
  445. return nil
  446. }
  447. func credsFromAssumeRole(ctx context.Context, cfg *aws.Config, sharedCfg *SharedConfig, configs configs) (err error) {
  448. // resolve credentials early
  449. credentialSources := getCredentialSources(ctx)
  450. optFns := []func(*stscreds.AssumeRoleOptions){
  451. func(options *stscreds.AssumeRoleOptions) {
  452. options.RoleSessionName = sharedCfg.RoleSessionName
  453. if sharedCfg.RoleDurationSeconds != nil {
  454. if *sharedCfg.RoleDurationSeconds/time.Minute > 15 {
  455. options.Duration = *sharedCfg.RoleDurationSeconds
  456. }
  457. }
  458. // Assume role with external ID
  459. if len(sharedCfg.ExternalID) > 0 {
  460. options.ExternalID = aws.String(sharedCfg.ExternalID)
  461. }
  462. // Assume role with MFA
  463. if len(sharedCfg.MFASerial) != 0 {
  464. options.SerialNumber = aws.String(sharedCfg.MFASerial)
  465. }
  466. // add existing credential chain
  467. options.CredentialSources = credentialSources
  468. },
  469. }
  470. optFn, found, err := getAssumeRoleCredentialProviderOptions(ctx, configs)
  471. if err != nil {
  472. return err
  473. }
  474. if found {
  475. optFns = append(optFns, optFn)
  476. }
  477. {
  478. // Synthesize options early to validate configuration errors sooner to ensure a token provider
  479. // is present if the SerialNumber was set.
  480. var o stscreds.AssumeRoleOptions
  481. for _, fn := range optFns {
  482. fn(&o)
  483. }
  484. if o.TokenProvider == nil && o.SerialNumber != nil {
  485. return AssumeRoleTokenProviderNotSetError{}
  486. }
  487. }
  488. cfg.Credentials = stscreds.NewAssumeRoleProvider(sts.NewFromConfig(*cfg), sharedCfg.RoleARN, optFns...)
  489. return nil
  490. }
  491. // wrapWithCredentialsCache will wrap provider with an aws.CredentialsCache
  492. // with the provided options if the provider is not already a
  493. // aws.CredentialsCache.
  494. func wrapWithCredentialsCache(
  495. ctx context.Context,
  496. cfgs configs,
  497. provider aws.CredentialsProvider,
  498. optFns ...func(options *aws.CredentialsCacheOptions),
  499. ) (aws.CredentialsProvider, error) {
  500. _, ok := provider.(*aws.CredentialsCache)
  501. if ok {
  502. return provider, nil
  503. }
  504. credCacheOptions, optionsFound, err := getCredentialsCacheOptionsProvider(ctx, cfgs)
  505. if err != nil {
  506. return nil, err
  507. }
  508. // force allocation of a new slice if the additional options are
  509. // needed, to prevent overwriting the passed in slice of options.
  510. optFns = optFns[:len(optFns):len(optFns)]
  511. if optionsFound {
  512. optFns = append(optFns, credCacheOptions)
  513. }
  514. return aws.NewCredentialsCache(provider, optFns...), nil
  515. }
  516. // credentialSource stores the chain of providers that was used to create an instance of
  517. // a credentials provider on the context
  518. type credentialSource struct{}
  519. func addCredentialSource(ctx context.Context, source aws.CredentialSource) context.Context {
  520. existing, ok := ctx.Value(credentialSource{}).([]aws.CredentialSource)
  521. if !ok {
  522. existing = []aws.CredentialSource{source}
  523. } else {
  524. existing = append(existing, source)
  525. }
  526. return context.WithValue(ctx, credentialSource{}, existing)
  527. }
  528. func getCredentialSources(ctx context.Context) []aws.CredentialSource {
  529. return ctx.Value(credentialSource{}).([]aws.CredentialSource)
  530. }