Skip to content

Commit

Permalink
Merge ee92f23 into 15745d8
Browse files Browse the repository at this point in the history
  • Loading branch information
cjyclaire committed Oct 23, 2019
2 parents 15745d8 + ee92f23 commit 5f7951f
Show file tree
Hide file tree
Showing 10 changed files with 282 additions and 6 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
@@ -1,6 +1,8 @@
Unreleased Changes
------------------

* Feature - Aws::Core - Support enable STS regional endpoints by `sts_regional_endpoints: 'regional'`

2.11.379 (2019-10-22)
------------------

Expand Down
1 change: 1 addition & 0 deletions aws-sdk-core/lib/aws-sdk-core.rb
Expand Up @@ -327,6 +327,7 @@ module Plugins
autoload :S3RequestSigner, 'aws-sdk-core/plugins/s3_request_signer'
autoload :S3SseCpk, 'aws-sdk-core/plugins/s3_sse_cpk'
autoload :S3UrlEncodedKeys, 'aws-sdk-core/plugins/s3_url_encoded_keys'
autoload :STSRegionalEndpoints, 'aws-sdk-core/plugins/sts_regional_endpoints'
autoload :SQSQueueUrls, 'aws-sdk-core/plugins/sqs_queue_urls'
autoload :SQSMd5s, 'aws-sdk-core/plugins/sqs_md5s'
autoload :StubResponses, 'aws-sdk-core/plugins/stub_responses'
Expand Down
4 changes: 4 additions & 0 deletions aws-sdk-core/lib/aws-sdk-core/api/customizations.rb
Expand Up @@ -274,6 +274,10 @@ def is_eventstream?(api, shape_name)
Aws::Plugins::S3RequestSigner
))

plugins('AWS Security Token Service', add: %w(
Aws::Plugins::STSRegionalEndpoints
))

plugins('AWS S3 Control', add: %w(
Aws::Plugins::S3HostId
Aws::Plugins::S3ControlDns
Expand Down
39 changes: 33 additions & 6 deletions aws-sdk-core/lib/aws-sdk-core/endpoint_provider.rb
Expand Up @@ -2,12 +2,34 @@ module Aws
# @api private
class EndpointProvider

# when sts_regional_endpoint set to `legacy`
# endpoint pattern stays global for
# following regions
STS_LEGACY_REGIONS = %w(
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
)

def initialize(rules)
@rules = rules
end

def resolve(region, service)
"https://" + endpoint_for(region, service)
def resolve(region, service, sts_regional_endpoints = nil)
"https://" + endpoint_for(region, service, sts_regional_endpoints)
end

def signing_region(region, service)
Expand All @@ -27,16 +49,21 @@ def dns_suffix_for(region)

private

def endpoint_for(region, service)
def endpoint_for(region, service, sts_regional_endpoints)
partition = get_partition(region)
endpoint = default_endpoint(partition, service, region)
service_cfg = partition.fetch("services", {}).fetch(service, {})

# Check for service-level default endpoint.
endpoint = service_cfg.fetch("defaults", {}).fetch("hostname", endpoint)

# Check for sts legacy behavior
sts_legacy = service == 'sts' &&
sts_regional_endpoints == 'legacy' &&
STS_LEGACY_REGIONS.include?(region)

# Check for global endpoint.
if service_cfg["isRegionalized"] == false
if sts_legacy || service_cfg["isRegionalized"] == false
region = service_cfg.fetch("partitionEndpoint", region)
end

Expand Down Expand Up @@ -81,8 +108,8 @@ def default_partition

class << self

def resolve(region, service)
default_provider.resolve(region, service)
def resolve(region, service, sts_regional_endpoints = nil)
default_provider.resolve(region, service, sts_regional_endpoints)
end

def signing_region(region, service)
Expand Down
2 changes: 2 additions & 0 deletions aws-sdk-core/lib/aws-sdk-core/plugins/regional_endpoint.rb
Expand Up @@ -26,6 +26,8 @@ class RegionalEndpoint < Seahorse::Client::Plugin
endpoint_prefix = cfg.api.metadata['endpointPrefix']
if cfg.region && endpoint_prefix
EndpointProvider.resolve(cfg.region, endpoint_prefix)
sts_regional = cfg.respond_to?(:sts_regional_endpoints) ? cfg.sts_regional_endpoints : nil
EndpointProvider.resolve(cfg.region, endpoint_prefix, sts_regional)
end
end

Expand Down
30 changes: 30 additions & 0 deletions aws-sdk-core/lib/aws-sdk-core/plugins/sts_regional_endpoints.rb
@@ -0,0 +1,30 @@
module Aws
module Plugins

class STSRegionalEndpoints < Seahorse::Client::Plugin

option(:sts_regional_endpoints,
default: 'legacy',
doc_type: String,
docstring: <<-DOCS) do |cfg|
Passing in 'regional' to enable regional endpoint for STS for all supported
regions (except 'aws-global'), defaults to 'legacy' mode, using global endpoint
for legacy regions.
DOCS
resolve_sts_regional_endpoints(cfg)
end

private

def self.resolve_sts_regional_endpoints(cfg)
env_mode = ENV['AWS_STS_REGIONAL_ENDPOINTS']
env_mode = nil if env_mode == ''
cfg_mode = Aws.shared_config.sts_regional_endpoints(
profile: cfg.profile)
env_mode || cfg_mode || 'legacy'
end

end

end
end
15 changes: 15 additions & 0 deletions aws-sdk-core/lib/aws-sdk-core/shared_config.rb
Expand Up @@ -128,6 +128,21 @@ def region(opts = {})
end
end

def sts_regional_endpoints(opts = {})
p = opts[:profile] || @profile_name
if @config_enabled
if @parsed_credentials
mode = @parsed_credentials.fetch(p, {})["sts_regional_endpoints"]
end
if @parsed_config
mode ||= @parsed_config.fetch(p, {})["sts_regional_endpoints"]
end
mode
else
nil
end
end

def endpoint_discovery(opts = {})
p = opts[:profile] || @profile_name
if @config_enabled && @parsed_config
Expand Down
20 changes: 20 additions & 0 deletions aws-sdk-core/spec/aws/shared_config_spec.rb
Expand Up @@ -110,6 +110,26 @@ module Aws
expect(config.endpoint_discovery).to eq("false")
end

context 'sts_regional_endpoints selection' do

it 'can resolve sts_regional_endpoints from config file' do
config = SharedConfig.new(
config_path: mock_config_file,
config_enabled: true,
profile_name: "sts_regional"
)
expect(config.sts_regional_endpoints).to eq('regional')

config = SharedConfig.new(
config_path: mock_config_file,
config_enabled: true,
profile_name: "sts_legacy"
)
expect(config.sts_regional_endpoints).to eq('legacy')
end

end

end
end
end
165 changes: 165 additions & 0 deletions aws-sdk-core/spec/aws/sts/sts_regional_endpoints_spec.rb
@@ -0,0 +1,165 @@
require_relative '../../spec_helper'

module Aws
module STS
describe Client do

describe ':sts_regional_endpoints' do

let(:mock_config_file) {
File.expand_path(File.join(File.dirname(__FILE__),
'..', 'fixtures', 'credentials', 'mock_shared_config'))
}

it 'uses ENV before shared config' do
ENV['AWS_STS_REGIONAL_ENDPOINTS'] = 'regional'
config = SharedConfig.new(
config_path: mock_config_file,
config_enabled: true,
profile_name: "sts_legacy"
)

allow(Aws).to receive(:shared_config).and_return(config)
client = Client.new(
stub_responses: true,
region: 'us-west-2'
)
expect(client.config.sts_regional_endpoints).to eq('regional')
end

it 'defaults to `legacy`' do
client = Client.new(
stub_responses: true,
region: 'us-west-2'
)
expect(client.config.sts_regional_endpoints).to eq('legacy')
resp = client.get_caller_identity
expect(resp.context.http_request.endpoint.to_s).to eq(
'https://sts.amazonaws.com')
end

it 'can be set `regional` in the constructor' do
client = Client.new(
stub_responses: true,
sts_regional_endpoints: 'regional',
region: 'us-west-2'
)
expect(client.config.sts_regional_endpoints).to eq('regional')
resp = client.get_caller_identity
expect(resp.context.http_request.endpoint.to_s).to eq(
'https://sts.us-west-2.amazonaws.com')
end

it 'can be set fron ENV' do
ENV['AWS_STS_REGIONAL_ENDPOINTS'] = 'regional'
client = Client.new(
stub_responses: true,
region: 'us-west-2'
)
expect(client.config.sts_regional_endpoints).to eq('regional')
resp = client.get_caller_identity
expect(resp.context.http_request.endpoint.to_s).to eq(
'https://sts.us-west-2.amazonaws.com')
end

it 'has no effect on fips endpoint' do
client = Client.new(
stub_responses: true,
region: 'us-west-2-fips'
)
expect(client.config.sts_regional_endpoints).to eq('legacy')
resp = client.get_caller_identity
expect(resp.context.http_request.endpoint.to_s).to eq(
'https://sts-fips.us-west-2.amazonaws.com')

client = Client.new(
stub_responses: true,
sts_regional_endpoints: 'regional',
region: 'us-west-2-fips'
)
resp = client.get_caller_identity
expect(resp.context.http_request.endpoint.to_s).to eq(
'https://sts-fips.us-west-2.amazonaws.com')
end

it 'has no effect on aws-global even when `regional`' do
client = Client.new(
stub_responses: true,
sts_regional_endpoints: 'regional',
region: 'aws-global'
)
expect(client.config.sts_regional_endpoints).to eq('regional')
resp = client.get_caller_identity
expect(resp.context.http_request.endpoint.to_s).to eq(
'https://sts.amazonaws.com')
end

it 'has no effect on current regionalized regions' do
client = Client.new(
stub_responses: true,
region: 'ap-east-1'
)
expect(client.config.sts_regional_endpoints).to eq('legacy')
resp = client.get_caller_identity
expect(resp.context.http_request.endpoint.to_s).to eq(
'https://sts.ap-east-1.amazonaws.com')

client = Client.new(
stub_responses: true,
sts_regional_endpoints: 'regional',
region: 'ap-east-1'
)
expect(client.config.sts_regional_endpoints).to eq('regional')
resp = client.get_caller_identity
expect(resp.context.http_request.endpoint.to_s).to eq(
'https://sts.ap-east-1.amazonaws.com')
end

it 'has no effect on cn-north-1 region' do
client = Client.new(
stub_responses: true,
region: 'cn-north-1'
)
expect(client.config.sts_regional_endpoints).to eq('legacy')
resp = client.get_caller_identity
expect(resp.context.http_request.endpoint.to_s).to eq(
'https://sts.cn-north-1.amazonaws.com.cn')

client = Client.new(
stub_responses: true,
sts_regional_endpoints: 'regional',
region: 'cn-north-1'
)
expect(client.config.sts_regional_endpoints).to eq('regional')
resp = client.get_caller_identity
expect(resp.context.http_request.endpoint.to_s).to eq(
'https://sts.cn-north-1.amazonaws.com.cn')
end

it 'configures properly at config' do
client = Client.new(
stub_responses: true,
region: 'us-west-2'
)
expect(client.config.sts_regional_endpoints).to eq('legacy')
expect(client.config.region).to eq('us-west-2')
expect(client.config.sigv4_region).to eq('us-east-1')
expect(client.config.endpoint.to_s).to eq('https://sts.amazonaws.com')

client = Client.new(
stub_responses: true,
sts_regional_endpoints: 'regional',
region: 'us-west-2'
)
expect(client.config.sts_regional_endpoints).to eq('regional')
expect(client.config.region).to eq('us-west-2')
expect(client.config.sigv4_region).to eq('us-west-2')
expect(client.config.endpoint.to_s).to eq(
'https://sts.us-west-2.amazonaws.com')
end

end

end
end
end
10 changes: 10 additions & 0 deletions aws-sdk-core/spec/fixtures/credentials/mock_shared_config
Expand Up @@ -78,3 +78,13 @@ endpoint_discovery_enabled = true
aws_access_key_id = AKID
aws_secret_access_key = SECRET
endpoint_discovery_enabled = false

[profile sts_regional]
aws_access_key_id = AKID
aws_secret_access_key = SECRET
sts_regional_endpoints = regional

[profile sts_legacy]
aws_access_key_id = AKID
aws_secret_access_key = SECRET
sts_regional_endpoints = legacy

0 comments on commit 5f7951f

Please sign in to comment.