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