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 18 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
3 changes: 3 additions & 0 deletions CHANGELOG_PENDING.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
### SDK Features

### SDK Enhancements
* `aws/endpoints`: Adds support for STS Regional Flags ([#2779](https://github.com/aws/aws-sdk-go/pull/2779))
* Adds unit test cases for STS Regional flags to test STS endpoint resolver when flag is set to `legacy` or `regional` or is `unset`.
skotambkar marked this conversation as resolved.
Show resolved Hide resolved
* Adds error handling when loading environment config from sharedConfig or envConfig.

### 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",
},
},
},
},
},
}
Loading