From 8dc28c2d249664da8344ea48e12677c542734ce6 Mon Sep 17 00:00:00 2001 From: Chengjun Li Date: Tue, 21 Jul 2026 17:12:43 -0700 Subject: [PATCH] fix(integ-tests): Add IAM auth to API Gateway resources in integration tests Add IAM authorization to all API Gateway resources created by integration tests. Changes: - WebSocket APIs: Added Auth.AuthType: AWS_IAM (11 templates) - HTTP APIs: Added Auth.EnableIamAuthorizer + DefaultAuthorizer (10 templates) - REST APIs: Added Auth.DefaultAuthorizer: AWS_IAM (27 templates) - Added SigV4 request signing helpers to base_test.py - Updated tests that verify HTTP responses to use SigV4 signed requests - Updated expected status code from 403 to 404 for deleted routes with IAM auth --- .../test_function_with_http_api.py | 10 +-- .../test_function_with_implicit_http_api.py | 6 +- integration/helpers/base_test.py | 83 +++++++++++++++++++ .../api_with_binary_media_types.yaml | 2 + ...nary_media_types_with_definition_body.yaml | 2 + ...ia_types_with_definition_body_openapi.yaml | 2 + .../api_with_custom_domains_edge.yaml | 2 + ...api_with_disable_execute_api_endpoint.yaml | 2 + ...isable_execute_api_endpoint_openapi_3.yaml | 2 + .../api_with_endpoint_configuration.yaml | 2 + .../api_with_endpoint_configuration_dict.yaml | 2 + .../api_with_fail_on_warnings.yaml | 2 + .../combination/api_with_method_settings.yaml | 2 + .../combination/api_with_request_models.yaml | 2 + .../api_with_request_models_openapi.yaml | 2 + .../combination/api_with_resource_refs.yaml | 2 + ...function_with_alias_and_event_sources.yaml | 2 + .../combination/function_with_api.yaml | 2 + .../combination/function_with_http_api.yaml | 3 + .../function_with_http_api_default_path.yaml | 3 + .../function_with_implicit_http_api.yaml | 6 ++ ...http_api_with_custom_domains_regional.yaml | 3 + ...mains_regional_ownership_verification.yaml | 3 + ...th_disable_execute_api_endpoint_false.yaml | 3 + ...ith_disable_execute_api_endpoint_true.yaml | 3 + ...il_on_warnings_and_default_stage_name.yaml | 3 + .../intrinsics_code_definition_uri.yaml | 2 + .../intrinsics_serverless_api.yaml | 4 + .../combination/state_machine_with_api.yaml | 2 + .../combination/websocket_api_basic.yaml | 2 + .../websocket_api_basic_config.yaml | 2 + ...websocket_api_custom_domains_regional.yaml | 2 + .../websocket_api_multiple_api.yaml | 4 + .../websocket_api_multiple_routes.yaml | 2 + .../websocket_api_route_config.yaml | 2 + .../websocket_api_route_settings.yaml | 2 + .../websocket_api_stage_config.yaml | 2 + ...api_with_disable_execute_api_endpoint.yaml | 2 + ...et_api_with_disable_schema_validation.yaml | 2 + .../websocket_api_with_ip_address_type.yaml | 2 + ...th_custom_domain_security_policy_edge.yaml | 2 + ...ustom_domain_security_policy_regional.yaml | 2 + .../single/api_with_domain_ipaddresstype.yaml | 2 + .../single/api_with_endpoint_access_mode.yaml | 2 + .../single/api_with_ipaddresstype.yaml | 2 + .../resources/templates/single/basic_api.yaml | 2 + .../single/basic_api_inline_openapi.yaml | 2 + .../single/basic_api_inline_swagger.yaml | 2 + .../templates/single/basic_api_with_mode.yaml | 2 + .../single/basic_api_with_mode_update.yaml | 2 + .../templates/single/basic_api_with_tags.yaml | 2 + .../templates/single/basic_http_api.yaml | 3 + .../function_alias_with_http_api_events.yaml | 4 + .../single/function_with_http_api_events.yaml | 4 + .../single/state_machine_with_api.yaml | 2 + integration/single/test_basic_api.py | 12 +-- 56 files changed, 221 insertions(+), 14 deletions(-) diff --git a/integration/combination/test_function_with_http_api.py b/integration/combination/test_function_with_http_api.py index db0bd4a893..fff6a19c5c 100644 --- a/integration/combination/test_function_with_http_api.py +++ b/integration/combination/test_function_with_http_api.py @@ -18,9 +18,9 @@ def test_function_with_http_api(self): stack_outputs = self.get_stack_outputs() base_url = stack_outputs["ApiUrl"] - self.verify_get_request_response(base_url + "some/path", 200) - self.verify_get_request_response(base_url + "something", 404) - self.verify_get_request_response(base_url + "another/endpoint", 404) + self.verify_get_request_response_sigv4(base_url + "some/path", 200) + self.verify_get_request_response_sigv4(base_url + "something", 404) + self.verify_get_request_response_sigv4(base_url + "another/endpoint", 404) def test_function_with_http_api_default_path(self): self.create_and_verify_stack("combination/function_with_http_api_default_path") @@ -28,5 +28,5 @@ def test_function_with_http_api_default_path(self): stack_outputs = self.get_stack_outputs() base_url = stack_outputs["ApiUrl"] # The $default route catches requests that don't explicitly match other routes - self.verify_get_request_response(base_url, 200) - self.verify_get_request_response(base_url + "something", 200) + self.verify_get_request_response_sigv4(base_url, 200) + self.verify_get_request_response_sigv4(base_url + "something", 200) diff --git a/integration/combination/test_function_with_implicit_http_api.py b/integration/combination/test_function_with_implicit_http_api.py index 6ccec0c09f..f3d2784233 100644 --- a/integration/combination/test_function_with_implicit_http_api.py +++ b/integration/combination/test_function_with_implicit_http_api.py @@ -12,6 +12,6 @@ def test_function_with_implicit_api(self): stack_outputs = self.get_stack_outputs() base_url = stack_outputs["ApiUrl"] - self.verify_get_request_response(base_url, 200) - self.verify_get_request_response(base_url + "something", 200) - self.verify_get_request_response(base_url + "another/endpoint", 200) + self.verify_get_request_response_sigv4(base_url, 200) + self.verify_get_request_response_sigv4(base_url + "something", 200) + self.verify_get_request_response_sigv4(base_url + "another/endpoint", 200) diff --git a/integration/helpers/base_test.py b/integration/helpers/base_test.py index b2c9fcf2f8..dd284c1cbb 100644 --- a/integration/helpers/base_test.py +++ b/integration/helpers/base_test.py @@ -4,11 +4,14 @@ import shutil from pathlib import Path from unittest.case import TestCase +from urllib.parse import urlparse import boto3 import botocore import pytest import requests +from botocore.auth import SigV4Auth +from botocore.awsrequest import AWSRequest from samtranslator.translator.arn_generator import ArnGenerator from samtranslator.yaml_helper import yaml_parse from tenacity import ( @@ -538,6 +541,25 @@ def verify_get_request_response(self, url, expected_status_code, headers=None): ) return response + @retry( + stop=stop_after_attempt(6), + wait=wait_exponential(multiplier=1, min=16, max=64) + wait_random(0, 1), + retry=retry_if_exception_type(StatusCodeError), + after=after_log(LOG, logging.WARNING), + reraise=True, + ) + def verify_get_request_response_sigv4(self, url, expected_status_code, headers=None): + """ + Verify if a SigV4-signed get request to a certain url returns the expected status code. + Use this for APIs with IAM authorization. + """ + response = self.do_get_request_with_sigv4(url, headers) + if response.status_code != expected_status_code: + raise StatusCodeError( + f"SigV4 request to {url} failed with status: {response.status_code}, expected status: {expected_status_code}" + ) + return response + @retry( stop=stop_after_attempt(6), wait=wait_exponential(multiplier=1, min=16, max=64) + wait_random(0, 1), @@ -581,6 +603,22 @@ def verify_post_request(self, url: str, body_obj, expected_status_code: int, hea ) return response + @retry( + stop=stop_after_attempt(6), + wait=wait_exponential(multiplier=1, min=16, max=64) + wait_random(0, 1), + retry=retry_if_exception_type(StatusCodeError), + after=after_log(LOG, logging.WARNING), + reraise=True, + ) + def verify_post_request_sigv4(self, url: str, body_obj, expected_status_code: int, headers=None): + """Return response to SigV4-signed POST request and verify matches expected status code.""" + response = self.do_post_request_with_sigv4(url, body_obj, headers) + if response.status_code != expected_status_code: + raise StatusCodeError( + f"SigV4 POST request to {url} failed with status: {response.status_code}, expected status: {expected_status_code}" + ) + return response + def get_default_test_template_parameters(self): """ get the default template parameters @@ -636,6 +674,29 @@ def do_get_request_with_logging(self, url, headers=None): ) return response + def do_get_request_with_sigv4(self, url, headers=None): + """ + Perform a SigV4-signed GET request to an APIGW endpoint with IAM auth. + """ + parsed = urlparse(url) + request_headers = {"host": parsed.hostname} + if headers: + request_headers.update(headers) + + aws_request = AWSRequest(method="GET", url=url, headers=request_headers) + session = botocore.session.Session() + credentials = session.get_credentials().get_frozen_credentials() + SigV4Auth(credentials, "execute-api", self.my_region).add_auth(aws_request) + + response = requests.get(url, headers=dict(aws_request.headers)) + amazon_headers = RequestUtils(response).get_amazon_headers() + if self.internal: + REQUEST_LOGGER.info( + "SigV4 request made to " + url, + extra={"test": self.testcase, "status": response.status_code, "headers": amazon_headers}, + ) + return response + def do_options_request_with_logging(self, url, headers=None): """ Perform a options request to an APIGW endpoint and log relevant info @@ -669,3 +730,25 @@ def do_post_request_with_logging(self, url: str, body_obj, requestHeaders=None): extra={"test": self.testcase, "status": response.status_code, "headers": amazon_headers}, ) return response + + def do_post_request_with_sigv4(self, url: str, body_obj, headers=None): + """Perform a SigV4-signed POST request to an APIGW endpoint with IAM auth.""" + parsed = urlparse(url) + body = json.dumps(body_obj) + request_headers = {"host": parsed.hostname, "content-type": "application/json"} + if headers: + request_headers.update(headers) + + aws_request = AWSRequest(method="POST", url=url, headers=request_headers, data=body) + session = botocore.session.Session() + credentials = session.get_credentials().get_frozen_credentials() + SigV4Auth(credentials, "execute-api", self.my_region).add_auth(aws_request) + + response = requests.post(url, data=body, headers=dict(aws_request.headers)) + amazon_headers = RequestUtils(response).get_amazon_headers() + if self.internal: + REQUEST_LOGGER.info( + "SigV4 POST request made to " + url, + extra={"test": self.testcase, "status": response.status_code, "headers": amazon_headers}, + ) + return response diff --git a/integration/resources/templates/combination/api_with_binary_media_types.yaml b/integration/resources/templates/combination/api_with_binary_media_types.yaml index 9d9dc92790..793c0b13b9 100644 --- a/integration/resources/templates/combination/api_with_binary_media_types.yaml +++ b/integration/resources/templates/combination/api_with_binary_media_types.yaml @@ -17,6 +17,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Prod DefinitionUri: ${definitionuri} BinaryMediaTypes: diff --git a/integration/resources/templates/combination/api_with_binary_media_types_with_definition_body.yaml b/integration/resources/templates/combination/api_with_binary_media_types_with_definition_body.yaml index 2f2bc155a4..fb88169c58 100644 --- a/integration/resources/templates/combination/api_with_binary_media_types_with_definition_body.yaml +++ b/integration/resources/templates/combination/api_with_binary_media_types_with_definition_body.yaml @@ -22,6 +22,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Prod DefinitionBody: # Simple HTTP Proxy API diff --git a/integration/resources/templates/combination/api_with_binary_media_types_with_definition_body_openapi.yaml b/integration/resources/templates/combination/api_with_binary_media_types_with_definition_body_openapi.yaml index 0b2348d8bc..2cd2d0d38d 100644 --- a/integration/resources/templates/combination/api_with_binary_media_types_with_definition_body_openapi.yaml +++ b/integration/resources/templates/combination/api_with_binary_media_types_with_definition_body_openapi.yaml @@ -26,6 +26,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Prod DefinitionBody: # Simple HTTP Proxy API diff --git a/integration/resources/templates/combination/api_with_custom_domains_edge.yaml b/integration/resources/templates/combination/api_with_custom_domains_edge.yaml index 31dfee1154..93db88c756 100644 --- a/integration/resources/templates/combination/api_with_custom_domains_edge.yaml +++ b/integration/resources/templates/combination/api_with_custom_domains_edge.yaml @@ -32,6 +32,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM OpenApiVersion: 3.0.1 StageName: Prod Domain: diff --git a/integration/resources/templates/combination/api_with_disable_execute_api_endpoint.yaml b/integration/resources/templates/combination/api_with_disable_execute_api_endpoint.yaml index 506934eb14..eb2a070202 100644 --- a/integration/resources/templates/combination/api_with_disable_execute_api_endpoint.yaml +++ b/integration/resources/templates/combination/api_with_disable_execute_api_endpoint.yaml @@ -12,6 +12,8 @@ Resources: RestApiGateway: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Prod DisableExecuteApiEndpoint: Ref: DisableExecuteApiEndpointValue diff --git a/integration/resources/templates/combination/api_with_disable_execute_api_endpoint_openapi_3.yaml b/integration/resources/templates/combination/api_with_disable_execute_api_endpoint_openapi_3.yaml index 801bea3607..a44b574ccf 100644 --- a/integration/resources/templates/combination/api_with_disable_execute_api_endpoint_openapi_3.yaml +++ b/integration/resources/templates/combination/api_with_disable_execute_api_endpoint_openapi_3.yaml @@ -12,6 +12,8 @@ Resources: RestApiGateway: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Prod OpenApiVersion: 3.0 DisableExecuteApiEndpoint: diff --git a/integration/resources/templates/combination/api_with_endpoint_configuration.yaml b/integration/resources/templates/combination/api_with_endpoint_configuration.yaml index 5741b31c33..765a8f27eb 100644 --- a/integration/resources/templates/combination/api_with_endpoint_configuration.yaml +++ b/integration/resources/templates/combination/api_with_endpoint_configuration.yaml @@ -13,6 +13,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Prod EndpointConfiguration: {Ref: Config} DefinitionUri: ${definitionuri} diff --git a/integration/resources/templates/combination/api_with_endpoint_configuration_dict.yaml b/integration/resources/templates/combination/api_with_endpoint_configuration_dict.yaml index 9628eb0e13..bda5cf8881 100644 --- a/integration/resources/templates/combination/api_with_endpoint_configuration_dict.yaml +++ b/integration/resources/templates/combination/api_with_endpoint_configuration_dict.yaml @@ -10,6 +10,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Prod EndpointConfiguration: Type: REGIONAL diff --git a/integration/resources/templates/combination/api_with_fail_on_warnings.yaml b/integration/resources/templates/combination/api_with_fail_on_warnings.yaml index 40c2bc9ae0..73b3f69bf5 100644 --- a/integration/resources/templates/combination/api_with_fail_on_warnings.yaml +++ b/integration/resources/templates/combination/api_with_fail_on_warnings.yaml @@ -11,6 +11,8 @@ Resources: RestApiGateway: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Prod FailOnWarnings: Ref: FailOnWarningsValue diff --git a/integration/resources/templates/combination/api_with_method_settings.yaml b/integration/resources/templates/combination/api_with_method_settings.yaml index 95d72c2a6b..12d66499db 100644 --- a/integration/resources/templates/combination/api_with_method_settings.yaml +++ b/integration/resources/templates/combination/api_with_method_settings.yaml @@ -6,6 +6,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Prod DefinitionUri: ${definitionuri} MethodSettings: [{LoggingLevel: INFO, MetricsEnabled: true, DataTraceEnabled: true, diff --git a/integration/resources/templates/combination/api_with_request_models.yaml b/integration/resources/templates/combination/api_with_request_models.yaml index 56fe7bfce9..20856cfb1a 100644 --- a/integration/resources/templates/combination/api_with_request_models.yaml +++ b/integration/resources/templates/combination/api_with_request_models.yaml @@ -6,6 +6,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Prod Models: User: diff --git a/integration/resources/templates/combination/api_with_request_models_openapi.yaml b/integration/resources/templates/combination/api_with_request_models_openapi.yaml index 77486926d5..a773cf2316 100644 --- a/integration/resources/templates/combination/api_with_request_models_openapi.yaml +++ b/integration/resources/templates/combination/api_with_request_models_openapi.yaml @@ -6,6 +6,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM OpenApiVersion: 3.0.1 StageName: Prod Models: diff --git a/integration/resources/templates/combination/api_with_resource_refs.yaml b/integration/resources/templates/combination/api_with_resource_refs.yaml index 1dc292af5f..490f815c1d 100644 --- a/integration/resources/templates/combination/api_with_resource_refs.yaml +++ b/integration/resources/templates/combination/api_with_resource_refs.yaml @@ -8,6 +8,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Prod DefinitionUri: ${definitionuri} diff --git a/integration/resources/templates/combination/function_with_alias_and_event_sources.yaml b/integration/resources/templates/combination/function_with_alias_and_event_sources.yaml index ea68464396..8e396430d2 100644 --- a/integration/resources/templates/combination/function_with_alias_and_event_sources.yaml +++ b/integration/resources/templates/combination/function_with_alias_and_event_sources.yaml @@ -86,6 +86,8 @@ Resources: ExistingRestApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Dev DefinitionUri: ${definitionuri} diff --git a/integration/resources/templates/combination/function_with_api.yaml b/integration/resources/templates/combination/function_with_api.yaml index 2166721b65..548667cfe4 100644 --- a/integration/resources/templates/combination/function_with_api.yaml +++ b/integration/resources/templates/combination/function_with_api.yaml @@ -8,6 +8,8 @@ Resources: ExistingRestApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Dev DefinitionUri: ${definitionuri} diff --git a/integration/resources/templates/combination/function_with_http_api.yaml b/integration/resources/templates/combination/function_with_http_api.yaml index 0911ddcc92..07541cbeac 100644 --- a/integration/resources/templates/combination/function_with_http_api.yaml +++ b/integration/resources/templates/combination/function_with_http_api.yaml @@ -20,6 +20,9 @@ Resources: MyApi: Type: AWS::Serverless::HttpApi Properties: + Auth: + EnableIamAuthorizer: true + DefaultAuthorizer: AWS_IAM DefinitionBody: info: version: '1.0' diff --git a/integration/resources/templates/combination/function_with_http_api_default_path.yaml b/integration/resources/templates/combination/function_with_http_api_default_path.yaml index bb3234377a..d7d27f79ba 100644 --- a/integration/resources/templates/combination/function_with_http_api_default_path.yaml +++ b/integration/resources/templates/combination/function_with_http_api_default_path.yaml @@ -20,6 +20,9 @@ Resources: MyApi: Type: AWS::Serverless::HttpApi Properties: + Auth: + EnableIamAuthorizer: true + DefaultAuthorizer: AWS_IAM DefinitionBody: info: version: '1.0' diff --git a/integration/resources/templates/combination/function_with_implicit_http_api.yaml b/integration/resources/templates/combination/function_with_implicit_http_api.yaml index 4412178863..8ea3d466ff 100644 --- a/integration/resources/templates/combination/function_with_implicit_http_api.yaml +++ b/integration/resources/templates/combination/function_with_implicit_http_api.yaml @@ -1,3 +1,9 @@ +Globals: + HttpApi: + Auth: + EnableIamAuthorizer: true + DefaultAuthorizer: AWS_IAM + Resources: MyLambdaFunction: diff --git a/integration/resources/templates/combination/http_api_with_custom_domains_regional.yaml b/integration/resources/templates/combination/http_api_with_custom_domains_regional.yaml index 72b033eff8..d42ebfe0d9 100644 --- a/integration/resources/templates/combination/http_api_with_custom_domains_regional.yaml +++ b/integration/resources/templates/combination/http_api_with_custom_domains_regional.yaml @@ -57,6 +57,9 @@ Resources: MyApi: Type: AWS::Serverless::HttpApi Properties: + Auth: + EnableIamAuthorizer: true + DefaultAuthorizer: AWS_IAM StageName: Prod Metadata: SamTransformTest: true diff --git a/integration/resources/templates/combination/http_api_with_custom_domains_regional_ownership_verification.yaml b/integration/resources/templates/combination/http_api_with_custom_domains_regional_ownership_verification.yaml index 24ba30da30..a7f4a99126 100644 --- a/integration/resources/templates/combination/http_api_with_custom_domains_regional_ownership_verification.yaml +++ b/integration/resources/templates/combination/http_api_with_custom_domains_regional_ownership_verification.yaml @@ -61,6 +61,9 @@ Resources: MyApi: Type: AWS::Serverless::HttpApi Properties: + Auth: + EnableIamAuthorizer: true + DefaultAuthorizer: AWS_IAM StageName: Prod Metadata: SamTransformTest: true diff --git a/integration/resources/templates/combination/http_api_with_disable_execute_api_endpoint_false.yaml b/integration/resources/templates/combination/http_api_with_disable_execute_api_endpoint_false.yaml index 451321a5ed..6e97dd5d00 100644 --- a/integration/resources/templates/combination/http_api_with_disable_execute_api_endpoint_false.yaml +++ b/integration/resources/templates/combination/http_api_with_disable_execute_api_endpoint_false.yaml @@ -30,6 +30,9 @@ Resources: MyApi: Type: AWS::Serverless::HttpApi Properties: + Auth: + EnableIamAuthorizer: true + DefaultAuthorizer: AWS_IAM DisableExecuteApiEndpoint: false StageName: Prod Outputs: diff --git a/integration/resources/templates/combination/http_api_with_disable_execute_api_endpoint_true.yaml b/integration/resources/templates/combination/http_api_with_disable_execute_api_endpoint_true.yaml index d461b21e78..ea288c88f1 100644 --- a/integration/resources/templates/combination/http_api_with_disable_execute_api_endpoint_true.yaml +++ b/integration/resources/templates/combination/http_api_with_disable_execute_api_endpoint_true.yaml @@ -30,6 +30,9 @@ Resources: MyApi: Type: AWS::Serverless::HttpApi Properties: + Auth: + EnableIamAuthorizer: true + DefaultAuthorizer: AWS_IAM DisableExecuteApiEndpoint: true StageName: Prod diff --git a/integration/resources/templates/combination/http_api_with_fail_on_warnings_and_default_stage_name.yaml b/integration/resources/templates/combination/http_api_with_fail_on_warnings_and_default_stage_name.yaml index d54723d42f..075a4534e6 100644 --- a/integration/resources/templates/combination/http_api_with_fail_on_warnings_and_default_stage_name.yaml +++ b/integration/resources/templates/combination/http_api_with_fail_on_warnings_and_default_stage_name.yaml @@ -7,6 +7,9 @@ Resources: AppApi: Type: AWS::Serverless::HttpApi Properties: + Auth: + EnableIamAuthorizer: true + DefaultAuthorizer: AWS_IAM FailOnWarnings: !Ref FailOnWarningsValue StageName: $default AppFunction: diff --git a/integration/resources/templates/combination/intrinsics_code_definition_uri.yaml b/integration/resources/templates/combination/intrinsics_code_definition_uri.yaml index 2ce7242263..fc7e8f61d5 100644 --- a/integration/resources/templates/combination/intrinsics_code_definition_uri.yaml +++ b/integration/resources/templates/combination/intrinsics_code_definition_uri.yaml @@ -30,6 +30,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: FancyName DefinitionUri: Bucket: diff --git a/integration/resources/templates/combination/intrinsics_serverless_api.yaml b/integration/resources/templates/combination/intrinsics_serverless_api.yaml index d7aa06c785..4d0caa4c9a 100644 --- a/integration/resources/templates/combination/intrinsics_serverless_api.yaml +++ b/integration/resources/templates/combination/intrinsics_serverless_api.yaml @@ -90,6 +90,8 @@ Resources: Type: AWS::Serverless::Api Condition: TrueCondition Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Ref: MyStageName DefinitionUri: @@ -107,6 +109,8 @@ Resources: Type: AWS::Serverless::Api Condition: FalseCondition Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Ref: MyStageName DefinitionUri: diff --git a/integration/resources/templates/combination/state_machine_with_api.yaml b/integration/resources/templates/combination/state_machine_with_api.yaml index 1d8beca26c..eadab8c62b 100644 --- a/integration/resources/templates/combination/state_machine_with_api.yaml +++ b/integration/resources/templates/combination/state_machine_with_api.yaml @@ -8,6 +8,8 @@ Resources: ExistingRestApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Dev MyStateMachine: diff --git a/integration/resources/templates/combination/websocket_api_basic.yaml b/integration/resources/templates/combination/websocket_api_basic.yaml index a11de573dd..97d15f8fbe 100644 --- a/integration/resources/templates/combination/websocket_api_basic.yaml +++ b/integration/resources/templates/combination/websocket_api_basic.yaml @@ -8,6 +8,8 @@ Resources: MyApi: Type: AWS::Serverless::WebSocketApi Properties: + Auth: + AuthType: AWS_IAM Name: MyApi RouteSelectionExpression: $request.body.action Routes: diff --git a/integration/resources/templates/combination/websocket_api_basic_config.yaml b/integration/resources/templates/combination/websocket_api_basic_config.yaml index 99070c6ae7..24ba205c25 100644 --- a/integration/resources/templates/combination/websocket_api_basic_config.yaml +++ b/integration/resources/templates/combination/websocket_api_basic_config.yaml @@ -8,6 +8,8 @@ Resources: MyApi: Type: AWS::Serverless::WebSocketApi Properties: + Auth: + AuthType: AWS_IAM ApiKeySelectionExpression: $request.header.x-api-key Description: Toy API DisableExecuteApiEndpoint: false diff --git a/integration/resources/templates/combination/websocket_api_custom_domains_regional.yaml b/integration/resources/templates/combination/websocket_api_custom_domains_regional.yaml index 56d8e91657..5b0691ef39 100644 --- a/integration/resources/templates/combination/websocket_api_custom_domains_regional.yaml +++ b/integration/resources/templates/combination/websocket_api_custom_domains_regional.yaml @@ -39,6 +39,8 @@ Resources: MyApi: Type: AWS::Serverless::WebSocketApi Properties: + Auth: + AuthType: AWS_IAM Name: MyApi RouteSelectionExpression: $request.body.action Routes: diff --git a/integration/resources/templates/combination/websocket_api_multiple_api.yaml b/integration/resources/templates/combination/websocket_api_multiple_api.yaml index 456aaf736f..8b01c71b2d 100644 --- a/integration/resources/templates/combination/websocket_api_multiple_api.yaml +++ b/integration/resources/templates/combination/websocket_api_multiple_api.yaml @@ -8,6 +8,8 @@ Resources: Api1: Type: AWS::Serverless::WebSocketApi Properties: + Auth: + AuthType: AWS_IAM RouteSelectionExpression: $request.body.action Routes: $default: @@ -15,6 +17,8 @@ Resources: Api2: Type: AWS::Serverless::WebSocketApi Properties: + Auth: + AuthType: AWS_IAM Name: Api2 RouteSelectionExpression: $request.body.action Routes: diff --git a/integration/resources/templates/combination/websocket_api_multiple_routes.yaml b/integration/resources/templates/combination/websocket_api_multiple_routes.yaml index ab9237a811..ba324159bc 100644 --- a/integration/resources/templates/combination/websocket_api_multiple_routes.yaml +++ b/integration/resources/templates/combination/websocket_api_multiple_routes.yaml @@ -26,6 +26,8 @@ Resources: MyApi: Type: AWS::Serverless::WebSocketApi Properties: + Auth: + AuthType: AWS_IAM RouteSelectionExpression: $request.body.action Routes: $connect: diff --git a/integration/resources/templates/combination/websocket_api_route_config.yaml b/integration/resources/templates/combination/websocket_api_route_config.yaml index 6dcfe7b9da..1f4f416025 100644 --- a/integration/resources/templates/combination/websocket_api_route_config.yaml +++ b/integration/resources/templates/combination/websocket_api_route_config.yaml @@ -8,6 +8,8 @@ Resources: MyApi: Type: AWS::Serverless::WebSocketApi Properties: + Auth: + AuthType: AWS_IAM Routes: $connect: ApiKeyRequired: false diff --git a/integration/resources/templates/combination/websocket_api_route_settings.yaml b/integration/resources/templates/combination/websocket_api_route_settings.yaml index 67e00782e7..115be141b4 100644 --- a/integration/resources/templates/combination/websocket_api_route_settings.yaml +++ b/integration/resources/templates/combination/websocket_api_route_settings.yaml @@ -12,6 +12,8 @@ Resources: MyApi: Type: AWS::Serverless::WebSocketApi Properties: + Auth: + AuthType: AWS_IAM RouteSelectionExpression: $request.body.action RouteSettings: sendMessage: diff --git a/integration/resources/templates/combination/websocket_api_stage_config.yaml b/integration/resources/templates/combination/websocket_api_stage_config.yaml index c43e97f50a..7519fa84c5 100644 --- a/integration/resources/templates/combination/websocket_api_stage_config.yaml +++ b/integration/resources/templates/combination/websocket_api_stage_config.yaml @@ -8,6 +8,8 @@ Resources: MyApi: Type: AWS::Serverless::WebSocketApi Properties: + Auth: + AuthType: AWS_IAM Name: MyApi PropagateTags: true Routes: diff --git a/integration/resources/templates/combination/websocket_api_with_disable_execute_api_endpoint.yaml b/integration/resources/templates/combination/websocket_api_with_disable_execute_api_endpoint.yaml index 2421e8f479..c86623edc4 100644 --- a/integration/resources/templates/combination/websocket_api_with_disable_execute_api_endpoint.yaml +++ b/integration/resources/templates/combination/websocket_api_with_disable_execute_api_endpoint.yaml @@ -13,6 +13,8 @@ Resources: MyApi: Type: AWS::Serverless::WebSocketApi Properties: + Auth: + AuthType: AWS_IAM DisableExecuteApiEndpoint: !Ref DisableExecuteApiEndpointValue Name: MyApi RouteSelectionExpression: $request.body.action diff --git a/integration/resources/templates/combination/websocket_api_with_disable_schema_validation.yaml b/integration/resources/templates/combination/websocket_api_with_disable_schema_validation.yaml index 118ea5434b..6173b83900 100644 --- a/integration/resources/templates/combination/websocket_api_with_disable_schema_validation.yaml +++ b/integration/resources/templates/combination/websocket_api_with_disable_schema_validation.yaml @@ -14,6 +14,8 @@ Resources: MyApi: Type: AWS::Serverless::WebSocketApi Properties: + Auth: + AuthType: AWS_IAM DisableSchemaValidation: true Name: MyApi RouteSelectionExpression: $request.body.action diff --git a/integration/resources/templates/combination/websocket_api_with_ip_address_type.yaml b/integration/resources/templates/combination/websocket_api_with_ip_address_type.yaml index be226be46b..f5f518876d 100644 --- a/integration/resources/templates/combination/websocket_api_with_ip_address_type.yaml +++ b/integration/resources/templates/combination/websocket_api_with_ip_address_type.yaml @@ -13,6 +13,8 @@ Resources: MyApi: Type: AWS::Serverless::WebSocketApi Properties: + Auth: + AuthType: AWS_IAM IpAddressType: !Ref IpAddressType Name: MyApi RouteSelectionExpression: $request.body.action 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 index b12ed721ff..3fc1d902d7 100644 --- 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 @@ -10,6 +10,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Prod DefinitionUri: ${definitionuri} EndpointConfiguration: 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 index 4799cc90f5..a8c05704f9 100644 --- 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 @@ -10,6 +10,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Prod DefinitionUri: ${definitionuri} EndpointConfiguration: diff --git a/integration/resources/templates/single/api_with_domain_ipaddresstype.yaml b/integration/resources/templates/single/api_with_domain_ipaddresstype.yaml index 8c2c5377ba..5a359c7234 100644 --- a/integration/resources/templates/single/api_with_domain_ipaddresstype.yaml +++ b/integration/resources/templates/single/api_with_domain_ipaddresstype.yaml @@ -11,6 +11,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Prod DefinitionUri: ${definitionuri} Domain: 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 40b1cb3279..64fa3b2550 100644 --- a/integration/resources/templates/single/api_with_endpoint_access_mode.yaml +++ b/integration/resources/templates/single/api_with_endpoint_access_mode.yaml @@ -10,6 +10,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Prod DefinitionUri: ${definitionuri} SecurityPolicy: !Ref SecurityPolicyValue diff --git a/integration/resources/templates/single/api_with_ipaddresstype.yaml b/integration/resources/templates/single/api_with_ipaddresstype.yaml index 26f17d0ea0..d7042f94cc 100644 --- a/integration/resources/templates/single/api_with_ipaddresstype.yaml +++ b/integration/resources/templates/single/api_with_ipaddresstype.yaml @@ -7,6 +7,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Prod DefinitionUri: ${definitionuri} EndpointConfiguration: diff --git a/integration/resources/templates/single/basic_api.yaml b/integration/resources/templates/single/basic_api.yaml index 1d726f625a..dc0ca32b1a 100644 --- a/integration/resources/templates/single/basic_api.yaml +++ b/integration/resources/templates/single/basic_api.yaml @@ -6,6 +6,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: MyNewStageName DefinitionUri: ${definitionuri} Metadata: diff --git a/integration/resources/templates/single/basic_api_inline_openapi.yaml b/integration/resources/templates/single/basic_api_inline_openapi.yaml index 3c0a592dd3..914d3e3591 100644 --- a/integration/resources/templates/single/basic_api_inline_openapi.yaml +++ b/integration/resources/templates/single/basic_api_inline_openapi.yaml @@ -6,6 +6,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: MyNewStageName DefinitionBody: # Simple HTTP Proxy API diff --git a/integration/resources/templates/single/basic_api_inline_swagger.yaml b/integration/resources/templates/single/basic_api_inline_swagger.yaml index 68111ce2a6..466df7992a 100644 --- a/integration/resources/templates/single/basic_api_inline_swagger.yaml +++ b/integration/resources/templates/single/basic_api_inline_swagger.yaml @@ -6,6 +6,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: MyNewStageName DefinitionBody: # Simple HTTP Proxy API diff --git a/integration/resources/templates/single/basic_api_with_mode.yaml b/integration/resources/templates/single/basic_api_with_mode.yaml index 82a9624548..7b2c2ed6c4 100644 --- a/integration/resources/templates/single/basic_api_with_mode.yaml +++ b/integration/resources/templates/single/basic_api_with_mode.yaml @@ -6,6 +6,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: MyNewStageName Mode: overwrite diff --git a/integration/resources/templates/single/basic_api_with_mode_update.yaml b/integration/resources/templates/single/basic_api_with_mode_update.yaml index 589fd4d1f6..ea2acd12a0 100644 --- a/integration/resources/templates/single/basic_api_with_mode_update.yaml +++ b/integration/resources/templates/single/basic_api_with_mode_update.yaml @@ -6,6 +6,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: MyNewStageName Mode: overwrite diff --git a/integration/resources/templates/single/basic_api_with_tags.yaml b/integration/resources/templates/single/basic_api_with_tags.yaml index 4af4987f70..fda952c2ef 100644 --- a/integration/resources/templates/single/basic_api_with_tags.yaml +++ b/integration/resources/templates/single/basic_api_with_tags.yaml @@ -6,6 +6,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: my-new-stage-name DefinitionUri: ${definitionuri} Tags: diff --git a/integration/resources/templates/single/basic_http_api.yaml b/integration/resources/templates/single/basic_http_api.yaml index e5b5f0ff16..c6e85f654c 100644 --- a/integration/resources/templates/single/basic_http_api.yaml +++ b/integration/resources/templates/single/basic_http_api.yaml @@ -2,6 +2,9 @@ Resources: MyApi: Type: AWS::Serverless::HttpApi Properties: + Auth: + EnableIamAuthorizer: true + DefaultAuthorizer: AWS_IAM DefinitionBody: info: version: '1.0' diff --git a/integration/resources/templates/single/function_alias_with_http_api_events.yaml b/integration/resources/templates/single/function_alias_with_http_api_events.yaml index 6c5fb449d1..6e817207d7 100644 --- a/integration/resources/templates/single/function_alias_with_http_api_events.yaml +++ b/integration/resources/templates/single/function_alias_with_http_api_events.yaml @@ -1,6 +1,10 @@ Resources: MyHttpApi: Type: AWS::Serverless::HttpApi + Properties: + Auth: + EnableIamAuthorizer: true + DefaultAuthorizer: AWS_IAM MyLambdaFunction: Type: AWS::Serverless::Function Properties: diff --git a/integration/resources/templates/single/function_with_http_api_events.yaml b/integration/resources/templates/single/function_with_http_api_events.yaml index fa44fd3336..5fe2668a67 100644 --- a/integration/resources/templates/single/function_with_http_api_events.yaml +++ b/integration/resources/templates/single/function_with_http_api_events.yaml @@ -1,6 +1,10 @@ Resources: MyHttpApi: Type: AWS::Serverless::HttpApi + Properties: + Auth: + EnableIamAuthorizer: true + DefaultAuthorizer: AWS_IAM MyLambdaFunction: Type: AWS::Serverless::Function Properties: diff --git a/integration/resources/templates/single/state_machine_with_api.yaml b/integration/resources/templates/single/state_machine_with_api.yaml index c72a660988..c1df85e392 100644 --- a/integration/resources/templates/single/state_machine_with_api.yaml +++ b/integration/resources/templates/single/state_machine_with_api.yaml @@ -3,6 +3,8 @@ Resources: MyApi: Type: AWS::Serverless::Api Properties: + Auth: + DefaultAuthorizer: AWS_IAM StageName: Prod EndpointConfiguration: Type: REGIONAL diff --git a/integration/single/test_basic_api.py b/integration/single/test_basic_api.py index c749f9ffd5..17093afc3d 100644 --- a/integration/single/test_basic_api.py +++ b/integration/single/test_basic_api.py @@ -47,21 +47,21 @@ def test_basic_api_with_mode(self): stack_output = self.get_stack_outputs() api_endpoint = stack_output.get("ApiEndpoint") - self.verify_get_request_response(f"{api_endpoint}/get", 200) + self.verify_get_request_response_sigv4(f"{api_endpoint}/get", 200) # Removes get from the API self.update_and_verify_stack(file_path="single/basic_api_with_mode_update") - # API Gateway by default returns 403 if a path do not exist - self.verify_get_request_response.retry_with( + # With IAM auth, API Gateway returns 404 for non-existent routes (instead of 403 without auth) + self.verify_get_request_response_sigv4.retry_with( stop=stop_after_attempt(20), wait=wait_exponential(multiplier=1, min=4, max=10) + wait_random(0, 1), retry=retry_if_exception_type(StatusCodeError), after=after_log(LOG, logging.WARNING), reraise=True, - )(self, f"{api_endpoint}/get", 403) + )(self, f"{api_endpoint}/get", 404) - LOG.log(msg=f"retry times {self.verify_get_request_response.retry.statistics}", level=logging.WARNING) + LOG.log(msg=f"retry times {self.verify_get_request_response_sigv4.retry.statistics}", level=logging.WARNING) def test_basic_api_inline_openapi(self): """ @@ -134,7 +134,7 @@ def test_state_machine_with_api_single_quotes_input(self): # This will be the wait time before triggering the APIGW request time.sleep(10) - response = self.verify_post_request(api_endpoint, input_json, 200) + response = self.verify_post_request_sigv4(api_endpoint, input_json, 200) LOG.log(msg=f"retry times {self.verify_get_request_response.retry.statistics}", level=logging.WARNING)