Repository: hashicorp/vault
File: builtin/logical/aws/client.go (Go)

Code before:
		configs = append(configs, &aws.Config{
			Credentials: creds,
			Region:      aws.String(credsConfig.Region),
			Endpoint:    aws.String(endpoints[i]),
			MaxRetries:  aws.Int(maxRetries),
			HTTPClient:  cleanhttp.DefaultClient(),
		})
	}

	return configs, nil
}

func (b *backend) nonCachedClientIAM(ctx context.Context, s logical.Storage, logger hclog.Logger, entry *staticRoleEntry) (*iam.IAM, error) {
	var awsConfig *aws.Config
	var err error

	if entry != nil && entry.AssumeRoleARN != "" {
		awsConfig, err = b.assumeRoleStatic(ctx, s, entry)
		if err != nil {
			return nil, fmt.Errorf("failed to assume role %q: %w", entry.AssumeRoleARN, err)
		}
	} else {
		configs, err := b.getRootConfigs(ctx, s, "iam", logger)
		if err != nil {
			return nil, err
		}
		if len(configs) != 1 {
			return nil, errors.New("could not obtain aws config")
		}
		awsConfig = configs[0]
	}

	sess, err := session.NewSession(awsConfig)
	if err != nil {
		return nil, err
	}
	client := iam.New(sess)
	if client == nil {
		return nil, fmt.Errorf("could not obtain IAM client")
	}
	return client, nil
}

func (b *backend) nonCachedClientSTS(ctx context.Context, s logical.Storage, logger hclog.Logger) (*sts.STS, error) {
	awsConfig, err := b.getRootConfigs(ctx, s, "sts", logger)
	if err != nil {
		return nil, err
	}

	var client *sts.STS


Review comment (suggestion):
It is possible for no endpoint to be supplied even if a region was - in particular in the IAM case, which expects no endpoint unless a third-party reimplementer of IAM is being used.

Code after:
		}

		sessionSuffix := strconv.FormatInt(time.Now().UnixNano(), 10)
		credsConfig.RoleSessionName = fmt.Sprintf("vault-aws-secrets-%s", sessionSuffix)
		credsConfig.WebIdentityTokenFetcher = fetcher
		credsConfig.RoleARN = config.RoleARN

		// explicitly disable environment and shared credential providers when using Web Identity Token Fetcher
		// enables WIF usage in environments that may use AWS Profiles or environment variables for other use-cases
		opts = append(opts, awsutil.WithEnvironmentCredentials(false), awsutil.WithSharedCredentials(false))
	}

	// at this point, in the IAM case,
	// - regions contains config.Region, if it was set.
	// - endpoints contains iam_endpoint, if it was set.
	// in the sts case,
	// - regions contains sts_region, if it was set, then sts_fallback_regions in order, if they were set.
	// - endpoints contains sts_endpoint, if it was set, then sts_fallback_endpoints in order, if they were set.

	// case in which nothing was supplied
	if len(regions) == 0 {
		// fallback region is in descending order, AWS_REGION, or AWS_DEFAULT_REGION, or us-east-1
		regions = append(regions, fallbackRegion)
	}

	if len(endpoints) == 0 {
		for _, v := range regions {
			endpoints = append(endpoints, matchingSTSEndpoint(v))
		}
	}

	// for this approach of using parallel arrays to part out the configs, we want equal numbers of regions and endpoints
	if len(regions) != len(endpoints) {
		return nil, errors.New("number of regions does not match number of endpoints")
	}

	for i := 0; i < len(endpoints); i++ {
		if len(regions) > i {
			credsConfig.Region = regions[i]
		} else {
			credsConfig.Region = fallbackRegion
		}
		creds, err := credsConfig.GenerateCredentialChain(opts...)
		if err != nil {
			return nil, err
		}
		configs = append(configs, &aws.Config{
			Credentials: creds,
			Region:      aws.String(credsConfig.Region),
			Endpoint:    aws.String(endpoints[i]),
			MaxRetries:  aws.Int(maxRetries),