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

aws/endpoints: STS regional flag Implementation #2779

Merged
merged 20 commits into from
Oct 23, 2019
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
21 changes: 21 additions & 0 deletions CHANGELOG_PENDING.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
### SDK Features

### SDK Enhancements
* `aws/endpoints`: Adds support for STS Regional Flags ([#2779](https://github.com/aws/aws-sdk-go/pull/2779))
* Implements STS regional flag, with support for `legacy` and `regional` options. Defaults to `legacy`. Legacy, will force all regions specified in aws/endpoints/sts_legacy_regions.go to resolve to the STS global endpoint, sts.amazonaws.com. This is the SDK's current behavior.
* When the flag's value is `regional` the SDK will resolve the endpoint based on the endpoints.json model. This allows STS to update their service's modeled endpoints to be regionalized for all regions. When `regional` turned on use `aws-global` as the region to use the global endpoint.
* `AWS_STS_REGIONAL_ENDPOINTS=regional` for environment, or `sts_regional_endpoints=regional` in shared config file.
* The regions the SDK defaults to the STS global endpoint in `legacy` mode are:
* ap-northeast-1
* ap-south-1
* ap-southeast-1
* ap-southeast-2
* aws-global
* ca-central-1
* eu-central-1
* eu-north-1
* eu-west-1
* eu-west-2
* eu-west-3
* sa-east-1
* us-east-1
* us-east-2
* us-west-1
* us-west-2

### SDK Bugs
6 changes: 3 additions & 3 deletions aws/client/default_retryer.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,19 @@ import (
type DefaultRetryer struct {
// Num max Retries is the number of max retries that will be performed.
// By default, this is zero.
NumMaxRetries int
NumMaxRetries int

// MinRetryDelay is the minimum retry delay after which retry will be performed.
// If not set, the value is 0ns.
MinRetryDelay time.Duration
MinRetryDelay time.Duration

// MinThrottleRetryDelay is the minimum retry delay when throttled.
// If not set, the value is 0ns.
MinThrottleDelay time.Duration

// MaxRetryDelay is the maximum retry delay before which retry must be performed.
// If not set, the value is 0ns.
MaxRetryDelay time.Duration
MaxRetryDelay time.Duration

// MaxThrottleDelay is the maximum retry delay when throttled.
// If not set, the value is 0ns.
Expand Down
2 changes: 1 addition & 1 deletion aws/client/default_retryer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ func TestGetRetryDelay(t *testing.T) {
}

func TestRetryDelay(t *testing.T) {
d := DefaultRetryer{NumMaxRetries:100}
d := DefaultRetryer{NumMaxRetries: 100}
r := request.Request{}
for i := 0; i < 100; i++ {
rTemp := r
Expand Down
14 changes: 14 additions & 0 deletions aws/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ type Config struct {
// Disabling this feature is useful when you want to use local endpoints
// for testing that do not support the modeled host prefix pattern.
DisableEndpointHostPrefix *bool

// STSRegionalEndpoint will enable regional or legacy endpoint resolving
STSRegionalEndpoint endpoints.STSRegionalEndpoint
}

// NewConfig returns a new Config pointer that can be chained with builder
Expand Down Expand Up @@ -420,6 +423,13 @@ func (c *Config) MergeIn(cfgs ...*Config) {
}
}

// WithSTSRegionalEndpoint will set whether or not to use regional endpoint flag
// when resolving the endpoint for a service
func (c *Config) WithSTSRegionalEndpoint(sre endpoints.STSRegionalEndpoint) *Config {
c.STSRegionalEndpoint = sre
return c
}

func mergeInConfig(dst *Config, other *Config) {
if other == nil {
return
Expand Down Expand Up @@ -520,6 +530,10 @@ func mergeInConfig(dst *Config, other *Config) {
if other.DisableEndpointHostPrefix != nil {
dst.DisableEndpointHostPrefix = other.DisableEndpointHostPrefix
}

if other.STSRegionalEndpoint != endpoints.UnsetSTSEndpoint {
dst.STSRegionalEndpoint = other.STSRegionalEndpoint
}
}

// Copy will return a shallow copy of the Config object. If any additional
Expand Down
46 changes: 45 additions & 1 deletion aws/endpoints/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package endpoints
import (
"fmt"
"regexp"
"strings"

"github.com/aws/aws-sdk-go/aws/awserr"
)
Expand Down Expand Up @@ -46,6 +47,43 @@ type Options struct {
//
// This option is ignored if StrictMatching is enabled.
ResolveUnknownService bool

// STS Regional Endpoint flag helps with resolving the STS endpoint
STSRegionalEndpoint STSRegionalEndpoint
}

// STSRegionalEndpoint is an enum type alias for int
// It is used internally by the core sdk as STS Regional Endpoint flag value
type STSRegionalEndpoint int

const (

// UnsetSTSEndpoint represents that STS Regional Endpoint flag is not specified.
UnsetSTSEndpoint STSRegionalEndpoint = iota

// LegacySTSEndpoint represents when STS Regional Endpoint flag is specified
// to use legacy endpoints.
LegacySTSEndpoint

// RegionalSTSEndpoint represents when STS Regional Endpoint flag is specified
// to use regional endpoints.
RegionalSTSEndpoint
)

// GetSTSRegionalEndpoint function returns the STSRegionalEndpointFlag based
// on the input string provided in env config or shared config by the user.
//
// `legacy`, `regional` are the only case-insensitive valid strings for
// resolving the STS regional Endpoint flag.
func GetSTSRegionalEndpoint(s string) (STSRegionalEndpoint, error) {
switch {
case strings.EqualFold(s, "legacy"):
return LegacySTSEndpoint, nil
case strings.EqualFold(s, "regional"):
return RegionalSTSEndpoint, nil
default:
return UnsetSTSEndpoint, fmt.Errorf("unable to resolve the value of STSRegionalEndpoint for %v", s)
}
}

// Set combines all of the option functions together.
Expand Down Expand Up @@ -79,6 +117,12 @@ func ResolveUnknownServiceOption(o *Options) {
o.ResolveUnknownService = true
}

// STSRegionalEndpointOption enables the STS endpoint resolver behavior to resolve
// STS endpoint to their regional endpoint, instead of the global endpoint.
skotambkar marked this conversation as resolved.
Show resolved Hide resolved
func STSRegionalEndpointOption(o *Options) {
skotambkar marked this conversation as resolved.
Show resolved Hide resolved
o.STSRegionalEndpoint = RegionalSTSEndpoint
}

// A Resolver provides the interface for functionality to resolve endpoints.
// The build in Partition and DefaultResolver return value satisfy this interface.
type Resolver interface {
Expand Down Expand Up @@ -194,7 +238,7 @@ func (p Partition) ID() string { return p.id }
// require the provided service and region to be known by the partition.
// If the endpoint cannot be strictly resolved an error will be returned. This
// mode is useful to ensure the endpoint resolved is valid. Without
// StrictMatching enabled the endpoint returned my look valid but may not work.
// StrictMatching enabled the endpoint returned may look valid but may not work.
// StrictMatching requires the SDK to be updated if you want to take advantage
// of new regions and services expansions.
//
Expand Down
20 changes: 20 additions & 0 deletions aws/endpoints/sts_legacy_regions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package endpoints

var stsLegacyGlobalRegions = map[string]struct{}{
"ap-northeast-1": {},
"ap-south-1": {},
"ap-southeast-1": {},
"ap-southeast-2": {},
"aws-global": {},
"ca-central-1": {},
"eu-central-1": {},
"eu-north-1": {},
"eu-west-1": {},
"eu-west-2": {},
"eu-west-3": {},
"sa-east-1": {},
"us-east-1": {},
"us-east-2": {},
"us-west-1": {},
"us-west-2": {},
}
7 changes: 7 additions & 0 deletions aws/endpoints/v3model.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ func (p partition) EndpointFor(service, region string, opts ...func(*Options)) (
var opt Options
opt.Set(opts...)

if service == "sts" && opt.STSRegionalEndpoint != RegionalSTSEndpoint {
if _, ok := stsLegacyGlobalRegions[region]; ok {
region = "aws-global"
}
}

s, hasService := p.Services[service]
if !(hasService || opt.ResolveUnknownService) {
// Only return error if the resolver will not fallback to creating
Expand All @@ -92,6 +98,7 @@ func (p partition) EndpointFor(service, region string, opts ...func(*Options)) (
}

defs := []endpoint{p.Defaults, s.Defaults}

return e.resolve(service, region, p.DNSSuffix, defs, opt), nil
}

Expand Down
69 changes: 69 additions & 0 deletions aws/endpoints/v3model_shared_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package endpoints

import "regexp"

var testPartitions = partitions{
partition{
ID: "part-id",
Name: "partitionName",
DNSSuffix: "amazonaws.com",
RegionRegex: regionRegex{
Regexp: func() *regexp.Regexp {
reg, _ := regexp.Compile("^(us|eu|ap|sa|ca)\\-\\w+\\-\\d+$")
return reg
}(),
},
Defaults: endpoint{
Hostname: "{service}.{region}.{dnsSuffix}",
Protocols: []string{"https"},
SignatureVersions: []string{"v4"},
},
Regions: regions{
"us-east-1": region{
Description: "region description",
},
"us-west-2": region{},
},
Services: services{
"s3": service{},
"service1": service{
Defaults: endpoint{
CredentialScope: credentialScope{
Service: "service1",
},
},
Endpoints: endpoints{
"us-east-1": {},
"us-west-2": {
HasDualStack: boxedTrue,
DualStackHostname: "{service}.dualstack.{region}.{dnsSuffix}",
},
},
},
"service2": service{
Defaults: endpoint{
CredentialScope: credentialScope{
Service: "service2",
},
},
},
"httpService": service{
Defaults: endpoint{
Protocols: []string{"http"},
},
},
"globalService": service{
IsRegionalized: boxedFalse,
PartitionEndpoint: "aws-global",
Endpoints: endpoints{
"aws-global": endpoint{
CredentialScope: credentialScope{
Region: "us-east-1",
},
Hostname: "globalService.amazonaws.com",
},
},
},
},
},
}