# Copyright 2014 Amazon.com, Inc. or its affiliates. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"). You # may not use this file except in compliance with the License. A copy of # the License is located at # # http://aws.amazon.com/apache2.0/ # # or in the "license" file accompanying this file. This file is # distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF # ANY KIND, either express or implied. See the License for the specific # language governing permissions and limitations under the License. from tests import unittest, BaseSessionTest, create_session import mock from nose.tools import assert_equals from botocore import regions from botocore.exceptions import UnknownEndpointError from botocore.exceptions import NoRegionError # NOTE: sqs endpoint updated to be the CN in the SSL cert because # a bug in python2.6 prevents subjectAltNames from being parsed # and subsequently being used in cert validation. # Same thing is needed for rds. KNOWN_REGIONS = { "us-east-1": { "cloudformation": "cloudformation.us-east-1.amazonaws.com", "cloudfront": "cloudfront.amazonaws.com", "cloudsearch": "cloudsearch.us-east-1.amazonaws.com", "cloudtrail": "cloudtrail.us-east-1.amazonaws.com", "monitoring": "monitoring.us-east-1.amazonaws.com", "dynamodb": "dynamodb.us-east-1.amazonaws.com", "ec2": "ec2.us-east-1.amazonaws.com", "elasticmapreduce": "elasticmapreduce.us-east-1.amazonaws.com", "elasticache": "elasticache.us-east-1.amazonaws.com", "rds": "rds.amazonaws.com", "route53": "route53.amazonaws.com", "email": "email.us-east-1.amazonaws.com", "sdb": "sdb.amazonaws.com", "sns": "sns.us-east-1.amazonaws.com", "sqs": "queue.amazonaws.com", "s3": "s3.amazonaws.com", "autoscaling": "autoscaling.us-east-1.amazonaws.com", "elasticbeanstalk": "elasticbeanstalk.us-east-1.amazonaws.com", "iam": "iam.amazonaws.com", "importexport": "importexport.amazonaws.com", "sts": "sts.amazonaws.com", "storagegateway": "storagegateway.us-east-1.amazonaws.com", "support": "support.us-east-1.amazonaws.com", "elasticloadbalancing": "elasticloadbalancing.us-east-1.amazonaws.com", "swf": "swf.us-east-1.amazonaws.com", "glacier": "glacier.us-east-1.amazonaws.com", "directconnect": "directconnect.us-east-1.amazonaws.com", "datapipeline": "datapipeline.us-east-1.amazonaws.com", "redshift": "redshift.us-east-1.amazonaws.com", "kinesis": "kinesis.us-east-1.amazonaws.com", "opsworks": "opsworks.us-east-1.amazonaws.com", "elastictranscoder": "elastictranscoder.us-east-1.amazonaws.com", }, "us-west-1": { "cloudformation": "cloudformation.us-west-1.amazonaws.com", "cloudfront": "cloudfront.amazonaws.com", "cloudsearch": "cloudsearch.us-west-1.amazonaws.com", "monitoring": "monitoring.us-west-1.amazonaws.com", "dynamodb": "dynamodb.us-west-1.amazonaws.com", "ec2": "ec2.us-west-1.amazonaws.com", "elasticmapreduce": "us-west-1.elasticmapreduce.amazonaws.com", "elasticache": "elasticache.us-west-1.amazonaws.com", "rds": "rds.us-west-1.amazonaws.com", "route53": "route53.amazonaws.com", "sdb": "sdb.us-west-1.amazonaws.com", "sns": "sns.us-west-1.amazonaws.com", "sqs": "us-west-1.queue.amazonaws.com", "s3": "s3-us-west-1.amazonaws.com", "autoscaling": "autoscaling.us-west-1.amazonaws.com", "elasticbeanstalk": "elasticbeanstalk.us-west-1.amazonaws.com", "iam": "iam.amazonaws.com", "importexport": "importexport.amazonaws.com", "sts": "sts.amazonaws.com", "storagegateway": "storagegateway.us-west-1.amazonaws.com", "elasticloadbalancing": "elasticloadbalancing.us-west-1.amazonaws.com", "swf": "swf.us-west-1.amazonaws.com", "glacier": "glacier.us-west-1.amazonaws.com", "directconnect": "directconnect.us-west-1.amazonaws.com", "elastictranscoder": "elastictranscoder.us-west-1.amazonaws.com", }, "us-west-2": { "cloudformation": "cloudformation.us-west-2.amazonaws.com", "cloudfront": "cloudfront.amazonaws.com", "cloudsearch": "cloudsearch.us-west-2.amazonaws.com", "cloudtrail": "cloudtrail.us-west-2.amazonaws.com", "monitoring": "monitoring.us-west-2.amazonaws.com", "dynamodb": "dynamodb.us-west-2.amazonaws.com", "ec2": "ec2.us-west-2.amazonaws.com", "elasticmapreduce": "us-west-2.elasticmapreduce.amazonaws.com", "elasticache": "elasticache.us-west-2.amazonaws.com", "rds": "rds.us-west-2.amazonaws.com", "route53": "route53.amazonaws.com", "sdb": "sdb.us-west-2.amazonaws.com", "sns": "sns.us-west-2.amazonaws.com", "sqs": "us-west-2.queue.amazonaws.com", "s3": "s3-us-west-2.amazonaws.com", "autoscaling": "autoscaling.us-west-2.amazonaws.com", "elasticbeanstalk": "elasticbeanstalk.us-west-2.amazonaws.com", "iam": "iam.amazonaws.com", "importexport": "importexport.amazonaws.com", "sts": "sts.amazonaws.com", "storagegateway": "storagegateway.us-west-2.amazonaws.com", "elasticloadbalancing": "elasticloadbalancing.us-west-2.amazonaws.com", "swf": "swf.us-west-2.amazonaws.com", "glacier": "glacier.us-west-2.amazonaws.com", "directconnect": "directconnect.us-west-2.amazonaws.com", "redshift": "redshift.us-west-2.amazonaws.com", "elastictranscoder": "elastictranscoder.us-west-2.amazonaws.com", }, "ap-northeast-1": { "cloudformation": "cloudformation.ap-northeast-1.amazonaws.com", "cloudfront": "cloudfront.amazonaws.com", "monitoring": "monitoring.ap-northeast-1.amazonaws.com", "dynamodb": "dynamodb.ap-northeast-1.amazonaws.com", "ec2": "ec2.ap-northeast-1.amazonaws.com", "elasticmapreduce": "ap-northeast-1.elasticmapreduce.amazonaws.com", "elasticache": "elasticache.ap-northeast-1.amazonaws.com", "rds": "rds.ap-northeast-1.amazonaws.com", "route53": "route53.amazonaws.com", "sdb": "sdb.ap-northeast-1.amazonaws.com", "sns": "sns.ap-northeast-1.amazonaws.com", "sqs": "ap-northeast-1.queue.amazonaws.com", "s3": "s3-ap-northeast-1.amazonaws.com", "autoscaling": "autoscaling.ap-northeast-1.amazonaws.com", "elasticbeanstalk": "elasticbeanstalk.ap-northeast-1.amazonaws.com", "iam": "iam.amazonaws.com", "importexport": "importexport.amazonaws.com", "sts": "sts.amazonaws.com", "storagegateway": "storagegateway.ap-northeast-1.amazonaws.com", "elasticloadbalancing": "elasticloadbalancing.ap-northeast-1.amazonaws.com", "swf": "swf.ap-northeast-1.amazonaws.com", "glacier": "glacier.ap-northeast-1.amazonaws.com", "directconnect": "directconnect.ap-northeast-1.amazonaws.com", "redshift": "redshift.ap-northeast-1.amazonaws.com", "elastictranscoder": "elastictranscoder.ap-northeast-1.amazonaws.com", }, "ap-southeast-1": { "cloudformation": "cloudformation.ap-southeast-1.amazonaws.com", "cloudfront": "cloudfront.amazonaws.com", "cloudsearch": "cloudsearch.ap-southeast-1.amazonaws.com", "monitoring": "monitoring.ap-southeast-1.amazonaws.com", "dynamodb": "dynamodb.ap-southeast-1.amazonaws.com", "ec2": "ec2.ap-southeast-1.amazonaws.com", "elasticmapreduce": "ap-southeast-1.elasticmapreduce.amazonaws.com", "elasticache": "elasticache.ap-southeast-1.amazonaws.com", "rds": "rds.ap-southeast-1.amazonaws.com", "route53": "route53.amazonaws.com", "sdb": "sdb.ap-southeast-1.amazonaws.com", "sns": "sns.ap-southeast-1.amazonaws.com", "sqs": "ap-southeast-1.queue.amazonaws.com", "s3": "s3-ap-southeast-1.amazonaws.com", "autoscaling": "autoscaling.ap-southeast-1.amazonaws.com", "elasticbeanstalk": "elasticbeanstalk.ap-southeast-1.amazonaws.com", "iam": "iam.amazonaws.com", "importexport": "importexport.amazonaws.com", "sts": "sts.amazonaws.com", "storagegateway": "storagegateway.ap-southeast-1.amazonaws.com", "elasticloadbalancing": "elasticloadbalancing.ap-southeast-1.amazonaws.com", "swf": "swf.ap-southeast-1.amazonaws.com", "directconnect": "directconnect.ap-southeast-1.amazonaws.com", "redshift": "redshift.ap-southeast-1.amazonaws.com", "elastictranscoder": "elastictranscoder.ap-southeast-1.amazonaws.com", }, "ap-southeast-2": { "cloudformation": "cloudformation.ap-southeast-2.amazonaws.com", "cloudfront": "cloudfront.amazonaws.com", "monitoring": "monitoring.ap-southeast-2.amazonaws.com", "dynamodb": "dynamodb.ap-southeast-2.amazonaws.com", "ec2": "ec2.ap-southeast-2.amazonaws.com", "elasticmapreduce": "ap-southeast-2.elasticmapreduce.amazonaws.com", "elasticache": "elasticache.ap-southeast-2.amazonaws.com", "rds": "rds.ap-southeast-2.amazonaws.com", "route53": "route53.amazonaws.com", "sdb": "sdb.ap-southeast-2.amazonaws.com", "sns": "sns.ap-southeast-2.amazonaws.com", "sqs": "ap-southeast-2.queue.amazonaws.com", "s3": "s3-ap-southeast-2.amazonaws.com", "autoscaling": "autoscaling.ap-southeast-2.amazonaws.com", "elasticbeanstalk": "elasticbeanstalk.ap-southeast-2.amazonaws.com", "iam": "iam.amazonaws.com", "importexport": "importexport.amazonaws.com", "sts": "sts.amazonaws.com", "storagegateway": "storagegateway.ap-southeast-2.amazonaws.com", "elasticloadbalancing": "elasticloadbalancing.ap-southeast-2.amazonaws.com", "swf": "swf.ap-southeast-2.amazonaws.com", "glacier": "glacier.ap-southeast-2.amazonaws.com", "directconnect": "directconnect.ap-southeast-2.amazonaws.com", "redshift": "redshift.ap-southeast-2.amazonaws.com", }, "sa-east-1": { "cloudformation": "cloudformation.sa-east-1.amazonaws.com", "cloudfront": "cloudfront.amazonaws.com", "monitoring": "monitoring.sa-east-1.amazonaws.com", "dynamodb": "dynamodb.sa-east-1.amazonaws.com", "ec2": "ec2.sa-east-1.amazonaws.com", "elasticmapreduce": "sa-east-1.elasticmapreduce.amazonaws.com", "elasticache": "elasticache.sa-east-1.amazonaws.com", "rds": "rds.sa-east-1.amazonaws.com", "route53": "route53.amazonaws.com", "sdb": "sdb.sa-east-1.amazonaws.com", "sns": "sns.sa-east-1.amazonaws.com", "sqs": "sa-east-1.queue.amazonaws.com", "s3": "s3-sa-east-1.amazonaws.com", "autoscaling": "autoscaling.sa-east-1.amazonaws.com", "elasticbeanstalk": "elasticbeanstalk.sa-east-1.amazonaws.com", "iam": "iam.amazonaws.com", "importexport": "importexport.amazonaws.com", "sts": "sts.amazonaws.com", "storagegateway": "storagegateway.sa-east-1.amazonaws.com", "elasticloadbalancing": "elasticloadbalancing.sa-east-1.amazonaws.com", "swf": "swf.sa-east-1.amazonaws.com", "directconnect": "directconnect.sa-east-1.amazonaws.com", }, "eu-west-1": { "cloudformation": "cloudformation.eu-west-1.amazonaws.com", "cloudfront": "cloudfront.amazonaws.com", "cloudsearch": "cloudsearch.eu-west-1.amazonaws.com", "monitoring": "monitoring.eu-west-1.amazonaws.com", "dynamodb": "dynamodb.eu-west-1.amazonaws.com", "ec2": "ec2.eu-west-1.amazonaws.com", "elasticmapreduce": "eu-west-1.elasticmapreduce.amazonaws.com", "elasticache": "elasticache.eu-west-1.amazonaws.com", "rds": "rds.eu-west-1.amazonaws.com", "route53": "route53.amazonaws.com", "sdb": "sdb.eu-west-1.amazonaws.com", "sns": "sns.eu-west-1.amazonaws.com", "sqs": "eu-west-1.queue.amazonaws.com", "s3": "s3-eu-west-1.amazonaws.com", "autoscaling": "autoscaling.eu-west-1.amazonaws.com", "elasticbeanstalk": "elasticbeanstalk.eu-west-1.amazonaws.com", "iam": "iam.amazonaws.com", "importexport": "importexport.amazonaws.com", "sts": "sts.amazonaws.com", "storagegateway": "storagegateway.eu-west-1.amazonaws.com", "elasticloadbalancing": "elasticloadbalancing.eu-west-1.amazonaws.com", "swf": "swf.eu-west-1.amazonaws.com", "glacier": "glacier.eu-west-1.amazonaws.com", "directconnect": "directconnect.eu-west-1.amazonaws.com", "redshift": "redshift.eu-west-1.amazonaws.com", "elastictranscoder": "elastictranscoder.eu-west-1.amazonaws.com", }, "cn-north-1": { "cloudformation": "cloudformation.cn-north-1.amazonaws.com.cn", "monitoring": "monitoring.cn-north-1.amazonaws.com.cn", "dynamodb": "dynamodb.cn-north-1.amazonaws.com.cn", "ec2": "ec2.cn-north-1.amazonaws.com.cn", "elasticmapreduce": "elasticmapreduce.cn-north-1.amazonaws.com.cn", "elasticache": "elasticache.cn-north-1.amazonaws.com.cn", "rds": "rds.cn-north-1.amazonaws.com.cn", "sns": "sns.cn-north-1.amazonaws.com.cn", "sqs": "cn-north-1.queue.amazonaws.com.cn", "s3": "s3.cn-north-1.amazonaws.com.cn", "autoscaling": "autoscaling.cn-north-1.amazonaws.com.cn", "iam": "iam.cn-north-1.amazonaws.com.cn", "sts": "sts.cn-north-1.amazonaws.com.cn", "storagegateway": "storagegateway.cn-north-1.amazonaws.com.cn", "elasticloadbalancing": "elasticloadbalancing.cn-north-1.amazonaws.com.cn", "swf": "swf.cn-north-1.amazonaws.com.cn", "glacier": "glacier.cn-north-1.amazonaws.com.cn", }, "us-gov-west-1": { "monitoring": "monitoring.us-gov-west-1.amazonaws.com", "dynamodb": "dynamodb.us-gov-west-1.amazonaws.com", "ec2": "ec2.us-gov-west-1.amazonaws.com", "elasticmapreduce": "us-gov-west-1.elasticmapreduce.amazonaws.com", "rds": "rds.us-gov-west-1.amazonaws.com", "sns": "sns.us-gov-west-1.amazonaws.com", # The endpoint has been replaced with the name in the common name. "sqs": "us-gov-west-1.queue.amazonaws.com", "s3": "s3-us-gov-west-1.amazonaws.com", "autoscaling": "autoscaling.us-gov-west-1.amazonaws.com", "iam": "iam.us-gov.amazonaws.com", "sts": "sts.us-gov-west-1.amazonaws.com", "elasticloadbalancing": "elasticloadbalancing.us-gov-west-1.amazonaws.com", "swf": "swf.us-gov-west-1.amazonaws.com", }, "fips-us-gov-west-1": { "s3": "s3-fips-us-gov-west-1.amazonaws.com" }, "eu-central-1": { "elasticmapreduce": "elasticmapreduce.eu-central-1.amazonaws.com", } } def test_known_endpoints(): # Verify the actual values from the _endpoints.json file. While # TestEndpointHeuristics verified the generic functionality given any # endpoints file, this test actually verifies the _endpoints.json against a # fixed list of known endpoints. This list doesn't need to be kept 100% up # to date, but serves as a basis for regressions as the endpoint heuristics # logic evolves. with mock.patch('os.environ') as environ: environ['AWS_ACCESS_KEY_ID'] = 'access_key' environ['AWS_SECRET_ACCESS_KEY'] = 'secret_key' environ['AWS_CONFIG_FILE'] = 'no-exist-foo' session = create_session() resolver = session.get_component('endpoint_resolver') for region_name, service_dict in KNOWN_REGIONS.items(): for service_name, endpoint in service_dict.items(): endpoint = 'https://%s' % endpoint yield (_test_single_service_region, service_name, region_name, endpoint, resolver) def _test_single_service_region(service_name, region_name, expected_endpoint, resolver): actual_endpoint = resolver.construct_endpoint( service_name=service_name, region_name=region_name) assert_equals(actual_endpoint['uri'], expected_endpoint) class TestEndpointHeuristics(unittest.TestCase): def create_endpoint_resolver(self, rules): return regions.EndpointResolver(rules) def test_matches_exact_rule(self): resolver = self.create_endpoint_resolver({ 'iam': [ {'uri': 'https://{service}.us-gov.amazonaws.com', 'constraints': [['region', 'startsWith', 'us-gov']]} ] }) endpoint = resolver.construct_endpoint( service_name='iam', region_name='us-gov-1') self.assertEqual(endpoint['uri'], 'https://iam.us-gov.amazonaws.com') self.assertEqual(endpoint['properties'], {}) def test_no_match_throws_exception(self): resolver = self.create_endpoint_resolver({ 'iam': [ {'uri': 'https://{service}.us-gov.amazonaws.com', 'constraints': [['region', 'startsWith', 'us-gov']]} ] }) with self.assertRaises(UnknownEndpointError): resolver.construct_endpoint(service_name='iam', region_name='not-us-gov-2') def test_no_region_throws_specific_error(self): resolver = self.create_endpoint_resolver({ 'iam': [ {'uri': 'https://{service}.us-gov.amazonaws.com', 'constraints': [['region', 'startsWith', 'us-gov']]} ] }) with self.assertRaises(NoRegionError): resolver.construct_endpoint(service_name='iam', region_name=None) def test_use_default_section_if_no_service_name(self): resolver = self.create_endpoint_resolver({ '_default': [ {'uri': 'https://{service}.us-gov.amazonaws.com', 'constraints': [['region', 'startsWith', 'us-gov']]} ] }) self.assertEqual( resolver.construct_endpoint(service_name='iam', region_name='us-gov-1')['uri'], 'https://iam.us-gov.amazonaws.com') def test_use_default_section_if_no_service_rule_matches(self): resolver = self.create_endpoint_resolver({ '_default': [ {"uri":"{scheme}://{service}.{region}.amazonaws.com", "constraints": [ ["region", "notEquals", None] ]} ], 'iam': [ {'uri': 'https://{service}.us-gov.amazonaws.com', 'constraints': [['region', 'startsWith', 'us-gov']]} ] }) self.assertEqual( resolver.construct_endpoint(service_name='iam', region_name='other-region')['uri'], 'https://iam.other-region.amazonaws.com') def test_matches_last_rule(self): resolver = self.create_endpoint_resolver({ "s3":[ { "uri":"{scheme}://s3.amazonaws.com", "constraints":[ ["region", "oneOf", ["us-east-1", None]] ] }, { "uri":"{scheme}://{service}-{region}.amazonaws.com.cn", "constraints":[ ["region", "startsWith", "cn-"] ] }, { "uri":"{scheme}://{service}-{region}.amazonaws.com", "constraints": [ ["region", "notEquals", None] ] } ], }) self.assertEqual( resolver.construct_endpoint(service_name='s3', region_name='us-east-1')['uri'], 'https://s3.amazonaws.com') self.assertEqual( resolver.construct_endpoint(service_name='s3', region_name=None)['uri'], 'https://s3.amazonaws.com') self.assertEqual( resolver.construct_endpoint(service_name='s3', region_name='us-west-2')['uri'], 'https://s3-us-west-2.amazonaws.com') self.assertEqual( resolver.construct_endpoint(service_name='s3', region_name='cn-north-1')['uri'], 'https://s3-cn-north-1.amazonaws.com.cn') def test_not_starts_with(self): resolver = self.create_endpoint_resolver({ 'iam': [ {'uri': 'https://route53.amazonaws.com', 'constraints': [['region', 'notStartsWith', 'cn-']]} ] }) self.assertEqual( resolver.construct_endpoint(service_name='iam', region_name='us-east-1')['uri'], 'https://route53.amazonaws.com') def test_can_add_rule(self): # This shows how a customer could add their own rules. resolver = self.create_endpoint_resolver({ 'iam': [ {'uri': 'https://{service}.us-gov.amazonaws.com', 'constraints': [['region', 'startsWith', 'us-gov']]} ] }) resolver.get_rules_for_service('iam').insert( 0, {'uri': 'https://my.custom.location', 'constraints': [['region', 'equals', 'custom-region']]}) self.assertEqual( resolver.construct_endpoint(service_name='iam', region_name='custom-region')['uri'], 'https://my.custom.location') def test_property_bags_returned(self): resolver = self.create_endpoint_resolver({ 'iam': [ {'uri': 'https://{service}.us-gov.amazonaws.com', 'constraints': [['region', 'startsWith', 'us-gov']], 'properties': { 'signatureVersion': 'v4', 'credentialScope': { 'region': 'us-east-1' } }} ] }) endpoint = resolver.construct_endpoint( service_name='iam', region_name='us-gov-1') self.assertEqual(endpoint['properties'], {'credentialScope': {'region': 'us-east-1'}, 'signatureVersion': 'v4'})