Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stabilize the selection of region from partition in AWS Auth #8161

Merged
merged 2 commits into from
Feb 14, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 17 additions & 7 deletions builtin/credential/aws/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,11 @@ type backend struct {
// will be flushed. The empty STS role signifies the master account
IAMClientsMap map[string]map[string]*iam.IAM

// Map to associate a partition to a random region in that partition. Users of
// this don't care what region in the partition they use, but there is some client
// cache efficiency gain if we keep the mapping stable, hence caching a single copy.
partitionToRegionMap map[string]*endpoints.Region

// Map of AWS unique IDs to the full ARN corresponding to that unique ID
// This avoids the overhead of an AWS API hit for every login request
// using the IAM auth method when bound_iam_principal_arn contains a wildcard
Expand Down Expand Up @@ -144,6 +149,8 @@ func Backend(_ *logical.BackendConfig) (*backend, error) {
Clean: b.cleanup,
}

b.partitionToRegionMap = generatePartitionToRegionMap()

return b, nil
}

Expand Down Expand Up @@ -249,7 +256,7 @@ func (b *backend) resolveArnToRealUniqueId(ctx context.Context, s logical.Storag
// partition, and passing that region back back to the SDK, so that the SDK can figure out the
// proper partition from the arbitrary region we passed in to look up the endpoint.
// Sigh
region := getAnyRegionForAwsPartition(entity.Partition)
region := b.partitionToRegionMap[entity.Partition]
if region == nil {
return "", fmt.Errorf("unable to resolve partition %q to a region", entity.Partition)
}
Expand Down Expand Up @@ -293,18 +300,21 @@ func (b *backend) resolveArnToRealUniqueId(ctx context.Context, s logical.Storag

// Adapted from https://docs.aws.amazon.com/sdk-for-go/api/aws/endpoints/
// the "Enumerating Regions and Endpoint Metadata" section
func getAnyRegionForAwsPartition(partitionId string) *endpoints.Region {
func generatePartitionToRegionMap() map[string]*endpoints.Region {
partitionToRegion := make(map[string]*endpoints.Region)

resolver := endpoints.DefaultResolver()
partitions := resolver.(endpoints.EnumPartitions).Partitions()

for _, p := range partitions {
if p.ID() == partitionId {
for _, r := range p.Regions() {
return &r
}
// Choose a single region randomly from the partition
for _, r := range p.Regions() {
partitionToRegion[p.ID()] = &r
break
}
}
return nil

return partitionToRegion
}

const backendHelp = `
Expand Down
8 changes: 7 additions & 1 deletion builtin/credential/aws/path_login.go
Original file line number Diff line number Diff line change
Expand Up @@ -1650,7 +1650,13 @@ func (e *iamEntity) canonicalArn() string {
// This returns the "full" ARN of an iamEntity, how it would be referred to in AWS proper
func (b *backend) fullArn(ctx context.Context, e *iamEntity, s logical.Storage) (string, error) {
// Not assuming path is reliable for any entity types
client, err := b.clientIAM(ctx, s, getAnyRegionForAwsPartition(e.Partition).ID(), e.AccountNumber)

region := b.partitionToRegionMap[e.Partition]
if region == nil {
return "", fmt.Errorf("unable to resolve partition %q to a region", e.Partition)
}

client, err := b.clientIAM(ctx, s, region.ID(), e.AccountNumber)
if err != nil {
return "", errwrap.Wrapf("error creating IAM client: {{err}}", err)
}
Expand Down