From eb6043e678998ad31f18abce4d62b2c97bf91003 Mon Sep 17 00:00:00 2001 From: ryotanr Date: Wed, 25 Mar 2026 16:35:22 +0900 Subject: [PATCH 1/3] support EndpointAccessMode --- docs/globals.rst | 1 + .../single/api_with_endpoint_access_mode.json | 14 +++ .../single/api_with_endpoint_access_mode.yaml | 12 +++ .../test_api_with_endpoint_access_mode.py | 18 ++++ .../schema_source/aws_serverless_api.py | 10 ++ .../internal/schema_source/sam-docs.json | 1 + samtranslator/model/api/api_generator.py | 7 +- samtranslator/model/apigateway.py | 2 + samtranslator/model/sam_resources.py | 3 + samtranslator/plugins/globals/globals.py | 1 + samtranslator/schema/schema.json | 10 ++ schema_source/sam.schema.json | 38 ++++++++ ...test_api_generator_endpoint_access_mode.py | 43 +++++++++ .../input/api_with_endpoint_access_mode.yaml | 17 ++++ .../output/api_with_endpoint_access_mode.json | 80 ++++++++++++++++ .../aws-cn/api_with_endpoint_access_mode.json | 96 +++++++++++++++++++ .../api_with_endpoint_access_mode.json | 96 +++++++++++++++++++ .../error_globals_api_with_stage_name.json | 4 +- 18 files changed, 450 insertions(+), 3 deletions(-) create mode 100644 integration/resources/expected/single/api_with_endpoint_access_mode.json create mode 100644 integration/resources/templates/single/api_with_endpoint_access_mode.yaml create mode 100644 integration/single/test_api_with_endpoint_access_mode.py create mode 100644 tests/model/api/test_api_generator_endpoint_access_mode.py create mode 100644 tests/translator/input/api_with_endpoint_access_mode.yaml create mode 100644 tests/translator/output/api_with_endpoint_access_mode.json create mode 100644 tests/translator/output/aws-cn/api_with_endpoint_access_mode.json create mode 100644 tests/translator/output/aws-us-gov/api_with_endpoint_access_mode.json diff --git a/docs/globals.rst b/docs/globals.rst index ed83e64902..466d684ee7 100644 --- a/docs/globals.rst +++ b/docs/globals.rst @@ -99,6 +99,7 @@ Currently, the following resources and properties are being supported: OpenApiVersion: Domain: SecurityPolicy: + EndpointAccessMode: HttpApi: # Properties of AWS::Serverless::HttpApi diff --git a/integration/resources/expected/single/api_with_endpoint_access_mode.json b/integration/resources/expected/single/api_with_endpoint_access_mode.json new file mode 100644 index 0000000000..30b334c234 --- /dev/null +++ b/integration/resources/expected/single/api_with_endpoint_access_mode.json @@ -0,0 +1,14 @@ +[ + { + "LogicalResourceId": "MyApi", + "ResourceType": "AWS::ApiGateway::RestApi" + }, + { + "LogicalResourceId": "MyApiDeployment", + "ResourceType": "AWS::ApiGateway::Deployment" + }, + { + "LogicalResourceId": "MyApiProdStage", + "ResourceType": "AWS::ApiGateway::Stage" + } +] diff --git a/integration/resources/templates/single/api_with_endpoint_access_mode.yaml b/integration/resources/templates/single/api_with_endpoint_access_mode.yaml new file mode 100644 index 0000000000..c484c89028 --- /dev/null +++ b/integration/resources/templates/single/api_with_endpoint_access_mode.yaml @@ -0,0 +1,12 @@ +Resources: + MyApi: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + DefinitionUri: ${definitionuri} + SecurityPolicy: SecurityPolicy_TLS13_1_3_2025_09 + EndpointAccessMode: STRICT + EndpointConfiguration: + Type: REGIONAL +Metadata: + SamTransformTest: true diff --git a/integration/single/test_api_with_endpoint_access_mode.py b/integration/single/test_api_with_endpoint_access_mode.py new file mode 100644 index 0000000000..3a5cf35708 --- /dev/null +++ b/integration/single/test_api_with_endpoint_access_mode.py @@ -0,0 +1,18 @@ +from unittest.case import skipIf + +from integration.config.service_names import REST_API +from integration.helpers.base_test import BaseTest +from integration.helpers.resource import current_region_does_not_support + + +@skipIf(current_region_does_not_support([REST_API]), "Rest API is not supported in this testing region") +class TestApiWithEndpointAccessMode(BaseTest): + """ + Tests for AWS::Serverless::Api with EndpointAccessMode property + """ + + def test_api_with_endpoint_access_mode(self): + self.create_and_verify_stack("single/api_with_endpoint_access_mode") + + rest_api_resources = self.get_stack_resources("AWS::ApiGateway::RestApi") + self.assertEqual(len(rest_api_resources), 1) diff --git a/samtranslator/internal/schema_source/aws_serverless_api.py b/samtranslator/internal/schema_source/aws_serverless_api.py index c478a3c3ae..7dcce23164 100644 --- a/samtranslator/internal/schema_source/aws_serverless_api.py +++ b/samtranslator/internal/schema_source/aws_serverless_api.py @@ -306,6 +306,11 @@ class Properties(BaseModel): ) DisableExecuteApiEndpoint: Optional[PassThroughProp] = properties("DisableExecuteApiEndpoint") Domain: Optional[Domain] = properties("Domain") + EndpointAccessMode: Optional[PassThroughProp] = passthrough_prop( + PROPERTIES_STEM, + "EndpointAccessMode", + ["AWS::ApiGateway::RestApi", "Properties", "EndpointAccessMode"], + ) EndpointConfiguration: Optional[EndpointConfigurationType] = properties("EndpointConfiguration") FailOnWarnings: Optional[PassThroughProp] = passthrough_prop( PROPERTIES_STEM, @@ -419,6 +424,11 @@ class Globals(BaseModel): "SecurityPolicy", ["AWS::ApiGateway::RestApi", "Properties", "SecurityPolicy"], ) + EndpointAccessMode: Optional[PassThroughProp] = passthrough_prop( + PROPERTIES_STEM, + "EndpointAccessMode", + ["AWS::ApiGateway::RestApi", "Properties", "EndpointAccessMode"], + ) class Resource(ResourceAttributes): diff --git a/samtranslator/internal/schema_source/sam-docs.json b/samtranslator/internal/schema_source/sam-docs.json index edd52e62dc..c818950bf7 100644 --- a/samtranslator/internal/schema_source/sam-docs.json +++ b/samtranslator/internal/schema_source/sam-docs.json @@ -723,6 +723,7 @@ "Description": "A description of the Api resource. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`Description`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-restapi.html#cfn-apigateway-restapi-description) property of an `AWS::ApiGateway::RestApi` resource.", "DisableExecuteApiEndpoint": "Specifies whether clients can invoke your API by using the default `execute-api` endpoint. By default, clients can invoke your API with the default `https://{api_id}.execute-api.{region}.amazonaws.com`. To require that clients use a custom domain name to invoke your API, specify `True`. \n*Type*: Boolean \n*Required*: No \n*CloudFormation compatibility*: This property is similar to the `[ DisableExecuteApiEndpoint](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-restapi.html#cfn-apigateway-restapi-disableexecuteapiendpoint)` property of an `AWS::ApiGateway::RestApi` resource. It is passed directly to the `disableExecuteApiEndpoint` property of an `[ x-amazon-apigateway-endpoint-configuration](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-endpoint-configuration.html)` extension, which gets added to the ` [ Body](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-restapi.html#cfn-apigateway-restapi-body)` property of an `AWS::ApiGateway::RestApi` resource.", "Domain": "Configures a custom domain for this API Gateway API. \n*Type*: [DomainConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-api-domainconfiguration.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "EndpointAccessMode": "The endpoint access mode for the RestApi. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`EndpointAccessMode`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-restapi.html#cfn-apigateway-restapi-endpointaccessmode) property of an `AWS::ApiGateway::RestApi` resource.", "EndpointConfiguration": "The endpoint type of a REST API. \n*Type*: [EndpointConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-api-endpointconfiguration.html) \n*Required*: No \n*CloudFormation compatibility*: This property is similar to the [`EndpointConfiguration`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-restapi.html#cfn-apigateway-restapi-endpointconfiguration) property of an `AWS::ApiGateway::RestApi` resource. The nested configuration properties are named differently.", "FailOnWarnings": "Specifies whether to roll back the API creation (`true`) or not (`false`) when a warning is encountered. The default value is `false`. \n*Type*: Boolean \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`FailOnWarnings`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-restapi.html#cfn-apigateway-restapi-failonwarnings) property of an `AWS::ApiGateway::RestApi` resource.", "GatewayResponses": "Configures Gateway Responses for an API. Gateway Responses are responses returned by API Gateway, either directly or through the use of Lambda Authorizers. For more information, see the documentation for the [Api Gateway OpenApi extension for Gateway Responses](https://docs.aws.amazon.com/apigateway/latest/developerguide/api-gateway-swagger-extensions-gateway-responses.html). \n*Type*: Map \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index 10af5ed825..1bf4e5fc20 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -222,6 +222,7 @@ def __init__( # noqa: PLR0913 feature_toggle: Optional[FeatureToggle] = None, policy: Optional[Union[Dict[str, Any], Intrinsicable[str]]] = None, security_policy: Optional[Intrinsicable[str]] = None, + endpoint_access_mode: Optional[Intrinsicable[str]] = None, ): """Constructs an API Generator class that generates API Gateway resources @@ -281,8 +282,9 @@ def __init__( # noqa: PLR0913 self.feature_toggle = feature_toggle self.policy = policy self.security_policy = security_policy + self.endpoint_access_mode = endpoint_access_mode - def _construct_rest_api(self) -> ApiGatewayRestApi: + def _construct_rest_api(self) -> ApiGatewayRestApi: # noqa: PLR0912 """Constructs and returns the ApiGateway RestApi. :returns: the RestApi to which this SAM Api corresponds @@ -340,6 +342,9 @@ def _construct_rest_api(self) -> ApiGatewayRestApi: if self.security_policy: rest_api.SecurityPolicy = self.security_policy + if self.endpoint_access_mode: + rest_api.EndpointAccessMode = self.endpoint_access_mode + return rest_api def _validate_properties(self) -> None: diff --git a/samtranslator/model/apigateway.py b/samtranslator/model/apigateway.py index 73966d6452..eae1197696 100644 --- a/samtranslator/model/apigateway.py +++ b/samtranslator/model/apigateway.py @@ -31,6 +31,7 @@ class ApiGatewayRestApi(Resource): "Tags": GeneratedProperty(), "Policy": GeneratedProperty(), "SecurityPolicy": GeneratedProperty(), + "EndpointAccessMode": GeneratedProperty(), } Body: Optional[Dict[str, Any]] @@ -48,6 +49,7 @@ class ApiGatewayRestApi(Resource): Tags: Optional[PassThrough] Policy: Optional[PassThrough] SecurityPolicy: Optional[PassThrough] + EndpointAccessMode: Optional[PassThrough] runtime_attrs = {"rest_api_id": lambda self: ref(self.logical_id)} diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index d58642828f..93511b9ec1 100644 --- a/samtranslator/model/sam_resources.py +++ b/samtranslator/model/sam_resources.py @@ -1648,6 +1648,7 @@ class SamApi(SamResourceMacro): "AlwaysDeploy": Property(False, IS_BOOL), "Policy": PropertyType(False, one_of(IS_STR, IS_DICT)), "SecurityPolicy": PropertyType(False, IS_STR), + "EndpointAccessMode": PropertyType(False, IS_STR), } Name: Optional[Intrinsicable[str]] @@ -1681,6 +1682,7 @@ class SamApi(SamResourceMacro): AlwaysDeploy: Optional[bool] Policy: Optional[Union[Dict[str, Any], Intrinsicable[str]]] SecurityPolicy: Optional[Intrinsicable[str]] + EndpointAccessMode: Optional[Intrinsicable[str]] referable_properties = { "Stage": ApiGatewayStage.resource_type, @@ -1750,6 +1752,7 @@ def to_cloudformation(self, **kwargs) -> List[Resource]: # type: ignore[no-unty feature_toggle=feature_toggle, policy=self.Policy, security_policy=self.SecurityPolicy, + endpoint_access_mode=self.EndpointAccessMode, ) generated_resources = api_generator.to_cloudformation(redeploy_restapi_parameters, route53_record_set_groups) diff --git a/samtranslator/plugins/globals/globals.py b/samtranslator/plugins/globals/globals.py index 9defaeaf98..092f4486b5 100644 --- a/samtranslator/plugins/globals/globals.py +++ b/samtranslator/plugins/globals/globals.py @@ -89,6 +89,7 @@ class Globals: "AlwaysDeploy", "PropagateTags", "SecurityPolicy", + "EndpointAccessMode", ], SamResourceType.HttpApi.value: [ "Auth", diff --git a/samtranslator/schema/schema.json b/samtranslator/schema/schema.json index cfbcf14ca0..3574458877 100644 --- a/samtranslator/schema/schema.json +++ b/samtranslator/schema/schema.json @@ -359621,6 +359621,11 @@ "markdownDescription": "Configures a custom domain for this API Gateway API. \n*Type*: [DomainConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-api-domainconfiguration.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", "title": "Domain" }, + "EndpointAccessMode": { + "markdownDescription": "The endpoint access mode for the RestApi. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`EndpointAccessMode`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-restapi.html#cfn-apigateway-restapi-endpointaccessmode) property of an `AWS::ApiGateway::RestApi` resource.", + "title": "EndpointAccessMode", + "type": "string" + }, "EndpointConfiguration": { "allOf": [ { @@ -359807,6 +359812,11 @@ "markdownDescription": "Configures a custom domain for this API Gateway API. \n*Type*: [DomainConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-api-domainconfiguration.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", "title": "Domain" }, + "EndpointAccessMode": { + "markdownDescription": "The endpoint access mode for the RestApi. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`EndpointAccessMode`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-restapi.html#cfn-apigateway-restapi-endpointaccessmode) property of an `AWS::ApiGateway::RestApi` resource.", + "title": "EndpointAccessMode", + "type": "string" + }, "EndpointConfiguration": { "anyOf": [ { diff --git a/schema_source/sam.schema.json b/schema_source/sam.schema.json index 5cbca5201a..6af095148c 100644 --- a/schema_source/sam.schema.json +++ b/schema_source/sam.schema.json @@ -4624,6 +4624,25 @@ "markdownDescription": "Configures a custom domain for this API Gateway API. \n*Type*: [DomainConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-api-domainconfiguration.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", "title": "Domain" }, + "EndpointAccessMode": { + "__samPassThrough": { + "markdownDescriptionOverride": "The endpoint access mode for the RestApi. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`EndpointAccessMode`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-restapi.html#cfn-apigateway-restapi-endpointaccessmode) property of an `AWS::ApiGateway::RestApi` resource.", + "schemaPath": [ + "definitions", + "AWS::ApiGateway::RestApi", + "properties", + "Properties", + "properties", + "EndpointAccessMode" + ] + }, + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "title": "EndpointAccessMode" + }, "EndpointConfiguration": { "allOf": [ { @@ -4958,6 +4977,25 @@ "markdownDescription": "Configures a custom domain for this API Gateway API. \n*Type*: [DomainConfiguration](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-api-domainconfiguration.html) \n*Required*: No \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", "title": "Domain" }, + "EndpointAccessMode": { + "__samPassThrough": { + "markdownDescriptionOverride": "The endpoint access mode for the RestApi. \n*Type*: String \n*Required*: No \n*AWS CloudFormation compatibility*: This property is passed directly to the [`EndpointAccessMode`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-restapi.html#cfn-apigateway-restapi-endpointaccessmode) property of an `AWS::ApiGateway::RestApi` resource.", + "schemaPath": [ + "definitions", + "AWS::ApiGateway::RestApi", + "properties", + "Properties", + "properties", + "EndpointAccessMode" + ] + }, + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "title": "EndpointAccessMode" + }, "EndpointConfiguration": { "anyOf": [ { diff --git a/tests/model/api/test_api_generator_endpoint_access_mode.py b/tests/model/api/test_api_generator_endpoint_access_mode.py new file mode 100644 index 0000000000..47e4e42c19 --- /dev/null +++ b/tests/model/api/test_api_generator_endpoint_access_mode.py @@ -0,0 +1,43 @@ +from unittest import TestCase +from unittest.mock import Mock + +from samtranslator.model.api.api_generator import ApiGenerator + + +class TestApiGeneratorEndpointAccessMode(TestCase): + def setUp(self): + self.logical_id = "MyApi" + self.default_args = { + "logical_id": self.logical_id, + "cache_cluster_enabled": None, + "cache_cluster_size": None, + "variables": None, + "depends_on": None, + "definition_body": {"swagger": "2.0"}, + "definition_uri": None, + "name": None, + "stage_name": "Prod", + "shared_api_usage_plan": Mock(), + "template_conditions": Mock(), + "method_settings": None, + "endpoint_configuration": {"Type": "REGIONAL"}, + "access_log_setting": None, + "canary_setting": None, + "tracing_enabled": None, + "open_api_version": None, + "always_deploy": None, + } + + def test_endpoint_access_mode_set(self): + api_generator = ApiGenerator(**self.default_args, endpoint_access_mode="STRICT") + + rest_api = api_generator._construct_rest_api() + + self.assertEqual(rest_api.EndpointAccessMode, "STRICT") + + def test_no_endpoint_access_mode(self): + api_generator = ApiGenerator(**self.default_args, endpoint_access_mode=None) + + rest_api = api_generator._construct_rest_api() + + self.assertIsNone(rest_api.EndpointAccessMode) diff --git a/tests/translator/input/api_with_endpoint_access_mode.yaml b/tests/translator/input/api_with_endpoint_access_mode.yaml new file mode 100644 index 0000000000..56e98bdb03 --- /dev/null +++ b/tests/translator/input/api_with_endpoint_access_mode.yaml @@ -0,0 +1,17 @@ +Globals: + Api: + EndpointAccessMode: BASIC + +Resources: + # Inherits Globals + ApiInheritGlobals: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + + # Top-level overrides Globals + ApiTopLevelOverride: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + EndpointAccessMode: STRICT diff --git a/tests/translator/output/api_with_endpoint_access_mode.json b/tests/translator/output/api_with_endpoint_access_mode.json new file mode 100644 index 0000000000..d8639d44ba --- /dev/null +++ b/tests/translator/output/api_with_endpoint_access_mode.json @@ -0,0 +1,80 @@ +{ + "Resources": { + "ApiInheritGlobals": { + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "paths": {}, + "swagger": "2.0" + }, + "EndpointAccessMode": "BASIC" + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiInheritGlobalsDeployment5332c373d4": { + "Properties": { + "Description": "RestApi deployment id: 5332c373d45c69e6c0f562b4a419aa8eb311adc7", + "RestApiId": { + "Ref": "ApiInheritGlobals" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiInheritGlobalsProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiInheritGlobalsDeployment5332c373d4" + }, + "RestApiId": { + "Ref": "ApiInheritGlobals" + }, + "StageName": "Prod" + }, + "Type": "AWS::ApiGateway::Stage" + }, + "ApiTopLevelOverride": { + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "paths": {}, + "swagger": "2.0" + }, + "EndpointAccessMode": "STRICT" + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiTopLevelOverrideDeployment5332c373d4": { + "Properties": { + "Description": "RestApi deployment id: 5332c373d45c69e6c0f562b4a419aa8eb311adc7", + "RestApiId": { + "Ref": "ApiTopLevelOverride" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiTopLevelOverrideProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiTopLevelOverrideDeployment5332c373d4" + }, + "RestApiId": { + "Ref": "ApiTopLevelOverride" + }, + "StageName": "Prod" + }, + "Type": "AWS::ApiGateway::Stage" + } + } +} diff --git a/tests/translator/output/aws-cn/api_with_endpoint_access_mode.json b/tests/translator/output/aws-cn/api_with_endpoint_access_mode.json new file mode 100644 index 0000000000..a177488f00 --- /dev/null +++ b/tests/translator/output/aws-cn/api_with_endpoint_access_mode.json @@ -0,0 +1,96 @@ +{ + "Resources": { + "ApiInheritGlobals": { + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "paths": {}, + "swagger": "2.0" + }, + "EndpointAccessMode": "BASIC", + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiInheritGlobalsDeployment5332c373d4": { + "Properties": { + "Description": "RestApi deployment id: 5332c373d45c69e6c0f562b4a419aa8eb311adc7", + "RestApiId": { + "Ref": "ApiInheritGlobals" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiInheritGlobalsProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiInheritGlobalsDeployment5332c373d4" + }, + "RestApiId": { + "Ref": "ApiInheritGlobals" + }, + "StageName": "Prod" + }, + "Type": "AWS::ApiGateway::Stage" + }, + "ApiTopLevelOverride": { + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "paths": {}, + "swagger": "2.0" + }, + "EndpointAccessMode": "STRICT", + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiTopLevelOverrideDeployment5332c373d4": { + "Properties": { + "Description": "RestApi deployment id: 5332c373d45c69e6c0f562b4a419aa8eb311adc7", + "RestApiId": { + "Ref": "ApiTopLevelOverride" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiTopLevelOverrideProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiTopLevelOverrideDeployment5332c373d4" + }, + "RestApiId": { + "Ref": "ApiTopLevelOverride" + }, + "StageName": "Prod" + }, + "Type": "AWS::ApiGateway::Stage" + } + } +} diff --git a/tests/translator/output/aws-us-gov/api_with_endpoint_access_mode.json b/tests/translator/output/aws-us-gov/api_with_endpoint_access_mode.json new file mode 100644 index 0000000000..a177488f00 --- /dev/null +++ b/tests/translator/output/aws-us-gov/api_with_endpoint_access_mode.json @@ -0,0 +1,96 @@ +{ + "Resources": { + "ApiInheritGlobals": { + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "paths": {}, + "swagger": "2.0" + }, + "EndpointAccessMode": "BASIC", + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiInheritGlobalsDeployment5332c373d4": { + "Properties": { + "Description": "RestApi deployment id: 5332c373d45c69e6c0f562b4a419aa8eb311adc7", + "RestApiId": { + "Ref": "ApiInheritGlobals" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiInheritGlobalsProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiInheritGlobalsDeployment5332c373d4" + }, + "RestApiId": { + "Ref": "ApiInheritGlobals" + }, + "StageName": "Prod" + }, + "Type": "AWS::ApiGateway::Stage" + }, + "ApiTopLevelOverride": { + "Properties": { + "Body": { + "info": { + "title": { + "Ref": "AWS::StackName" + }, + "version": "1.0" + }, + "paths": {}, + "swagger": "2.0" + }, + "EndpointAccessMode": "STRICT", + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiTopLevelOverrideDeployment5332c373d4": { + "Properties": { + "Description": "RestApi deployment id: 5332c373d45c69e6c0f562b4a419aa8eb311adc7", + "RestApiId": { + "Ref": "ApiTopLevelOverride" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiTopLevelOverrideProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiTopLevelOverrideDeployment5332c373d4" + }, + "RestApiId": { + "Ref": "ApiTopLevelOverride" + }, + "StageName": "Prod" + }, + "Type": "AWS::ApiGateway::Stage" + } + } +} diff --git a/tests/translator/output/error_globals_api_with_stage_name.json b/tests/translator/output/error_globals_api_with_stage_name.json index 570d065c71..775a5a4830 100644 --- a/tests/translator/output/error_globals_api_with_stage_name.json +++ b/tests/translator/output/error_globals_api_with_stage_name.json @@ -4,7 +4,7 @@ "Number of errors found: 1. ", "'Globals' section is invalid. ", "'StageName' is not a supported property of 'Api'. ", - "Must be one of the following values - ['Auth', 'Name', 'DefinitionUri', 'CacheClusterEnabled', 'CacheClusterSize', 'MergeDefinitions', 'Variables', 'EndpointConfiguration', 'MethodSettings', 'BinaryMediaTypes', 'MinimumCompressionSize', 'Cors', 'GatewayResponses', 'AccessLogSetting', 'CanarySetting', 'TracingEnabled', 'OpenApiVersion', 'Domain', 'AlwaysDeploy', 'PropagateTags', 'SecurityPolicy']" + "Must be one of the following values - ['Auth', 'Name', 'DefinitionUri', 'CacheClusterEnabled', 'CacheClusterSize', 'MergeDefinitions', 'Variables', 'EndpointConfiguration', 'MethodSettings', 'BinaryMediaTypes', 'MinimumCompressionSize', 'Cors', 'GatewayResponses', 'AccessLogSetting', 'CanarySetting', 'TracingEnabled', 'OpenApiVersion', 'Domain', 'AlwaysDeploy', 'PropagateTags', 'SecurityPolicy', 'EndpointAccessMode']" ], - "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. 'Globals' section is invalid. 'StageName' is not a supported property of 'Api'. Must be one of the following values - ['Auth', 'Name', 'DefinitionUri', 'CacheClusterEnabled', 'CacheClusterSize', 'MergeDefinitions', 'Variables', 'EndpointConfiguration', 'MethodSettings', 'BinaryMediaTypes', 'MinimumCompressionSize', 'Cors', 'GatewayResponses', 'AccessLogSetting', 'CanarySetting', 'TracingEnabled', 'OpenApiVersion', 'Domain', 'AlwaysDeploy', 'PropagateTags', 'SecurityPolicy']" + "errorMessage": "Invalid Serverless Application Specification document. Number of errors found: 1. 'Globals' section is invalid. 'StageName' is not a supported property of 'Api'. Must be one of the following values - ['Auth', 'Name', 'DefinitionUri', 'CacheClusterEnabled', 'CacheClusterSize', 'MergeDefinitions', 'Variables', 'EndpointConfiguration', 'MethodSettings', 'BinaryMediaTypes', 'MinimumCompressionSize', 'Cors', 'GatewayResponses', 'AccessLogSetting', 'CanarySetting', 'TracingEnabled', 'OpenApiVersion', 'Domain', 'AlwaysDeploy', 'PropagateTags', 'SecurityPolicy', 'EndpointAccessMode']" } From 366aaeba8b91646b35786dac54d746b28a1879cf Mon Sep 17 00:00:00 2001 From: ryotanr Date: Sun, 29 Mar 2026 13:11:43 +0900 Subject: [PATCH 2/3] test(api): enhance endpoint access mode unit and integration tests outputs --- .../single/api_with_endpoint_access_mode.yaml | 12 +++++++-- .../test_api_with_endpoint_access_mode.py | 26 ++++++++++++++++--- .../input/api_with_endpoint_access_mode.yaml | 2 ++ .../output/api_with_endpoint_access_mode.json | 6 +++-- .../aws-cn/api_with_endpoint_access_mode.json | 6 +++-- .../api_with_endpoint_access_mode.json | 6 +++-- 6 files changed, 47 insertions(+), 11 deletions(-) diff --git a/integration/resources/templates/single/api_with_endpoint_access_mode.yaml b/integration/resources/templates/single/api_with_endpoint_access_mode.yaml index c484c89028..40b1cb3279 100644 --- a/integration/resources/templates/single/api_with_endpoint_access_mode.yaml +++ b/integration/resources/templates/single/api_with_endpoint_access_mode.yaml @@ -1,11 +1,19 @@ +Parameters: + SecurityPolicyValue: + Type: String + Default: SecurityPolicy_TLS13_1_3_2025_09 + EndpointAccessModeValue: + Type: String + Default: STRICT + Resources: MyApi: Type: AWS::Serverless::Api Properties: StageName: Prod DefinitionUri: ${definitionuri} - SecurityPolicy: SecurityPolicy_TLS13_1_3_2025_09 - EndpointAccessMode: STRICT + SecurityPolicy: !Ref SecurityPolicyValue + EndpointAccessMode: !Ref EndpointAccessModeValue EndpointConfiguration: Type: REGIONAL Metadata: diff --git a/integration/single/test_api_with_endpoint_access_mode.py b/integration/single/test_api_with_endpoint_access_mode.py index 3a5cf35708..dc2ce6a95f 100644 --- a/integration/single/test_api_with_endpoint_access_mode.py +++ b/integration/single/test_api_with_endpoint_access_mode.py @@ -12,7 +12,27 @@ class TestApiWithEndpointAccessMode(BaseTest): """ def test_api_with_endpoint_access_mode(self): - self.create_and_verify_stack("single/api_with_endpoint_access_mode") + # Create stack with STRICT + parameters = [ + {"ParameterKey": "SecurityPolicyValue", "ParameterValue": "SecurityPolicy_TLS13_1_3_2025_09"}, + {"ParameterKey": "EndpointAccessModeValue", "ParameterValue": "STRICT"}, + ] + self.create_and_verify_stack("single/api_with_endpoint_access_mode", parameters) - rest_api_resources = self.get_stack_resources("AWS::ApiGateway::RestApi") - self.assertEqual(len(rest_api_resources), 1) + rest_api_id = self.get_physical_id_by_type("AWS::ApiGateway::RestApi") + rest_api = self.client_provider.api_client.get_rest_api(restApiId=rest_api_id) + + self.assertEqual(rest_api["securityPolicy"], "SecurityPolicy_TLS13_1_3_2025_09") + self.assertEqual(rest_api["endpointAccessMode"], "STRICT") + + # Update stack with BASIC + update_parameters = [ + {"ParameterKey": "SecurityPolicyValue", "ParameterValue": "SecurityPolicy_TLS13_1_3_2025_09"}, + {"ParameterKey": "EndpointAccessModeValue", "ParameterValue": "BASIC"}, + ] + self.update_stack(parameters=update_parameters) + + rest_api = self.client_provider.api_client.get_rest_api(restApiId=rest_api_id) + + self.assertEqual(rest_api["securityPolicy"], "SecurityPolicy_TLS13_1_3_2025_09") + self.assertEqual(rest_api["endpointAccessMode"], "BASIC") diff --git a/tests/translator/input/api_with_endpoint_access_mode.yaml b/tests/translator/input/api_with_endpoint_access_mode.yaml index 56e98bdb03..dbd0e995c9 100644 --- a/tests/translator/input/api_with_endpoint_access_mode.yaml +++ b/tests/translator/input/api_with_endpoint_access_mode.yaml @@ -1,6 +1,7 @@ Globals: Api: EndpointAccessMode: BASIC + SecurityPolicy: SecurityPolicy_TLS13_1_3_2025_09 Resources: # Inherits Globals @@ -15,3 +16,4 @@ Resources: Properties: StageName: Prod EndpointAccessMode: STRICT + SecurityPolicy: SecurityPolicy_TLS13_1_3_2025_09 diff --git a/tests/translator/output/api_with_endpoint_access_mode.json b/tests/translator/output/api_with_endpoint_access_mode.json index d8639d44ba..c906946b24 100644 --- a/tests/translator/output/api_with_endpoint_access_mode.json +++ b/tests/translator/output/api_with_endpoint_access_mode.json @@ -12,7 +12,8 @@ "paths": {}, "swagger": "2.0" }, - "EndpointAccessMode": "BASIC" + "EndpointAccessMode": "BASIC", + "SecurityPolicy": "SecurityPolicy_TLS13_1_3_2025_09" }, "Type": "AWS::ApiGateway::RestApi" }, @@ -50,7 +51,8 @@ "paths": {}, "swagger": "2.0" }, - "EndpointAccessMode": "STRICT" + "EndpointAccessMode": "STRICT", + "SecurityPolicy": "SecurityPolicy_TLS13_1_3_2025_09" }, "Type": "AWS::ApiGateway::RestApi" }, diff --git a/tests/translator/output/aws-cn/api_with_endpoint_access_mode.json b/tests/translator/output/aws-cn/api_with_endpoint_access_mode.json index a177488f00..f0c892e72a 100644 --- a/tests/translator/output/aws-cn/api_with_endpoint_access_mode.json +++ b/tests/translator/output/aws-cn/api_with_endpoint_access_mode.json @@ -20,7 +20,8 @@ }, "Parameters": { "endpointConfigurationTypes": "REGIONAL" - } + }, + "SecurityPolicy": "SecurityPolicy_TLS13_1_3_2025_09" }, "Type": "AWS::ApiGateway::RestApi" }, @@ -66,7 +67,8 @@ }, "Parameters": { "endpointConfigurationTypes": "REGIONAL" - } + }, + "SecurityPolicy": "SecurityPolicy_TLS13_1_3_2025_09" }, "Type": "AWS::ApiGateway::RestApi" }, diff --git a/tests/translator/output/aws-us-gov/api_with_endpoint_access_mode.json b/tests/translator/output/aws-us-gov/api_with_endpoint_access_mode.json index a177488f00..f0c892e72a 100644 --- a/tests/translator/output/aws-us-gov/api_with_endpoint_access_mode.json +++ b/tests/translator/output/aws-us-gov/api_with_endpoint_access_mode.json @@ -20,7 +20,8 @@ }, "Parameters": { "endpointConfigurationTypes": "REGIONAL" - } + }, + "SecurityPolicy": "SecurityPolicy_TLS13_1_3_2025_09" }, "Type": "AWS::ApiGateway::RestApi" }, @@ -66,7 +67,8 @@ }, "Parameters": { "endpointConfigurationTypes": "REGIONAL" - } + }, + "SecurityPolicy": "SecurityPolicy_TLS13_1_3_2025_09" }, "Type": "AWS::ApiGateway::RestApi" }, From 53e77f85f3d1e1c7e883c0430c3b90f71d66d95e Mon Sep 17 00:00:00 2001 From: ryotanr Date: Mon, 30 Mar 2026 12:41:08 +0900 Subject: [PATCH 3/3] feat(api): add EndpointAccessMode support for custom domain configuration ains --- ...th_custom_domain_security_policy_edge.json | 26 +++ ...ustom_domain_security_policy_regional.json | 26 +++ ...th_custom_domain_security_policy_edge.yaml | 27 +++ ...ustom_domain_security_policy_regional.yaml | 27 +++ ..._api_with_custom_domain_security_policy.py | 39 ++++ .../schema_source/aws_serverless_api.py | 5 + .../internal/schema_source/sam-docs.json | 1 + samtranslator/model/api/api_generator.py | 2 + samtranslator/model/apigateway.py | 4 + samtranslator/schema/schema.json | 5 + schema_source/sam.schema.json | 19 ++ ...th_custom_domain_security_policy_edge.yaml | 45 ++++ ...custom_domain_security_policy_private.yaml | 78 +++++++ ...ustom_domain_security_policy_regional.yaml | 45 ++++ ...th_custom_domain_security_policy_edge.json | 142 ++++++++++++ ...custom_domain_security_policy_private.json | 205 ++++++++++++++++++ ...ustom_domain_security_policy_regional.json | 147 +++++++++++++ ...th_custom_domain_security_policy_edge.json | 142 ++++++++++++ ...custom_domain_security_policy_private.json | 205 ++++++++++++++++++ ...ustom_domain_security_policy_regional.json | 147 +++++++++++++ ...th_custom_domain_security_policy_edge.json | 142 ++++++++++++ ...custom_domain_security_policy_private.json | 205 ++++++++++++++++++ ...ustom_domain_security_policy_regional.json | 147 +++++++++++++ 23 files changed, 1831 insertions(+) create mode 100644 integration/resources/expected/single/api_with_custom_domain_security_policy_edge.json create mode 100644 integration/resources/expected/single/api_with_custom_domain_security_policy_regional.json create mode 100644 integration/resources/templates/single/api_with_custom_domain_security_policy_edge.yaml create mode 100644 integration/resources/templates/single/api_with_custom_domain_security_policy_regional.yaml create mode 100644 integration/single/test_api_with_custom_domain_security_policy.py create mode 100644 tests/translator/input/api_with_custom_domain_security_policy_edge.yaml create mode 100644 tests/translator/input/api_with_custom_domain_security_policy_private.yaml create mode 100644 tests/translator/input/api_with_custom_domain_security_policy_regional.yaml create mode 100644 tests/translator/output/api_with_custom_domain_security_policy_edge.json create mode 100644 tests/translator/output/api_with_custom_domain_security_policy_private.json create mode 100644 tests/translator/output/api_with_custom_domain_security_policy_regional.json create mode 100644 tests/translator/output/aws-cn/api_with_custom_domain_security_policy_edge.json create mode 100644 tests/translator/output/aws-cn/api_with_custom_domain_security_policy_private.json create mode 100644 tests/translator/output/aws-cn/api_with_custom_domain_security_policy_regional.json create mode 100644 tests/translator/output/aws-us-gov/api_with_custom_domain_security_policy_edge.json create mode 100644 tests/translator/output/aws-us-gov/api_with_custom_domain_security_policy_private.json create mode 100644 tests/translator/output/aws-us-gov/api_with_custom_domain_security_policy_regional.json diff --git a/integration/resources/expected/single/api_with_custom_domain_security_policy_edge.json b/integration/resources/expected/single/api_with_custom_domain_security_policy_edge.json new file mode 100644 index 0000000000..d45f763995 --- /dev/null +++ b/integration/resources/expected/single/api_with_custom_domain_security_policy_edge.json @@ -0,0 +1,26 @@ +[ + { + "LogicalResourceId": "MyApi", + "ResourceType": "AWS::ApiGateway::RestApi" + }, + { + "LogicalResourceId": "MyApiDeployment", + "ResourceType": "AWS::ApiGateway::Deployment" + }, + { + "LogicalResourceId": "MyApiProdStage", + "ResourceType": "AWS::ApiGateway::Stage" + }, + { + "LogicalResourceId": "ApiGatewayDomainName", + "ResourceType": "AWS::ApiGateway::DomainName" + }, + { + "LogicalResourceId": "MyApiBasePathMapping", + "ResourceType": "AWS::ApiGateway::BasePathMapping" + }, + { + "LogicalResourceId": "RecordSetGroup", + "ResourceType": "AWS::Route53::RecordSetGroup" + } +] diff --git a/integration/resources/expected/single/api_with_custom_domain_security_policy_regional.json b/integration/resources/expected/single/api_with_custom_domain_security_policy_regional.json new file mode 100644 index 0000000000..d45f763995 --- /dev/null +++ b/integration/resources/expected/single/api_with_custom_domain_security_policy_regional.json @@ -0,0 +1,26 @@ +[ + { + "LogicalResourceId": "MyApi", + "ResourceType": "AWS::ApiGateway::RestApi" + }, + { + "LogicalResourceId": "MyApiDeployment", + "ResourceType": "AWS::ApiGateway::Deployment" + }, + { + "LogicalResourceId": "MyApiProdStage", + "ResourceType": "AWS::ApiGateway::Stage" + }, + { + "LogicalResourceId": "ApiGatewayDomainName", + "ResourceType": "AWS::ApiGateway::DomainName" + }, + { + "LogicalResourceId": "MyApiBasePathMapping", + "ResourceType": "AWS::ApiGateway::BasePathMapping" + }, + { + "LogicalResourceId": "RecordSetGroup", + "ResourceType": "AWS::Route53::RecordSetGroup" + } +] diff --git a/integration/resources/templates/single/api_with_custom_domain_security_policy_edge.yaml b/integration/resources/templates/single/api_with_custom_domain_security_policy_edge.yaml new file mode 100644 index 0000000000..b12ed721ff --- /dev/null +++ b/integration/resources/templates/single/api_with_custom_domain_security_policy_edge.yaml @@ -0,0 +1,27 @@ +Parameters: + DomainName: + Type: String + CertificateArn: + Type: String + HostedZoneId: + Type: String + +Resources: + MyApi: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + DefinitionUri: ${definitionuri} + EndpointConfiguration: + Type: EDGE + Domain: + DomainName: !Ref DomainName + CertificateArn: !Ref CertificateArn + EndpointConfiguration: EDGE + SecurityPolicy: SecurityPolicy_TLS13_2025_EDGE + EndpointAccessMode: STRICT + Route53: + HostedZoneId: !Ref HostedZoneId + +Metadata: + SamTransformTest: true diff --git a/integration/resources/templates/single/api_with_custom_domain_security_policy_regional.yaml b/integration/resources/templates/single/api_with_custom_domain_security_policy_regional.yaml new file mode 100644 index 0000000000..4799cc90f5 --- /dev/null +++ b/integration/resources/templates/single/api_with_custom_domain_security_policy_regional.yaml @@ -0,0 +1,27 @@ +Parameters: + DomainName: + Type: String + CertificateArn: + Type: String + HostedZoneId: + Type: String + +Resources: + MyApi: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + DefinitionUri: ${definitionuri} + EndpointConfiguration: + Type: REGIONAL + Domain: + DomainName: !Ref DomainName + CertificateArn: !Ref CertificateArn + EndpointConfiguration: REGIONAL + SecurityPolicy: SecurityPolicy_TLS13_1_3_2025_09 + EndpointAccessMode: STRICT + Route53: + HostedZoneId: !Ref HostedZoneId + +Metadata: + SamTransformTest: true diff --git a/integration/single/test_api_with_custom_domain_security_policy.py b/integration/single/test_api_with_custom_domain_security_policy.py new file mode 100644 index 0000000000..e71e4c9f9d --- /dev/null +++ b/integration/single/test_api_with_custom_domain_security_policy.py @@ -0,0 +1,39 @@ +from unittest.case import skipIf + +from integration.config.service_names import CUSTOM_DOMAIN +from integration.helpers.base_internal_test import BaseInternalTest +from integration.helpers.base_test import nonblocking +from integration.helpers.resource import current_region_not_included + + +@skipIf( + current_region_not_included([CUSTOM_DOMAIN]), + "Custom domain is not supported in this testing region", +) +@nonblocking +class TestApiWithCustomDomainSecurityPolicy(BaseInternalTest): + """ + Test AWS::Serverless::Api with SecurityPolicy and EndpointAccessMode in Domain configuration + """ + + def test_api_with_custom_domain_security_policy_regional(self): + self.create_and_verify_stack("single/api_with_custom_domain_security_policy_regional") + + domain_name_id = self.get_physical_id_by_type("AWS::ApiGateway::DomainName") + result = self.client_provider.api_client.get_domain_name(domainName=domain_name_id) + + end_point_config = result["endpointConfiguration"] + self.assertEqual(["REGIONAL"], end_point_config["types"]) + self.assertEqual("SecurityPolicy_TLS13_1_3_2025_09", result["securityPolicy"]) + self.assertEqual("STRICT", result["endpointAccessMode"]) + + def test_api_with_custom_domain_security_policy_edge(self): + self.create_and_verify_stack("single/api_with_custom_domain_security_policy_edge") + + domain_name_id = self.get_physical_id_by_type("AWS::ApiGateway::DomainName") + result = self.client_provider.api_client.get_domain_name(domainName=domain_name_id) + + end_point_config = result["endpointConfiguration"] + self.assertEqual(["EDGE"], end_point_config["types"]) + self.assertEqual("SecurityPolicy_TLS13_2025_EDGE", result["securityPolicy"]) + self.assertEqual("STRICT", result["endpointAccessMode"]) diff --git a/samtranslator/internal/schema_source/aws_serverless_api.py b/samtranslator/internal/schema_source/aws_serverless_api.py index 7dcce23164..f0dfc73202 100644 --- a/samtranslator/internal/schema_source/aws_serverless_api.py +++ b/samtranslator/internal/schema_source/aws_serverless_api.py @@ -196,6 +196,11 @@ class Domain(BaseModel): EndpointConfiguration: Optional[SamIntrinsicable[Literal["REGIONAL", "EDGE", "PRIVATE"]]] = domain( "EndpointConfiguration" ) + EndpointAccessMode: Optional[PassThroughProp] = passthrough_prop( + DOMAIN_STEM, + "EndpointAccessMode", + ["AWS::ApiGateway::DomainName", "Properties", "EndpointAccessMode"], + ) IpAddressType: Optional[PassThroughProp] # TODO: add documentation; currently unavailable MutualTlsAuthentication: Optional[PassThroughProp] = passthrough_prop( DOMAIN_STEM, diff --git a/samtranslator/internal/schema_source/sam-docs.json b/samtranslator/internal/schema_source/sam-docs.json index c818950bf7..3b90cc7287 100644 --- a/samtranslator/internal/schema_source/sam-docs.json +++ b/samtranslator/internal/schema_source/sam-docs.json @@ -49,6 +49,7 @@ "CertificateArn": "The Amazon Resource Name (https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/ARN.html) of an AWS managed certificate this domain name's endpoint. AWS Certificate Manager is the only supported source. \n*Type*: String \n*Required*: Yes \n*CloudFormation compatibility*: This property is similar to the [`CertificateArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-domainname.html#cfn-apigateway-domainname-certificatearn) property of an `AWS::ApiGateway::DomainName` resource. If `EndpointConfiguration` is set to `REGIONAL` (the default value), `CertificateArn` maps to [RegionalCertificateArn](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-domainname.html#cfn-apigateway-domainname-regionalcertificatearn) in `AWS::ApiGateway::DomainName`. If the `EndpointConfiguration` is set to `EDGE`, `CertificateArn` maps to [CertificateArn](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-domainname.html#cfn-apigateway-domainname-certificatearn) in `AWS::ApiGateway::DomainName`. If `EndpointConfiguration` is set to `PRIVATE`, this property is passed to the [AWS::ApiGateway::DomainNameV2](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-domainnamev2) resource. \n*Additional notes*: For an `EDGE` endpoint, you must create the certificate in the `us-east-1` AWS Region.", "DomainName": "The custom domain name for your API Gateway API. Uppercase letters are not supported. \nAWS SAM generates an [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-domainname.html](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-domainname.html) resource when this property is set. For information about this scenario, see [DomainName property is specified](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources-api.html#sam-specification-generated-resources-api-domain-name). For information about generated CloudFormation resources, see [Generated CloudFormation resources for AWS SAM](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-specification-generated-resources.html). \n*Type*: String \n*Required*: Yes \n*CloudFormation compatibility*: This property is passed directly to the [`DomainName`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-domainname.html#cfn-apigateway-domainname-domainname) property of an `AWS::ApiGateway::DomainName` resource, or to [https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-domainnamev2](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-domainnamev2) when EndpointConfiguration is set to `PRIVATE`.", "EndpointConfiguration": "Defines the type of API Gateway endpoint to map to the custom domain. The value of this property determines how the `CertificateArn` property is mapped in CloudFormation. \n*Valid values*: `EDGE`, `REGIONAL`, or `PRIVATE` \n*Type*: String \n*Required*: No \n*Default*: `REGIONAL` \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", + "EndpointAccessMode": "The endpoint access mode for the custom domain name. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`EndpointAccessMode`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-domainname.html#cfn-apigateway-domainname-endpointaccessmode) property of an `AWS::ApiGateway::DomainName` resource, or to `AWS::ApiGateway::DomainNameV2` when `EndpointConfiguration` is set to `PRIVATE`.", "MutualTlsAuthentication": "The mutual Transport Layer Security (https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/TLS.html) authentication configuration for a custom domain name. \n*Type*: [MutualTlsAuthentication](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-domainname.html#cfn-apigateway-domainname-mutualtlsauthentication) \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`MutualTlsAuthentication`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-domainname.html#cfn-apigateway-domainname-mutualtlsauthentication) property of an `AWS::ApiGateway::DomainName` resource.", "NormalizeBasePath": "Indicates whether non-alphanumeric characters are allowed in basepaths defined by the `BasePath` property. When set to `True`, non-alphanumeric characters are removed from basepaths. \nUse `NormalizeBasePath` with the `BasePath` property. \n*Type*: Boolean \n*Required*: No \n*Default*: True \n*CloudFormation compatibility*: This property is unique to AWS SAM and doesn't have an CloudFormation equivalent.", "OwnershipVerificationCertificateArn": "The ARN of the public certificate issued by ACM to validate ownership of your custom domain. Required only when you configure mutual TLS and you specify an ACM imported or private CA certificate ARN for the `CertificateArn`. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`OwnershipVerificationCertificateArn`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-domainname.html#cfn-apigateway-domainname-ownershipverificationcertificatearn) property of an `AWS::ApiGateway::DomainName` resource.", diff --git a/samtranslator/model/api/api_generator.py b/samtranslator/model/api/api_generator.py index 1bf4e5fc20..a37247907a 100644 --- a/samtranslator/model/api/api_generator.py +++ b/samtranslator/model/api/api_generator.py @@ -744,6 +744,8 @@ def _set_optional_domain_properties(self, domain: Union[ApiGatewayDomainName, Ap return if self.domain.get("SecurityPolicy", None): domain.SecurityPolicy = self.domain["SecurityPolicy"] + if self.domain.get("EndpointAccessMode", None): + domain.EndpointAccessMode = self.domain["EndpointAccessMode"] if self.domain.get("Policy", None): domain.Policy = self.domain["Policy"] if self.domain.get("OwnershipVerificationCertificateArn", None): diff --git a/samtranslator/model/apigateway.py b/samtranslator/model/apigateway.py index eae1197696..96470722d5 100644 --- a/samtranslator/model/apigateway.py +++ b/samtranslator/model/apigateway.py @@ -221,6 +221,7 @@ class ApiGatewayDomainName(Resource): "EndpointConfiguration": GeneratedProperty(), "MutualTlsAuthentication": GeneratedProperty(), "SecurityPolicy": GeneratedProperty(), + "EndpointAccessMode": GeneratedProperty(), "CertificateArn": GeneratedProperty(), "Tags": GeneratedProperty(), "OwnershipVerificationCertificateArn": GeneratedProperty(), @@ -231,6 +232,7 @@ class ApiGatewayDomainName(Resource): EndpointConfiguration: Optional[PassThrough] MutualTlsAuthentication: Optional[Dict[str, Any]] SecurityPolicy: Optional[PassThrough] + EndpointAccessMode: Optional[PassThrough] CertificateArn: Optional[PassThrough] Tags: Optional[PassThrough] OwnershipVerificationCertificateArn: Optional[PassThrough] @@ -242,6 +244,7 @@ class ApiGatewayDomainNameV2(Resource): "DomainName": GeneratedProperty(), "EndpointConfiguration": GeneratedProperty(), "SecurityPolicy": GeneratedProperty(), + "EndpointAccessMode": GeneratedProperty(), "CertificateArn": GeneratedProperty(), "Tags": GeneratedProperty(), "Policy": GeneratedProperty(), @@ -250,6 +253,7 @@ class ApiGatewayDomainNameV2(Resource): DomainName: PassThrough EndpointConfiguration: Optional[PassThrough] SecurityPolicy: Optional[PassThrough] + EndpointAccessMode: Optional[PassThrough] CertificateArn: Optional[PassThrough] Tags: Optional[PassThrough] Policy: Optional[PassThrough] diff --git a/samtranslator/schema/schema.json b/samtranslator/schema/schema.json index 3574458877..f1d9912483 100644 --- a/samtranslator/schema/schema.json +++ b/samtranslator/schema/schema.json @@ -359482,6 +359482,11 @@ "title": "DomainName", "type": "string" }, + "EndpointAccessMode": { + "markdownDescription": "The endpoint access mode for the custom domain name. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`EndpointAccessMode`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-domainname.html#cfn-apigateway-domainname-endpointaccessmode) property of an `AWS::ApiGateway::DomainName` resource, or to `AWS::ApiGateway::DomainNameV2` when `EndpointConfiguration` is set to `PRIVATE`.", + "title": "EndpointAccessMode", + "type": "string" + }, "EndpointConfiguration": { "anyOf": [ { diff --git a/schema_source/sam.schema.json b/schema_source/sam.schema.json index 6af095148c..32c8ae5e9f 100644 --- a/schema_source/sam.schema.json +++ b/schema_source/sam.schema.json @@ -4387,6 +4387,25 @@ ], "title": "DomainName" }, + "EndpointAccessMode": { + "__samPassThrough": { + "markdownDescriptionOverride": "The endpoint access mode for the custom domain name. \n*Type*: String \n*Required*: No \n*CloudFormation compatibility*: This property is passed directly to the [`EndpointAccessMode`](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-apigateway-domainname.html#cfn-apigateway-domainname-endpointaccessmode) property of an `AWS::ApiGateway::DomainName` resource, or to `AWS::ApiGateway::DomainNameV2` when `EndpointConfiguration` is set to `PRIVATE`.", + "schemaPath": [ + "definitions", + "AWS::ApiGateway::DomainName", + "properties", + "Properties", + "properties", + "EndpointAccessMode" + ] + }, + "allOf": [ + { + "$ref": "#/definitions/PassThroughProp" + } + ], + "title": "EndpointAccessMode" + }, "EndpointConfiguration": { "anyOf": [ { diff --git a/tests/translator/input/api_with_custom_domain_security_policy_edge.yaml b/tests/translator/input/api_with_custom_domain_security_policy_edge.yaml new file mode 100644 index 0000000000..4b4d73aee2 --- /dev/null +++ b/tests/translator/input/api_with_custom_domain_security_policy_edge.yaml @@ -0,0 +1,45 @@ +Parameters: + MyDomainName: + Type: String + MyCertificateArn: + Type: String + HostedZoneId: + Type: String + +Resources: + Api: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + EndpointConfiguration: + Type: EDGE + Domain: + DomainName: !Ref MyDomainName + CertificateArn: !Ref MyCertificateArn + EndpointConfiguration: EDGE + SecurityPolicy: SecurityPolicy_TLS13_2025_EDGE + EndpointAccessMode: STRICT + Route53: + HostedZoneId: !Ref HostedZoneId + DefinitionBody: + swagger: '2.0' + info: + title: MockApi + version: '1.0' + paths: + /get: + get: + responses: + '200': + description: 200 response + x-amazon-apigateway-integration: + type: mock + requestTemplates: + application/json: '{"statusCode": 200}' + responses: + default: + statusCode: '200' + responseTemplates: + application/json: '{"message": "Hello World"}' +Metadata: + SamTransformTest: true diff --git a/tests/translator/input/api_with_custom_domain_security_policy_private.yaml b/tests/translator/input/api_with_custom_domain_security_policy_private.yaml new file mode 100644 index 0000000000..871b640fed --- /dev/null +++ b/tests/translator/input/api_with_custom_domain_security_policy_private.yaml @@ -0,0 +1,78 @@ +Parameters: + MyDomainName: + Type: String + MyCertificateArn: + Type: String + HostedZoneId: + Type: String + VpcEndpointId: + Type: String + VpcEndpointDomainName: + Type: String + VpcEndpointHostedZoneId: + Type: String + +Resources: + Api: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + Auth: + ResourcePolicy: + CustomStatements: + - Effect: Allow + Action: execute-api:Invoke + Resource: + - execute-api:/*/*/* + Principal: '*' + Condition: + StringEquals: + aws:SourceVpce: !Ref VpcEndpointId + EndpointConfiguration: + Type: PRIVATE + VPCEndpointIds: + - !Ref VpcEndpointId + Domain: + DomainName: !Ref MyDomainName + CertificateArn: !Ref MyCertificateArn + EndpointConfiguration: PRIVATE + SecurityPolicy: SecurityPolicy_TLS13_1_3_2025_09 + EndpointAccessMode: STRICT + Route53: + HostedZoneId: !Ref HostedZoneId + VpcEndpointDomainName: !Ref VpcEndpointDomainName + VpcEndpointHostedZoneId: !Ref VpcEndpointHostedZoneId + AccessAssociation: + VpcEndpointId: !Ref VpcEndpointId + Policy: + Version: '2012-10-17' + Statement: + - Effect: Allow + Principal: '*' + Action: execute-api:Invoke + Resource: execute-api:/*/*/* + Condition: + StringEquals: + aws:SourceVpce: !Ref VpcEndpointId + DefinitionBody: + swagger: '2.0' + info: + title: MockApi + version: '1.0' + paths: + /get: + get: + responses: + '200': + description: 200 response + x-amazon-apigateway-integration: + type: mock + requestTemplates: + application/json: '{"statusCode": 200}' + responses: + default: + statusCode: '200' + responseTemplates: + application/json: '{"message": "Hello World"}' +Metadata: + SamTransformTest: true diff --git a/tests/translator/input/api_with_custom_domain_security_policy_regional.yaml b/tests/translator/input/api_with_custom_domain_security_policy_regional.yaml new file mode 100644 index 0000000000..bbd9d7189d --- /dev/null +++ b/tests/translator/input/api_with_custom_domain_security_policy_regional.yaml @@ -0,0 +1,45 @@ +Parameters: + MyDomainName: + Type: String + MyCertificateArn: + Type: String + HostedZoneId: + Type: String + +Resources: + Api: + Type: AWS::Serverless::Api + Properties: + StageName: Prod + EndpointConfiguration: + Type: REGIONAL + Domain: + DomainName: !Ref MyDomainName + CertificateArn: !Ref MyCertificateArn + EndpointConfiguration: REGIONAL + SecurityPolicy: SecurityPolicy_TLS13_1_3_2025_09 + EndpointAccessMode: STRICT + Route53: + HostedZoneId: !Ref HostedZoneId + DefinitionBody: + swagger: '2.0' + info: + title: MockApi + version: '1.0' + paths: + /get: + get: + responses: + '200': + description: 200 response + x-amazon-apigateway-integration: + type: mock + requestTemplates: + application/json: '{"statusCode": 200}' + responses: + default: + statusCode: '200' + responseTemplates: + application/json: '{"message": "Hello World"}' +Metadata: + SamTransformTest: true diff --git a/tests/translator/output/api_with_custom_domain_security_policy_edge.json b/tests/translator/output/api_with_custom_domain_security_policy_edge.json new file mode 100644 index 0000000000..67b32d5b9b --- /dev/null +++ b/tests/translator/output/api_with_custom_domain_security_policy_edge.json @@ -0,0 +1,142 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyCertificateArn": { + "Type": "String" + }, + "MyDomainName": { + "Type": "String" + } + }, + "Resources": { + "Api": { + "Properties": { + "Body": { + "info": { + "title": "MockApi", + "version": "1.0" + }, + "paths": { + "/get": { + "get": { + "responses": { + "200": { + "description": "200 response" + } + }, + "x-amazon-apigateway-integration": { + "requestTemplates": { + "application/json": "{\"statusCode\": 200}" + }, + "responses": { + "default": { + "responseTemplates": { + "application/json": "{\"message\": \"Hello World\"}" + }, + "statusCode": "200" + } + }, + "type": "mock" + } + } + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "EDGE" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "EDGE" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiBasePathMapping": { + "Properties": { + "DomainName": { + "Ref": "ApiGatewayDomainNamee12ae193a4" + }, + "RestApiId": { + "Ref": "Api" + }, + "Stage": { + "Ref": "ApiProdStage" + } + }, + "Type": "AWS::ApiGateway::BasePathMapping" + }, + "ApiDeploymentb4212ace49": { + "Properties": { + "Description": "RestApi deployment id: b4212ace4953ed4f1debfa33eda1b29707d537e1", + "RestApiId": { + "Ref": "Api" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiGatewayDomainNamee12ae193a4": { + "Properties": { + "CertificateArn": { + "Ref": "MyCertificateArn" + }, + "DomainName": { + "Ref": "MyDomainName" + }, + "EndpointAccessMode": "STRICT", + "EndpointConfiguration": { + "Types": [ + "EDGE" + ] + }, + "SecurityPolicy": "SecurityPolicy_TLS13_2025_EDGE" + }, + "Type": "AWS::ApiGateway::DomainName" + }, + "ApiProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiDeploymentb4212ace49" + }, + "RestApiId": { + "Ref": "Api" + }, + "StageName": "Prod" + }, + "Type": "AWS::ApiGateway::Stage" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNamee12ae193a4", + "DistributionDomainName" + ] + }, + "HostedZoneId": "Z2FDTNDATAQYW2" + }, + "Name": { + "Ref": "MyDomainName" + }, + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/api_with_custom_domain_security_policy_private.json b/tests/translator/output/api_with_custom_domain_security_policy_private.json new file mode 100644 index 0000000000..163ca73df2 --- /dev/null +++ b/tests/translator/output/api_with_custom_domain_security_policy_private.json @@ -0,0 +1,205 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyCertificateArn": { + "Type": "String" + }, + "MyDomainName": { + "Type": "String" + }, + "VpcEndpointDomainName": { + "Type": "String" + }, + "VpcEndpointHostedZoneId": { + "Type": "String" + }, + "VpcEndpointId": { + "Type": "String" + } + }, + "Resources": { + "Api": { + "Properties": { + "Body": { + "info": { + "title": "MockApi", + "version": "1.0" + }, + "paths": { + "/get": { + "get": { + "responses": { + "200": { + "description": "200 response" + } + }, + "x-amazon-apigateway-integration": { + "requestTemplates": { + "application/json": "{\"statusCode\": 200}" + }, + "responses": { + "default": { + "responseTemplates": { + "application/json": "{\"message\": \"Hello World\"}" + }, + "statusCode": "200" + } + }, + "type": "mock" + } + } + } + }, + "swagger": "2.0", + "x-amazon-apigateway-policy": { + "Statement": [ + { + "Action": "execute-api:Invoke", + "Condition": { + "StringEquals": { + "aws:SourceVpce": { + "Ref": "VpcEndpointId" + } + } + }, + "Effect": "Allow", + "Principal": "*", + "Resource": [ + "execute-api:/*/*/*" + ] + } + ], + "Version": "2012-10-17" + } + }, + "EndpointConfiguration": { + "Types": [ + "PRIVATE" + ], + "VpcEndpointIds": [ + { + "Ref": "VpcEndpointId" + } + ] + }, + "Parameters": { + "endpointConfigurationTypes": "PRIVATE" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiBasePathMapping": { + "Properties": { + "DomainNameArn": { + "Ref": "ApiGatewayDomainNameV2e12ae193a4" + }, + "RestApiId": { + "Ref": "Api" + }, + "Stage": { + "Ref": "ApiProdStage" + } + }, + "Type": "AWS::ApiGateway::BasePathMappingV2" + }, + "ApiDeployment201b5a52ed": { + "Properties": { + "Description": "RestApi deployment id: 201b5a52ed6f40089c7e4d46db54f63bdd4dd157", + "RestApiId": { + "Ref": "Api" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiGatewayDomainNameV2e12ae193a4": { + "Properties": { + "CertificateArn": { + "Ref": "MyCertificateArn" + }, + "DomainName": { + "Ref": "MyDomainName" + }, + "EndpointAccessMode": "STRICT", + "EndpointConfiguration": { + "Types": [ + "PRIVATE" + ] + }, + "Policy": { + "Statement": [ + { + "Action": "execute-api:Invoke", + "Condition": { + "StringEquals": { + "aws:SourceVpce": { + "Ref": "VpcEndpointId" + } + } + }, + "Effect": "Allow", + "Principal": "*", + "Resource": "execute-api:/*/*/*" + } + ], + "Version": "2012-10-17" + }, + "SecurityPolicy": "SecurityPolicy_TLS13_1_3_2025_09" + }, + "Type": "AWS::ApiGateway::DomainNameV2" + }, + "ApiProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiDeployment201b5a52ed" + }, + "RestApiId": { + "Ref": "Api" + }, + "StageName": "Prod" + }, + "Type": "AWS::ApiGateway::Stage" + }, + "DomainNameAccessAssociationf4f910dee7": { + "Properties": { + "AccessAssociationSource": { + "Ref": "VpcEndpointId" + }, + "AccessAssociationSourceType": "VPCE", + "DomainNameArn": { + "Ref": "ApiGatewayDomainNameV2e12ae193a4" + } + }, + "Type": "AWS::ApiGateway::DomainNameAccessAssociation" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Ref": "VpcEndpointDomainName" + }, + "HostedZoneId": { + "Ref": "VpcEndpointHostedZoneId" + } + }, + "Name": { + "Ref": "MyDomainName" + }, + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/api_with_custom_domain_security_policy_regional.json b/tests/translator/output/api_with_custom_domain_security_policy_regional.json new file mode 100644 index 0000000000..ca47621511 --- /dev/null +++ b/tests/translator/output/api_with_custom_domain_security_policy_regional.json @@ -0,0 +1,147 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyCertificateArn": { + "Type": "String" + }, + "MyDomainName": { + "Type": "String" + } + }, + "Resources": { + "Api": { + "Properties": { + "Body": { + "info": { + "title": "MockApi", + "version": "1.0" + }, + "paths": { + "/get": { + "get": { + "responses": { + "200": { + "description": "200 response" + } + }, + "x-amazon-apigateway-integration": { + "requestTemplates": { + "application/json": "{\"statusCode\": 200}" + }, + "responses": { + "default": { + "responseTemplates": { + "application/json": "{\"message\": \"Hello World\"}" + }, + "statusCode": "200" + } + }, + "type": "mock" + } + } + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiBasePathMapping": { + "Properties": { + "DomainName": { + "Ref": "ApiGatewayDomainNamee12ae193a4" + }, + "RestApiId": { + "Ref": "Api" + }, + "Stage": { + "Ref": "ApiProdStage" + } + }, + "Type": "AWS::ApiGateway::BasePathMapping" + }, + "ApiDeployment84a6e2abbb": { + "Properties": { + "Description": "RestApi deployment id: 84a6e2abbbe8b085641de8b944a7dd72a4d01764", + "RestApiId": { + "Ref": "Api" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiGatewayDomainNamee12ae193a4": { + "Properties": { + "DomainName": { + "Ref": "MyDomainName" + }, + "EndpointAccessMode": "STRICT", + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "RegionalCertificateArn": { + "Ref": "MyCertificateArn" + }, + "SecurityPolicy": "SecurityPolicy_TLS13_1_3_2025_09" + }, + "Type": "AWS::ApiGateway::DomainName" + }, + "ApiProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiDeployment84a6e2abbb" + }, + "RestApiId": { + "Ref": "Api" + }, + "StageName": "Prod" + }, + "Type": "AWS::ApiGateway::Stage" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNamee12ae193a4", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNamee12ae193a4", + "RegionalHostedZoneId" + ] + } + }, + "Name": { + "Ref": "MyDomainName" + }, + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/aws-cn/api_with_custom_domain_security_policy_edge.json b/tests/translator/output/aws-cn/api_with_custom_domain_security_policy_edge.json new file mode 100644 index 0000000000..67b32d5b9b --- /dev/null +++ b/tests/translator/output/aws-cn/api_with_custom_domain_security_policy_edge.json @@ -0,0 +1,142 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyCertificateArn": { + "Type": "String" + }, + "MyDomainName": { + "Type": "String" + } + }, + "Resources": { + "Api": { + "Properties": { + "Body": { + "info": { + "title": "MockApi", + "version": "1.0" + }, + "paths": { + "/get": { + "get": { + "responses": { + "200": { + "description": "200 response" + } + }, + "x-amazon-apigateway-integration": { + "requestTemplates": { + "application/json": "{\"statusCode\": 200}" + }, + "responses": { + "default": { + "responseTemplates": { + "application/json": "{\"message\": \"Hello World\"}" + }, + "statusCode": "200" + } + }, + "type": "mock" + } + } + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "EDGE" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "EDGE" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiBasePathMapping": { + "Properties": { + "DomainName": { + "Ref": "ApiGatewayDomainNamee12ae193a4" + }, + "RestApiId": { + "Ref": "Api" + }, + "Stage": { + "Ref": "ApiProdStage" + } + }, + "Type": "AWS::ApiGateway::BasePathMapping" + }, + "ApiDeploymentb4212ace49": { + "Properties": { + "Description": "RestApi deployment id: b4212ace4953ed4f1debfa33eda1b29707d537e1", + "RestApiId": { + "Ref": "Api" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiGatewayDomainNamee12ae193a4": { + "Properties": { + "CertificateArn": { + "Ref": "MyCertificateArn" + }, + "DomainName": { + "Ref": "MyDomainName" + }, + "EndpointAccessMode": "STRICT", + "EndpointConfiguration": { + "Types": [ + "EDGE" + ] + }, + "SecurityPolicy": "SecurityPolicy_TLS13_2025_EDGE" + }, + "Type": "AWS::ApiGateway::DomainName" + }, + "ApiProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiDeploymentb4212ace49" + }, + "RestApiId": { + "Ref": "Api" + }, + "StageName": "Prod" + }, + "Type": "AWS::ApiGateway::Stage" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNamee12ae193a4", + "DistributionDomainName" + ] + }, + "HostedZoneId": "Z2FDTNDATAQYW2" + }, + "Name": { + "Ref": "MyDomainName" + }, + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/aws-cn/api_with_custom_domain_security_policy_private.json b/tests/translator/output/aws-cn/api_with_custom_domain_security_policy_private.json new file mode 100644 index 0000000000..163ca73df2 --- /dev/null +++ b/tests/translator/output/aws-cn/api_with_custom_domain_security_policy_private.json @@ -0,0 +1,205 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyCertificateArn": { + "Type": "String" + }, + "MyDomainName": { + "Type": "String" + }, + "VpcEndpointDomainName": { + "Type": "String" + }, + "VpcEndpointHostedZoneId": { + "Type": "String" + }, + "VpcEndpointId": { + "Type": "String" + } + }, + "Resources": { + "Api": { + "Properties": { + "Body": { + "info": { + "title": "MockApi", + "version": "1.0" + }, + "paths": { + "/get": { + "get": { + "responses": { + "200": { + "description": "200 response" + } + }, + "x-amazon-apigateway-integration": { + "requestTemplates": { + "application/json": "{\"statusCode\": 200}" + }, + "responses": { + "default": { + "responseTemplates": { + "application/json": "{\"message\": \"Hello World\"}" + }, + "statusCode": "200" + } + }, + "type": "mock" + } + } + } + }, + "swagger": "2.0", + "x-amazon-apigateway-policy": { + "Statement": [ + { + "Action": "execute-api:Invoke", + "Condition": { + "StringEquals": { + "aws:SourceVpce": { + "Ref": "VpcEndpointId" + } + } + }, + "Effect": "Allow", + "Principal": "*", + "Resource": [ + "execute-api:/*/*/*" + ] + } + ], + "Version": "2012-10-17" + } + }, + "EndpointConfiguration": { + "Types": [ + "PRIVATE" + ], + "VpcEndpointIds": [ + { + "Ref": "VpcEndpointId" + } + ] + }, + "Parameters": { + "endpointConfigurationTypes": "PRIVATE" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiBasePathMapping": { + "Properties": { + "DomainNameArn": { + "Ref": "ApiGatewayDomainNameV2e12ae193a4" + }, + "RestApiId": { + "Ref": "Api" + }, + "Stage": { + "Ref": "ApiProdStage" + } + }, + "Type": "AWS::ApiGateway::BasePathMappingV2" + }, + "ApiDeployment201b5a52ed": { + "Properties": { + "Description": "RestApi deployment id: 201b5a52ed6f40089c7e4d46db54f63bdd4dd157", + "RestApiId": { + "Ref": "Api" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiGatewayDomainNameV2e12ae193a4": { + "Properties": { + "CertificateArn": { + "Ref": "MyCertificateArn" + }, + "DomainName": { + "Ref": "MyDomainName" + }, + "EndpointAccessMode": "STRICT", + "EndpointConfiguration": { + "Types": [ + "PRIVATE" + ] + }, + "Policy": { + "Statement": [ + { + "Action": "execute-api:Invoke", + "Condition": { + "StringEquals": { + "aws:SourceVpce": { + "Ref": "VpcEndpointId" + } + } + }, + "Effect": "Allow", + "Principal": "*", + "Resource": "execute-api:/*/*/*" + } + ], + "Version": "2012-10-17" + }, + "SecurityPolicy": "SecurityPolicy_TLS13_1_3_2025_09" + }, + "Type": "AWS::ApiGateway::DomainNameV2" + }, + "ApiProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiDeployment201b5a52ed" + }, + "RestApiId": { + "Ref": "Api" + }, + "StageName": "Prod" + }, + "Type": "AWS::ApiGateway::Stage" + }, + "DomainNameAccessAssociationf4f910dee7": { + "Properties": { + "AccessAssociationSource": { + "Ref": "VpcEndpointId" + }, + "AccessAssociationSourceType": "VPCE", + "DomainNameArn": { + "Ref": "ApiGatewayDomainNameV2e12ae193a4" + } + }, + "Type": "AWS::ApiGateway::DomainNameAccessAssociation" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Ref": "VpcEndpointDomainName" + }, + "HostedZoneId": { + "Ref": "VpcEndpointHostedZoneId" + } + }, + "Name": { + "Ref": "MyDomainName" + }, + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/aws-cn/api_with_custom_domain_security_policy_regional.json b/tests/translator/output/aws-cn/api_with_custom_domain_security_policy_regional.json new file mode 100644 index 0000000000..ca47621511 --- /dev/null +++ b/tests/translator/output/aws-cn/api_with_custom_domain_security_policy_regional.json @@ -0,0 +1,147 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyCertificateArn": { + "Type": "String" + }, + "MyDomainName": { + "Type": "String" + } + }, + "Resources": { + "Api": { + "Properties": { + "Body": { + "info": { + "title": "MockApi", + "version": "1.0" + }, + "paths": { + "/get": { + "get": { + "responses": { + "200": { + "description": "200 response" + } + }, + "x-amazon-apigateway-integration": { + "requestTemplates": { + "application/json": "{\"statusCode\": 200}" + }, + "responses": { + "default": { + "responseTemplates": { + "application/json": "{\"message\": \"Hello World\"}" + }, + "statusCode": "200" + } + }, + "type": "mock" + } + } + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiBasePathMapping": { + "Properties": { + "DomainName": { + "Ref": "ApiGatewayDomainNamee12ae193a4" + }, + "RestApiId": { + "Ref": "Api" + }, + "Stage": { + "Ref": "ApiProdStage" + } + }, + "Type": "AWS::ApiGateway::BasePathMapping" + }, + "ApiDeployment84a6e2abbb": { + "Properties": { + "Description": "RestApi deployment id: 84a6e2abbbe8b085641de8b944a7dd72a4d01764", + "RestApiId": { + "Ref": "Api" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiGatewayDomainNamee12ae193a4": { + "Properties": { + "DomainName": { + "Ref": "MyDomainName" + }, + "EndpointAccessMode": "STRICT", + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "RegionalCertificateArn": { + "Ref": "MyCertificateArn" + }, + "SecurityPolicy": "SecurityPolicy_TLS13_1_3_2025_09" + }, + "Type": "AWS::ApiGateway::DomainName" + }, + "ApiProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiDeployment84a6e2abbb" + }, + "RestApiId": { + "Ref": "Api" + }, + "StageName": "Prod" + }, + "Type": "AWS::ApiGateway::Stage" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNamee12ae193a4", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNamee12ae193a4", + "RegionalHostedZoneId" + ] + } + }, + "Name": { + "Ref": "MyDomainName" + }, + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/aws-us-gov/api_with_custom_domain_security_policy_edge.json b/tests/translator/output/aws-us-gov/api_with_custom_domain_security_policy_edge.json new file mode 100644 index 0000000000..67b32d5b9b --- /dev/null +++ b/tests/translator/output/aws-us-gov/api_with_custom_domain_security_policy_edge.json @@ -0,0 +1,142 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyCertificateArn": { + "Type": "String" + }, + "MyDomainName": { + "Type": "String" + } + }, + "Resources": { + "Api": { + "Properties": { + "Body": { + "info": { + "title": "MockApi", + "version": "1.0" + }, + "paths": { + "/get": { + "get": { + "responses": { + "200": { + "description": "200 response" + } + }, + "x-amazon-apigateway-integration": { + "requestTemplates": { + "application/json": "{\"statusCode\": 200}" + }, + "responses": { + "default": { + "responseTemplates": { + "application/json": "{\"message\": \"Hello World\"}" + }, + "statusCode": "200" + } + }, + "type": "mock" + } + } + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "EDGE" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "EDGE" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiBasePathMapping": { + "Properties": { + "DomainName": { + "Ref": "ApiGatewayDomainNamee12ae193a4" + }, + "RestApiId": { + "Ref": "Api" + }, + "Stage": { + "Ref": "ApiProdStage" + } + }, + "Type": "AWS::ApiGateway::BasePathMapping" + }, + "ApiDeploymentb4212ace49": { + "Properties": { + "Description": "RestApi deployment id: b4212ace4953ed4f1debfa33eda1b29707d537e1", + "RestApiId": { + "Ref": "Api" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiGatewayDomainNamee12ae193a4": { + "Properties": { + "CertificateArn": { + "Ref": "MyCertificateArn" + }, + "DomainName": { + "Ref": "MyDomainName" + }, + "EndpointAccessMode": "STRICT", + "EndpointConfiguration": { + "Types": [ + "EDGE" + ] + }, + "SecurityPolicy": "SecurityPolicy_TLS13_2025_EDGE" + }, + "Type": "AWS::ApiGateway::DomainName" + }, + "ApiProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiDeploymentb4212ace49" + }, + "RestApiId": { + "Ref": "Api" + }, + "StageName": "Prod" + }, + "Type": "AWS::ApiGateway::Stage" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNamee12ae193a4", + "DistributionDomainName" + ] + }, + "HostedZoneId": "Z2FDTNDATAQYW2" + }, + "Name": { + "Ref": "MyDomainName" + }, + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/aws-us-gov/api_with_custom_domain_security_policy_private.json b/tests/translator/output/aws-us-gov/api_with_custom_domain_security_policy_private.json new file mode 100644 index 0000000000..163ca73df2 --- /dev/null +++ b/tests/translator/output/aws-us-gov/api_with_custom_domain_security_policy_private.json @@ -0,0 +1,205 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyCertificateArn": { + "Type": "String" + }, + "MyDomainName": { + "Type": "String" + }, + "VpcEndpointDomainName": { + "Type": "String" + }, + "VpcEndpointHostedZoneId": { + "Type": "String" + }, + "VpcEndpointId": { + "Type": "String" + } + }, + "Resources": { + "Api": { + "Properties": { + "Body": { + "info": { + "title": "MockApi", + "version": "1.0" + }, + "paths": { + "/get": { + "get": { + "responses": { + "200": { + "description": "200 response" + } + }, + "x-amazon-apigateway-integration": { + "requestTemplates": { + "application/json": "{\"statusCode\": 200}" + }, + "responses": { + "default": { + "responseTemplates": { + "application/json": "{\"message\": \"Hello World\"}" + }, + "statusCode": "200" + } + }, + "type": "mock" + } + } + } + }, + "swagger": "2.0", + "x-amazon-apigateway-policy": { + "Statement": [ + { + "Action": "execute-api:Invoke", + "Condition": { + "StringEquals": { + "aws:SourceVpce": { + "Ref": "VpcEndpointId" + } + } + }, + "Effect": "Allow", + "Principal": "*", + "Resource": [ + "execute-api:/*/*/*" + ] + } + ], + "Version": "2012-10-17" + } + }, + "EndpointConfiguration": { + "Types": [ + "PRIVATE" + ], + "VpcEndpointIds": [ + { + "Ref": "VpcEndpointId" + } + ] + }, + "Parameters": { + "endpointConfigurationTypes": "PRIVATE" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiBasePathMapping": { + "Properties": { + "DomainNameArn": { + "Ref": "ApiGatewayDomainNameV2e12ae193a4" + }, + "RestApiId": { + "Ref": "Api" + }, + "Stage": { + "Ref": "ApiProdStage" + } + }, + "Type": "AWS::ApiGateway::BasePathMappingV2" + }, + "ApiDeployment201b5a52ed": { + "Properties": { + "Description": "RestApi deployment id: 201b5a52ed6f40089c7e4d46db54f63bdd4dd157", + "RestApiId": { + "Ref": "Api" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiGatewayDomainNameV2e12ae193a4": { + "Properties": { + "CertificateArn": { + "Ref": "MyCertificateArn" + }, + "DomainName": { + "Ref": "MyDomainName" + }, + "EndpointAccessMode": "STRICT", + "EndpointConfiguration": { + "Types": [ + "PRIVATE" + ] + }, + "Policy": { + "Statement": [ + { + "Action": "execute-api:Invoke", + "Condition": { + "StringEquals": { + "aws:SourceVpce": { + "Ref": "VpcEndpointId" + } + } + }, + "Effect": "Allow", + "Principal": "*", + "Resource": "execute-api:/*/*/*" + } + ], + "Version": "2012-10-17" + }, + "SecurityPolicy": "SecurityPolicy_TLS13_1_3_2025_09" + }, + "Type": "AWS::ApiGateway::DomainNameV2" + }, + "ApiProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiDeployment201b5a52ed" + }, + "RestApiId": { + "Ref": "Api" + }, + "StageName": "Prod" + }, + "Type": "AWS::ApiGateway::Stage" + }, + "DomainNameAccessAssociationf4f910dee7": { + "Properties": { + "AccessAssociationSource": { + "Ref": "VpcEndpointId" + }, + "AccessAssociationSourceType": "VPCE", + "DomainNameArn": { + "Ref": "ApiGatewayDomainNameV2e12ae193a4" + } + }, + "Type": "AWS::ApiGateway::DomainNameAccessAssociation" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Ref": "VpcEndpointDomainName" + }, + "HostedZoneId": { + "Ref": "VpcEndpointHostedZoneId" + } + }, + "Name": { + "Ref": "MyDomainName" + }, + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +} diff --git a/tests/translator/output/aws-us-gov/api_with_custom_domain_security_policy_regional.json b/tests/translator/output/aws-us-gov/api_with_custom_domain_security_policy_regional.json new file mode 100644 index 0000000000..ca47621511 --- /dev/null +++ b/tests/translator/output/aws-us-gov/api_with_custom_domain_security_policy_regional.json @@ -0,0 +1,147 @@ +{ + "Metadata": { + "SamTransformTest": true + }, + "Parameters": { + "HostedZoneId": { + "Type": "String" + }, + "MyCertificateArn": { + "Type": "String" + }, + "MyDomainName": { + "Type": "String" + } + }, + "Resources": { + "Api": { + "Properties": { + "Body": { + "info": { + "title": "MockApi", + "version": "1.0" + }, + "paths": { + "/get": { + "get": { + "responses": { + "200": { + "description": "200 response" + } + }, + "x-amazon-apigateway-integration": { + "requestTemplates": { + "application/json": "{\"statusCode\": 200}" + }, + "responses": { + "default": { + "responseTemplates": { + "application/json": "{\"message\": \"Hello World\"}" + }, + "statusCode": "200" + } + }, + "type": "mock" + } + } + } + }, + "swagger": "2.0" + }, + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "Parameters": { + "endpointConfigurationTypes": "REGIONAL" + } + }, + "Type": "AWS::ApiGateway::RestApi" + }, + "ApiBasePathMapping": { + "Properties": { + "DomainName": { + "Ref": "ApiGatewayDomainNamee12ae193a4" + }, + "RestApiId": { + "Ref": "Api" + }, + "Stage": { + "Ref": "ApiProdStage" + } + }, + "Type": "AWS::ApiGateway::BasePathMapping" + }, + "ApiDeployment84a6e2abbb": { + "Properties": { + "Description": "RestApi deployment id: 84a6e2abbbe8b085641de8b944a7dd72a4d01764", + "RestApiId": { + "Ref": "Api" + }, + "StageName": "Stage" + }, + "Type": "AWS::ApiGateway::Deployment" + }, + "ApiGatewayDomainNamee12ae193a4": { + "Properties": { + "DomainName": { + "Ref": "MyDomainName" + }, + "EndpointAccessMode": "STRICT", + "EndpointConfiguration": { + "Types": [ + "REGIONAL" + ] + }, + "RegionalCertificateArn": { + "Ref": "MyCertificateArn" + }, + "SecurityPolicy": "SecurityPolicy_TLS13_1_3_2025_09" + }, + "Type": "AWS::ApiGateway::DomainName" + }, + "ApiProdStage": { + "Properties": { + "DeploymentId": { + "Ref": "ApiDeployment84a6e2abbb" + }, + "RestApiId": { + "Ref": "Api" + }, + "StageName": "Prod" + }, + "Type": "AWS::ApiGateway::Stage" + }, + "RecordSetGroup1194dea82a": { + "Properties": { + "HostedZoneId": { + "Ref": "HostedZoneId" + }, + "RecordSets": [ + { + "AliasTarget": { + "DNSName": { + "Fn::GetAtt": [ + "ApiGatewayDomainNamee12ae193a4", + "RegionalDomainName" + ] + }, + "HostedZoneId": { + "Fn::GetAtt": [ + "ApiGatewayDomainNamee12ae193a4", + "RegionalHostedZoneId" + ] + } + }, + "Name": { + "Ref": "MyDomainName" + }, + "Type": "A" + } + ] + }, + "Type": "AWS::Route53::RecordSetGroup" + } + } +}