diff --git a/DEVELOPMENT_GUIDE.md b/DEVELOPMENT_GUIDE.md index 76486e5384..d260c6c70a 100644 --- a/DEVELOPMENT_GUIDE.md +++ b/DEVELOPMENT_GUIDE.md @@ -114,7 +114,9 @@ Running Tests ### Unit testing with one Python version -If you're trying to do a quick run, it's ok to use the current python version. Run `make pr`. +If you're trying to do a quick run, it's ok to use the current python version. +Run `make test` or `make test-fast`. Once all tests pass make sure to run +`make pr` before sending out your PR. ### Unit testing with multiple Python versions diff --git a/Makefile b/Makefile index 21f96495f0..c3fed92aa2 100755 --- a/Makefile +++ b/Makefile @@ -1,13 +1,16 @@ target: $(info ${HELP_MESSAGE}) @exit 0 - + init: pip install -e '.[dev]' test: pytest --cov samtranslator --cov-report term-missing --cov-fail-under 95 -n auto tests/* +test-fast: + pytest -x --cov samtranslator --cov-report term-missing --cov-fail-under 95 -n auto tests/* + test-cov-report: pytest --cov samtranslator --cov-report term-missing --cov-report html --cov-fail-under 95 tests/* diff --git a/integration/resources/expected/single/function_with_http_api_events_and_auth.json b/integration/resources/expected/single/function_with_http_api_events_and_auth.json new file mode 100644 index 0000000000..b505f2126e --- /dev/null +++ b/integration/resources/expected/single/function_with_http_api_events_and_auth.json @@ -0,0 +1,62 @@ +[ + { + "LogicalResourceId": "MyDefaultIamAuthHttpApi", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "MyDefaultIamAuthHttpApiApiGatewayDefaultStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + }, + { + "LogicalResourceId": "MyIamAuthEnabledHttpApi", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "MyIamAuthEnabledHttpApiApiGatewayDefaultStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + }, + { + "LogicalResourceId": "MyLambdaFunction", + "ResourceType": "AWS::Lambda::Function" + }, + { + "LogicalResourceId": "MyLambdaFunctionImplicitApiDefaultAuthEventPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyLambdaFunctionImplicitApiIamAuthEventPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyLambdaFunctionMyDefaultIamAuthHttpApiDefaultAuthEventPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyLambdaFunctionMyDefaultIamAuthHttpApiIamAuthEventPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyLambdaFunctionMyDefaultIamAuthHttpApiNoAuthEventPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyLambdaFunctionMyIamAuthEnabledHttpApiDefaultAuthEventPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyLambdaFunctionMyIamAuthEnabledHttpApiIamAuthEventPermission", + "ResourceType": "AWS::Lambda::Permission" + }, + { + "LogicalResourceId": "MyLambdaFunctionRole", + "ResourceType": "AWS::IAM::Role" + }, + { + "LogicalResourceId": "ServerlessHttpApi", + "ResourceType": "AWS::ApiGatewayV2::Api" + }, + { + "LogicalResourceId": "ServerlessHttpApiApiGatewayDefaultStage", + "ResourceType": "AWS::ApiGatewayV2::Stage" + } +] diff --git a/integration/resources/templates/single/function_with_http_api_events_and_auth.yaml b/integration/resources/templates/single/function_with_http_api_events_and_auth.yaml new file mode 100644 index 0000000000..bbff00e73f --- /dev/null +++ b/integration/resources/templates/single/function_with_http_api_events_and_auth.yaml @@ -0,0 +1,96 @@ +Globals: + HttpApi: + Auth: + EnableIamAuthorizer: true +Resources: + ####### + # Serverless function that use the implicit AWS::Serverless::HttpApi called "ServerlessHttpApi". + # IAM Authorizer of the implicit AWS::Serverless::HttpApi is enabled using the global above. + ####### + MyLambdaFunction: + Type: AWS::Serverless::Function + Properties: + Handler: index.handler + Runtime: nodejs12.x + CodeUri: ${codeuri} + Events: + # The following events use the implicit AWS::Serverless::HttpApi called "ServerlessHttpApi". + # The Iam Authorizer of the implicit AWS::Serverless::HttpApi is enabled using the global above. + # Should not have any auth enabled because there is no one set as the default. + ImplicitApiDefaultAuthEvent: + Type: HttpApi + Properties: + Path: /default-auth + Method: GET + # Should have Iam auth as it is set here. + ImplicitApiIamAuthEvent: + Type: HttpApi + Properties: + Auth: + Authorizer: AWS_IAM + Path: /iam-auth + Method: GET + + # The following events use the defined AWS::Serverless::HttpApi further down. + # Should not have any auth enabled. + MyDefaultIamAuthHttpApiNoAuthEvent: + Type: HttpApi + Properties: + ApiId: + Ref: MyDefaultIamAuthHttpApi + Auth: + Authorizer: NONE + Path: /no-auth + Method: GET + # Should have Iam auth as it is set as the default for the Api. + MyDefaultIamAuthHttpApiDefaultAuthEvent: + Type: HttpApi + Properties: + ApiId: + Ref: MyDefaultIamAuthHttpApi + Path: /default-auth + Method: GET + # Should have Iam auth as it is set here. + MyDefaultIamAuthHttpApiIamAuthEvent: + Type: HttpApi + Properties: + ApiId: + Ref: MyDefaultIamAuthHttpApi + Auth: + Authorizer: AWS_IAM + Path: /iam-auth + Method: GET + # The following events use the defined AWS::Serverless::HttpApi further down. + # Should not have any auth enabled because there is no one set as the default. + MyIamAuthEnabledHttpApiDefaultAuthEvent: + Type: HttpApi + Properties: + ApiId: + Ref: MyIamAuthEnabledHttpApi + Path: /default-auth + Method: GET + # Should have Iam auth as it is set here. + MyIamAuthEnabledHttpApiIamAuthEvent: + Type: HttpApi + Properties: + ApiId: + Ref: MyIamAuthEnabledHttpApi + Auth: + Authorizer: AWS_IAM + Path: /iam-auth + Method: GET + + # HTTP API resource with the Iam authorizer enabled and set to the default. + MyDefaultIamAuthHttpApi: + Type: AWS::Serverless::HttpApi + Properties: + Auth: + EnableIamAuthorizer: true + DefaultAuthorizer: AWS_IAM + + # HTTP API resource with the Iam authorizer enabled and NOT set to the default. + MyIamAuthEnabledHttpApi: + Type: AWS::Serverless::HttpApi + Properties: + Auth: + EnableIamAuthorizer: true diff --git a/integration/single/test_function_with_http_api_and_auth.py b/integration/single/test_function_with_http_api_and_auth.py new file mode 100644 index 0000000000..c1e5546d26 --- /dev/null +++ b/integration/single/test_function_with_http_api_and_auth.py @@ -0,0 +1,29 @@ +import requests +from parameterized import parameterized +from integration.helpers.base_test import BaseTest + + +class TestFunctionWithHttpApiAndAuth(BaseTest): + """ + AWS::Lambda::Function tests with http api events and auth + """ + + def test_function_with_http_api_and_auth(self): + # If the request is not signed, which none of the below are, IAM will respond with a "Forbidden" message. + # We are not testing that IAM auth works here, we are simply testing if it was applied. + IAM_AUTH_OUTPUT = '{"message":"Forbidden"}' + + self.create_and_verify_stack("function_with_http_api_events_and_auth") + + implicitEndpoint = self.get_api_v2_endpoint("ServerlessHttpApi") + self.assertEqual(requests.get(implicitEndpoint + "/default-auth").text, self.FUNCTION_OUTPUT) + self.assertEqual(requests.get(implicitEndpoint + "/iam-auth").text, IAM_AUTH_OUTPUT) + + defaultIamEndpoint = self.get_api_v2_endpoint("MyDefaultIamAuthHttpApi") + self.assertEqual(requests.get(defaultIamEndpoint + "/no-auth").text, self.FUNCTION_OUTPUT) + self.assertEqual(requests.get(defaultIamEndpoint + "/default-auth").text, IAM_AUTH_OUTPUT) + self.assertEqual(requests.get(defaultIamEndpoint + "/iam-auth").text, IAM_AUTH_OUTPUT) + + iamEnabledEndpoint = self.get_api_v2_endpoint("MyIamAuthEnabledHttpApi") + self.assertEqual(requests.get(iamEnabledEndpoint + "/default-auth").text, self.FUNCTION_OUTPUT) + self.assertEqual(requests.get(iamEnabledEndpoint + "/iam-auth").text, IAM_AUTH_OUTPUT) diff --git a/samtranslator/model/api/http_api_generator.py b/samtranslator/model/api/http_api_generator.py index d033a75bd9..869dddec46 100644 --- a/samtranslator/model/api/http_api_generator.py +++ b/samtranslator/model/api/http_api_generator.py @@ -24,8 +24,8 @@ ) CorsProperties.__new__.__defaults__ = (None, None, None, None, None, False) -AuthProperties = namedtuple("_AuthProperties", ["Authorizers", "DefaultAuthorizer"]) -AuthProperties.__new__.__defaults__ = (None, None) +AuthProperties = namedtuple("_AuthProperties", ["Authorizers", "DefaultAuthorizer", "EnableIamAuthorizer"]) +AuthProperties.__new__.__defaults__ = (None, None, False) DefaultStageName = "$default" HttpApiTagName = "httpapi:createdBy" @@ -422,7 +422,7 @@ def _add_auth(self): ) open_api_editor = OpenApiEditor(self.definition_body) auth_properties = AuthProperties(**self.auth) - authorizers = self._get_authorizers(auth_properties.Authorizers, auth_properties.DefaultAuthorizer) + authorizers = self._get_authorizers(auth_properties.Authorizers, auth_properties.EnableIamAuthorizer) # authorizers is guaranteed to return a value or raise an exception open_api_editor.add_authorizers_security_definitions(authorizers) @@ -494,14 +494,21 @@ def _set_default_authorizer(self, open_api_editor, authorizers, default_authoriz path, default_authorizer, authorizers=authorizers, api_authorizers=api_authorizers ) - def _get_authorizers(self, authorizers_config, default_authorizer=None): + def _get_authorizers(self, authorizers_config, enable_iam_authorizer=False): """ Returns all authorizers for an API as an ApiGatewayV2Authorizer object :param authorizers_config: authorizer configuration from the API Auth section - :param default_authorizer: name of the default authorizer + :param enable_iam_authorizer: if True add an "AWS_IAM" authorizer """ authorizers = {} + if enable_iam_authorizer is True: + authorizers["AWS_IAM"] = ApiGatewayV2Authorizer(is_aws_iam_authorizer=True) + + # If all the customer wants to do is enable the IAM authorizer the authorizers_config will be None. + if not authorizers_config: + return authorizers + if not isinstance(authorizers_config, dict): raise InvalidResourceException(self.logical_id, "Authorizers must be a dictionary.") diff --git a/samtranslator/model/apigatewayv2.py b/samtranslator/model/apigatewayv2.py index c7c1ea9beb..0dec3a3d5e 100644 --- a/samtranslator/model/apigatewayv2.py +++ b/samtranslator/model/apigatewayv2.py @@ -73,6 +73,7 @@ def __init__( identity=None, authorizer_payload_format_version=None, enable_simple_responses=None, + is_aws_iam_authorizer=False, ): """ Creates an authorizer for use in V2 Http Apis @@ -87,6 +88,7 @@ def __init__( self.identity = identity self.authorizer_payload_format_version = authorizer_payload_format_version self.enable_simple_responses = enable_simple_responses + self.is_aws_iam_authorizer = is_aws_iam_authorizer self._validate_input_parameters() @@ -100,6 +102,8 @@ def __init__( self._validate_lambda_authorizer() def _get_auth_type(self): + if self.is_aws_iam_authorizer: + return "AWS_IAM" if self.jwt_configuration: return "JWT" return "REQUEST" @@ -174,6 +178,14 @@ def generate_openapi(self): """ authorizer_type = self._get_auth_type() + if authorizer_type == "AWS_IAM": + openapi = { + "type": "apiKey", + "name": "Authorization", + "in": "header", + "x-amazon-apigateway-authtype": "awsSigv4", + } + if authorizer_type == "JWT": openapi = {"type": "oauth2"} openapi[APIGATEWAY_AUTHORIZER_KEY] = { diff --git a/samtranslator/model/eventsources/push.py b/samtranslator/model/eventsources/push.py index 13575d17bd..29edd59caa 100644 --- a/samtranslator/model/eventsources/push.py +++ b/samtranslator/model/eventsources/push.py @@ -705,7 +705,7 @@ def _add_swagger_integration(self, api, function, intrinsics_resolver): ) _check_valid_authorizer_types( - self.relative_id, self.Method, self.Path, method_authorizer, api_authorizers + self.relative_id, self.Method, self.Path, method_authorizer, api_authorizers, False ) if method_authorizer != "NONE" and not api_authorizers.get(method_authorizer): @@ -1209,40 +1209,51 @@ def _add_auth_to_openapi_integration(self, api, editor): # Default auth should already be applied, so apply any other auth here or scope override to default api_authorizers = api_auth and api_auth.get("Authorizers") - _check_valid_authorizer_types(self.relative_id, self.Method, self.Path, method_authorizer, api_authorizers) + # The IAM authorizer is built-in and not defined as a regular Authorizer. + iam_authorizer_enabled = api_auth and api_auth.get("EnableIamAuthorizer", False) is True - if method_authorizer != "NONE" and not api_authorizers: - raise InvalidEventException( - self.relative_id, - "Unable to set Authorizer [{authorizer}] on API method [{method}] for path [{path}] " - "because the related API does not define any Authorizers.".format( - authorizer=method_authorizer, method=self.Method, path=self.Path - ), - ) + _check_valid_authorizer_types( + self.relative_id, self.Method, self.Path, method_authorizer, api_authorizers, iam_authorizer_enabled + ) - if method_authorizer != "NONE" and not api_authorizers.get(method_authorizer): - raise InvalidEventException( - self.relative_id, - "Unable to set Authorizer [{authorizer}] on API method [{method}] for path [{path}] " - "because it wasn't defined in the API's Authorizers.".format( - authorizer=method_authorizer, method=self.Method, path=self.Path - ), - ) + if method_authorizer == "NONE": + if not api_auth.get("DefaultAuthorizer"): + raise InvalidEventException( + self.relative_id, + "Unable to set Authorizer on API method [{method}] for path [{path}] because 'NONE' " + "is only a valid value when a DefaultAuthorizer on the API is specified.".format( + method=self.Method, path=self.Path + ), + ) + # If the method authorizer is "AWS_IAM" but it's not enabled it's possible that's a custom authorizer, not the "official" one. + # In that case a check needs to be performed to make sure that such an authorizer is defined. + # The "official" AWS IAM authorizer is not defined as a normal authorizer so it won't exist in api_authorizer. + elif (method_authorizer == "AWS_IAM" and not iam_authorizer_enabled) or method_authorizer != "AWS_IAM": + if not api_authorizers: + raise InvalidEventException( + self.relative_id, + "Unable to set Authorizer [{authorizer}] on API method [{method}] for path [{path}] " + "because the related API does not define any Authorizers.".format( + authorizer=method_authorizer, method=self.Method, path=self.Path + ), + ) + + if not api_authorizers.get(method_authorizer): + raise InvalidEventException( + self.relative_id, + "Unable to set Authorizer [{authorizer}] on API method [{method}] for path [{path}] " + "because it wasn't defined in the API's Authorizers.".format( + authorizer=method_authorizer, method=self.Method, path=self.Path + ), + ) - if method_authorizer == "NONE" and not api_auth.get("DefaultAuthorizer"): - raise InvalidEventException( - self.relative_id, - "Unable to set Authorizer on API method [{method}] for path [{path}] because 'NONE' " - "is only a valid value when a DefaultAuthorizer on the API is specified.".format( - method=self.Method, path=self.Path - ), - ) if self.Auth.get("AuthorizationScopes") and not isinstance(self.Auth.get("AuthorizationScopes"), list): raise InvalidEventException( self.relative_id, "Unable to set Authorizer on API method [{method}] for path [{path}] because " "'AuthorizationScopes' must be a list of strings.".format(method=self.Method, path=self.Path), ) + editor.add_auth_to_method(api=api, path=self.Path, method_name=self.Method, auth=self.Auth) @@ -1262,12 +1273,19 @@ def _build_apigw_integration_uri(function, partition): return Py27Dict(fnSub(arn)) -def _check_valid_authorizer_types(relative_id, method, path, method_authorizer, api_authorizers): +def _check_valid_authorizer_types( + relative_id, method, path, method_authorizer, api_authorizers, iam_authorizer_enabled +): if method_authorizer == "NONE": # If the method authorizer is "NONE" then this check # isn't needed since DefaultAuthorizer needs to be used. return + if method_authorizer == "AWS_IAM" and iam_authorizer_enabled: + # The "official" AWS IAM authorizer is not defined as a normal authorizer so it won't exist in api_authorizers. + # So we can safety skip this check. + return + if not isinstance(method_authorizer, str) or not isinstance(api_authorizers, dict): raise InvalidEventException( relative_id, diff --git a/samtranslator/open_api/open_api.py b/samtranslator/open_api/open_api.py index d67f7aac9f..9bb6626d90 100644 --- a/samtranslator/open_api/open_api.py +++ b/samtranslator/open_api/open_api.py @@ -428,7 +428,8 @@ def _set_method_authorizer(self, path, method_name, authorizer_name, authorizers security_dict = dict() security_dict[authorizer_name] = [] - if authorizer_name != "NONE": + # Neither the NONE nor the AWS_IAM built-in authorizers support authorization scopes. + if authorizer_name not in ["NONE", "AWS_IAM"]: method_authorization_scopes = authorizers[authorizer_name].get("AuthorizationScopes") if authorization_scopes: method_authorization_scopes = authorization_scopes diff --git a/tests/model/api/test_http_api_generator.py b/tests/model/api/test_http_api_generator.py index 03030b1f7d..307841e640 100644 --- a/tests/model/api/test_http_api_generator.py +++ b/tests/model/api/test_http_api_generator.py @@ -76,6 +76,102 @@ def test_auth_intrinsic_default_auth(self): with pytest.raises(InvalidResourceException): HttpApiGenerator(**self.kwargs)._construct_http_api() + def test_auth_iam_enabled(self): + self.kwargs["auth"] = { + "EnableIamAuthorizer": True, + } + self.kwargs["definition_body"] = OpenApiEditor.gen_skeleton() + http_api = HttpApiGenerator(**self.kwargs)._construct_http_api() + self.assertEqual( + http_api.Body["components"]["securitySchemes"], + { + "AWS_IAM": { + "type": "apiKey", + "name": "Authorization", + "in": "header", + "x-amazon-apigateway-authtype": "awsSigv4", + } + }, + ) + + def test_enabling_auth_iam_does_not_clobber_conflicting_custom_authorizer(self): + self.kwargs["auth"] = { + "EnableIamAuthorizer": True, + "Authorizers": { + "AWS_IAM": { + "AuthorizationScopes": ["scope"], + "JwtConfiguration": {"config": "value"}, + "IdentitySource": "https://example.com", + } + }, + } + self.kwargs["definition_body"] = OpenApiEditor.gen_skeleton() + http_api = HttpApiGenerator(**self.kwargs)._construct_http_api() + self.assertEqual( + http_api.Body["components"]["securitySchemes"], + { + "AWS_IAM": { + "type": "oauth2", + "x-amazon-apigateway-authorizer": { + "jwtConfiguration": {"config": "value"}, + "identitySource": "https://example.com", + "type": "jwt", + }, + } + }, + ) + + def test_auth_iam_enabled_with_default(self): + self.kwargs["auth"] = { + "DefaultAuthorizer": "AWS_IAM", + "EnableIamAuthorizer": True, + } + self.kwargs["definition_body"] = OpenApiEditor.gen_skeleton() + http_api = HttpApiGenerator(**self.kwargs)._construct_http_api() + self.assertEqual( + http_api.Body["components"]["securitySchemes"], + { + "AWS_IAM": { + "type": "apiKey", + "name": "Authorization", + "in": "header", + "x-amazon-apigateway-authtype": "awsSigv4", + } + }, + ) + + def test_auth_missing_iam_enablement(self): + self.kwargs["auth"] = { + "DefaultAuthorizer": "AWS_IAM", + "EnableIamAuthorizer": False, + } + self.kwargs["definition_body"] = OpenApiEditor.gen_skeleton() + with pytest.raises(InvalidResourceException) as e: + HttpApiGenerator(**self.kwargs)._construct_http_api() + self.assertEqual( + e.value.message, + "Resource with id [HttpApiId] is invalid. " + + "Unable to set DefaultAuthorizer because 'AWS_IAM' was not defined in 'Authorizers'.", + ) + + def test_auth_iam_disabled(self): + self.kwargs["auth"] = { + "EnableIamAuthorizer": False, + } + self.kwargs["definition_body"] = OpenApiEditor.gen_skeleton() + http_api = HttpApiGenerator(**self.kwargs)._construct_http_api() + self.assertNotIn("components", http_api.Body) + + def test_auth_iam_not_enabled_with_unsupported_values(self): + unsupported_values = [1, "", [], {}, {"Ref": "MyVar"}, "True", None] + for val in unsupported_values: + self.kwargs["auth"] = { + "EnableIamAuthorizer": val, + } + self.kwargs["definition_body"] = OpenApiEditor.gen_skeleton() + http_api = HttpApiGenerator(**self.kwargs)._construct_http_api() + self.assertNotIn("components", http_api.Body, "EnableIamAuthorizer value: %s" % val) + def test_auth_novalue_default_does_not_raise(self): self.kwargs["auth"] = self.authorizers self.kwargs["auth"]["DefaultAuthorizer"] = {"Ref": "AWS::NoValue"} diff --git a/tests/model/test_api_v2.py b/tests/model/test_api_v2.py index 1d5428b8ec..17f88d33d8 100644 --- a/tests/model/test_api_v2.py +++ b/tests/model/test_api_v2.py @@ -7,6 +7,10 @@ class TestApiGatewayV2Authorizer(TestCase): + def test_create_iam_auth(self): + auth = ApiGatewayV2Authorizer(is_aws_iam_authorizer=True) + self.assertEqual(auth.is_aws_iam_authorizer, True) + def test_create_oauth2_auth(self): auth = ApiGatewayV2Authorizer( api_logical_id="logicalId", diff --git a/tests/translator/input/http_api_custom_iam_auth.yaml b/tests/translator/input/http_api_custom_iam_auth.yaml new file mode 100644 index 0000000000..35220d0237 --- /dev/null +++ b/tests/translator/input/http_api_custom_iam_auth.yaml @@ -0,0 +1,44 @@ +# This test-case tests what happens when an AWS_IAM authorizer is defined on an HttpApi but not enabled anywhere else. +# While the defined authorizer isn't really a true Iam authorizer (it's just a poorly-named OAuth authorizer) this shouldn't cause an error. +Resources: + HttpApiFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/todo_list.zip + Handler: index.restapi + Runtime: python3.7 + Events: + HelloAWSIAMAuth: + Type: HttpApi + Properties: + Path: /hello-aws-iam-auth + Method: get + ApiId: !Ref MyApi + Auth: + Authorizer: AWS_IAM + + MyAuthFn: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://bucket/key + Handler: index.handler + Runtime: nodejs12.x + + MyApi: + Type: AWS::Serverless::HttpApi + Properties: + Tags: + Tag1: value1 + Tag2: value2 + Auth: + Authorizers: + AWS_IAM: + AuthorizationScopes: + - scope + IdentitySource: $request.header.Authorization + JwtConfiguration: + audience: + - audience1 + - audience2 + issuer: "https://www.example.com/v1/connect/oidc" + DefaultAuthorizer: AWS_IAM diff --git a/tests/translator/input/http_api_global_iam_auth_enabled.yaml b/tests/translator/input/http_api_global_iam_auth_enabled.yaml new file mode 100644 index 0000000000..84092f5eea --- /dev/null +++ b/tests/translator/input/http_api_global_iam_auth_enabled.yaml @@ -0,0 +1,28 @@ +Globals: + HttpApi: + Auth: + EnableIamAuthorizer: true +Resources: + HttpApiFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/todo_list.zip + Handler: index.restapi + Runtime: python3.7 + Events: + # The following events use the implicit AWS::Serverless::HttpApi called "ServerlessHttpApi". + # The Iam Authorizer of the implicit AWS::Serverless::HttpApi is enabled using the global above. + # Should not have any auth enabled because there is no one set as the default on the implicit HttpApi. + ImplicitApiDefaultAuthEvent: + Type: HttpApi + Properties: + Path: /default-auth + Method: GET + # Should have Iam auth as it is set here and enabled globally. + ImplicitApiIamAuthEvent: + Type: HttpApi + Properties: + Auth: + Authorizer: AWS_IAM + Path: /iam-auth + Method: GET diff --git a/tests/translator/input/http_api_global_iam_auth_enabled_with_existing_conflicting_authorizer.yaml b/tests/translator/input/http_api_global_iam_auth_enabled_with_existing_conflicting_authorizer.yaml new file mode 100644 index 0000000000..c0c05c7b4b --- /dev/null +++ b/tests/translator/input/http_api_global_iam_auth_enabled_with_existing_conflicting_authorizer.yaml @@ -0,0 +1,23 @@ +# This test-case tests what happens when an AWS_IAM authorizer is defined on an HttpApi and also enabled globally. +# In this case the defined authorizer should NOT be overwritten. +Globals: + HttpApi: + Auth: + EnableIamAuthorizer: true +Resources: + MyApi: + Type: AWS::Serverless::HttpApi + Properties: + Auth: + Authorizers: + AWS_IAM: + AuthorizationScopes: + - scope + IdentitySource: $request.header.Authorization + JwtConfiguration: + audience: + - audience1 + - audience2 + issuer: "https://www.example.com/v1/connect/oidc" + DefaultAuthorizer: AWS_IAM + # EnableIamAuthorizer: true diff --git a/tests/translator/input/http_api_local_iam_auth_enabled.yaml b/tests/translator/input/http_api_local_iam_auth_enabled.yaml new file mode 100644 index 0000000000..50c7c38fee --- /dev/null +++ b/tests/translator/input/http_api_local_iam_auth_enabled.yaml @@ -0,0 +1,77 @@ +Globals: + HttpApi: + Auth: + EnableIamAuthorizer: false +Resources: + HttpApiFunction: + Type: AWS::Serverless::Function + Properties: + CodeUri: s3://sam-demo-bucket/todo_list.zip + Handler: index.restapi + Runtime: python3.7 + Events: + # The following events use the defined AWS::Serverless::HttpApi, MyDefaultIamAuthHttpApi, further down. + # This HttpApi has Iam auth enabled AND set as the default. + # Should not have any auth enabled as the authorizer is specifically set to "NONE". + MyDefaultIamAuthHttpApiNoAuthEvent: + Type: HttpApi + Properties: + ApiId: + Ref: MyDefaultIamAuthHttpApi + Auth: + Authorizer: NONE + Path: /no-auth + Method: GET + # Should have Iam auth as it is set as the default for the Api. + MyDefaultIamAuthHttpApiDefaultAuthEvent: + Type: HttpApi + Properties: + ApiId: + Ref: MyDefaultIamAuthHttpApi + Path: /default-auth + Method: GET + # Should have Iam auth as it is set here. + MyDefaultIamAuthHttpApiIamAuthEvent: + Type: HttpApi + Properties: + ApiId: + Ref: MyDefaultIamAuthHttpApi + Auth: + Authorizer: AWS_IAM + Path: /iam-auth + Method: GET + # The following events use the defined AWS::Serverless::HttpApi, MyIamAuthEnabledHttpApi, further down. + # This HttpApi has Iam auth enabled but NOT set as the default. + # Should not have any auth enabled because there is no one set as the default. + MyIamAuthEnabledHttpApiDefaultAuthEvent: + Type: HttpApi + Properties: + ApiId: + Ref: MyIamAuthEnabledHttpApi + Path: /default-auth + Method: GET + # Should have Iam auth as it is set here. + MyIamAuthEnabledHttpApiIamAuthEvent: + Type: HttpApi + Properties: + ApiId: + Ref: MyIamAuthEnabledHttpApi + Auth: + Authorizer: AWS_IAM + Path: /iam-auth + Method: GET + + # HTTP API resource with the Iam authorizer enabled and set to the default. + MyDefaultIamAuthHttpApi: + Type: AWS::Serverless::HttpApi + Properties: + Auth: + EnableIamAuthorizer: true + DefaultAuthorizer: AWS_IAM + + # HTTP API resource with the Iam authorizer enabled and NOT set to the default. + MyIamAuthEnabledHttpApi: + Type: AWS::Serverless::HttpApi + Properties: + Auth: + EnableIamAuthorizer: true \ No newline at end of file diff --git a/tests/translator/input/http_api_local_iam_auth_enabled_with_existing_conflicting_authorizer.yaml b/tests/translator/input/http_api_local_iam_auth_enabled_with_existing_conflicting_authorizer.yaml new file mode 100644 index 0000000000..38430e67cc --- /dev/null +++ b/tests/translator/input/http_api_local_iam_auth_enabled_with_existing_conflicting_authorizer.yaml @@ -0,0 +1,19 @@ +# This test-case tests what happens when an AWS_IAM authorizer is defined on an HttpApi and also enabled locally. +# In this case the defined authorizer should NOT be overwritten. +Resources: + MyApi: + Type: AWS::Serverless::HttpApi + Properties: + Auth: + Authorizers: + AWS_IAM: + AuthorizationScopes: + - scope + IdentitySource: $request.header.Authorization + JwtConfiguration: + audience: + - audience1 + - audience2 + issuer: "https://www.example.com/v1/connect/oidc" + DefaultAuthorizer: AWS_IAM + EnableIamAuthorizer: true diff --git a/tests/translator/input/http_api_multiple_authorizers.yaml b/tests/translator/input/http_api_multiple_authorizers.yaml index d23a443ced..cb5633c83c 100644 --- a/tests/translator/input/http_api_multiple_authorizers.yaml +++ b/tests/translator/input/http_api_multiple_authorizers.yaml @@ -30,6 +30,14 @@ Resources: Type: HttpApi Properties: ApiId: !Ref MyApi + HelloAWSIAMAuth: + Type: HttpApi + Properties: + Path: /hello-aws-iam-auth + Method: get + ApiId: !Ref MyApi + Auth: + Authorizer: AWS_IAM MyAuthFn: Type: AWS::Serverless::Function @@ -58,4 +66,5 @@ Resources: - audience1 - audience2 issuer: "https://www.example.com/v1/connect/oidc" - DefaultAuthorizer: LambdaAuth \ No newline at end of file + DefaultAuthorizer: LambdaAuth + EnableIamAuthorizer: true diff --git a/tests/translator/output/aws-cn/http_api_custom_iam_auth.json b/tests/translator/output/aws-cn/http_api_custom_iam_auth.json new file mode 100644 index 0000000000..295aab3d87 --- /dev/null +++ b/tests/translator/output/aws-cn/http_api_custom_iam_auth.json @@ -0,0 +1,137 @@ +{ + "Resources": { + "HttpApiFunction": { + "Properties": { + "Code": { "S3Bucket": "sam-demo-bucket", "S3Key": "todo_list.zip" }, + "Handler": "index.restapi", + "Role": { "Fn::GetAtt": ["Arn", "HttpApiFunctionRole"] }, + "Runtime": "python3.7", + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::Lambda::Function" + }, + "HttpApiFunctionHelloAWSIAMAuthPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { "__ApiId__": { "Ref": "MyApi" }, "__Stage__": "*" }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/hello-aws-iam-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": ["sts:AssumeRole"], + "Effect": "Allow", + "Principal": { "Service": ["lambda.amazonaws.com"] } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::IAM::Role" + }, + "MyApi": { + "Properties": { + "Body": { + "components": { + "securitySchemes": { + "AWS_IAM": { + "type": "oauth2", + "x-amazon-apigateway-authorizer": { + "identitySource": "$request.header.Authorization", + "jwtConfiguration": { + "audience": ["audience1", "audience2"], + "issuer": "https://www.example.com/v1/connect/oidc" + }, + "type": "jwt" + } + } + } + }, + "info": { "title": { "Ref": "AWS::StackName" }, "version": "1.0" }, + "openapi": "3.0.1", + "paths": { + "/hello-aws-iam-auth": { + "get": { + "responses": {}, + "security": [{ "AWS_IAM": [] }], + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + } + }, + "tags": [ + { "name": "Tag1", "x-amazon-apigateway-tag-value": "value1" }, + { "name": "Tag2", "x-amazon-apigateway-tag-value": "value2" }, + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { "Ref": "MyApi" }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { + "Tag1": "value1", + "Tag2": "value2", + "httpapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyAuthFn": { + "Properties": { + "Code": { "S3Bucket": "bucket", "S3Key": "key" }, + "Handler": "index.handler", + "Role": { "Fn::GetAtt": ["Arn", "MyAuthFnRole"] }, + "Runtime": "nodejs12.x", + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::Lambda::Function" + }, + "MyAuthFnRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": ["sts:AssumeRole"], + "Effect": "Allow", + "Principal": { "Service": ["lambda.amazonaws.com"] } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-cn/http_api_global_iam_auth_enabled.json b/tests/translator/output/aws-cn/http_api_global_iam_auth_enabled.json new file mode 100644 index 0000000000..4b0504085d --- /dev/null +++ b/tests/translator/output/aws-cn/http_api_global_iam_auth_enabled.json @@ -0,0 +1,124 @@ +{ + "Resources": { + "HttpApiFunction": { + "Properties": { + "Code": { "S3Bucket": "sam-demo-bucket", "S3Key": "todo_list.zip" }, + "Handler": "index.restapi", + "Role": { "Fn::GetAtt": ["Arn", "HttpApiFunctionRole"] }, + "Runtime": "python3.7", + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::Lambda::Function" + }, + "HttpApiFunctionImplicitApiDefaultAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { "__ApiId__": { "Ref": "ServerlessHttpApi" }, "__Stage__": "*" }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/default-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionImplicitApiIamAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { "__ApiId__": { "Ref": "ServerlessHttpApi" }, "__Stage__": "*" }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/iam-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": ["sts:AssumeRole"], + "Effect": "Allow", + "Principal": { "Service": ["lambda.amazonaws.com"] } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::IAM::Role" + }, + "ServerlessHttpApi": { + "Properties": { + "Body": { + "components": { + "securitySchemes": { + "AWS_IAM": { + "in": "header", + "name": "Authorization", + "type": "apiKey", + "x-amazon-apigateway-authtype": "awsSigv4" + } + } + }, + "info": { "title": { "Ref": "AWS::StackName" }, "version": "1.0" }, + "openapi": "3.0.1", + "paths": { + "/default-auth": { + "get": { + "responses": {}, + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + }, + "/iam-auth": { + "get": { + "responses": {}, + "security": [{ "AWS_IAM": [] }], + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + } + }, + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "ServerlessHttpApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { "Ref": "ServerlessHttpApi" }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { "httpapi:createdBy": "SAM" } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-cn/http_api_global_iam_auth_enabled_with_existing_conflicting_authorizer.json b/tests/translator/output/aws-cn/http_api_global_iam_auth_enabled_with_existing_conflicting_authorizer.json new file mode 100644 index 0000000000..ceea480e89 --- /dev/null +++ b/tests/translator/output/aws-cn/http_api_global_iam_auth_enabled_with_existing_conflicting_authorizer.json @@ -0,0 +1,44 @@ +{ + "Resources": { + "MyApi": { + "Properties": { + "Body": { + "components": { + "securitySchemes": { + "AWS_IAM": { + "type": "oauth2", + "x-amazon-apigateway-authorizer": { + "identitySource": "$request.header.Authorization", + "jwtConfiguration": { + "audience": ["audience1", "audience2"], + "issuer": "https://www.example.com/v1/connect/oidc" + }, + "type": "jwt" + } + } + } + }, + "info": { "title": { "Ref": "AWS::StackName" }, "version": "1.0" }, + "openapi": "3.0.1", + "paths": {}, + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { "Ref": "MyApi" }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { "httpapi:createdBy": "SAM" } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-cn/http_api_local_iam_auth_enabled.json b/tests/translator/output/aws-cn/http_api_local_iam_auth_enabled.json new file mode 100644 index 0000000000..6cf579d137 --- /dev/null +++ b/tests/translator/output/aws-cn/http_api_local_iam_auth_enabled.json @@ -0,0 +1,259 @@ +{ + "Resources": { + "HttpApiFunction": { + "Properties": { + "Code": { "S3Bucket": "sam-demo-bucket", "S3Key": "todo_list.zip" }, + "Handler": "index.restapi", + "Role": { "Fn::GetAtt": ["Arn", "HttpApiFunctionRole"] }, + "Runtime": "python3.7", + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::Lambda::Function" + }, + "HttpApiFunctionMyDefaultIamAuthHttpApiDefaultAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { + "__ApiId__": { "Ref": "MyDefaultIamAuthHttpApi" }, + "__Stage__": "*" + }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/default-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionMyDefaultIamAuthHttpApiIamAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { + "__ApiId__": { "Ref": "MyDefaultIamAuthHttpApi" }, + "__Stage__": "*" + }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/iam-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionMyDefaultIamAuthHttpApiNoAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { + "__ApiId__": { "Ref": "MyDefaultIamAuthHttpApi" }, + "__Stage__": "*" + }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/no-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionMyIamAuthEnabledHttpApiDefaultAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { + "__ApiId__": { "Ref": "MyIamAuthEnabledHttpApi" }, + "__Stage__": "*" + }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/default-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionMyIamAuthEnabledHttpApiIamAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { + "__ApiId__": { "Ref": "MyIamAuthEnabledHttpApi" }, + "__Stage__": "*" + }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/iam-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": ["sts:AssumeRole"], + "Effect": "Allow", + "Principal": { "Service": ["lambda.amazonaws.com"] } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-cn:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::IAM::Role" + }, + "MyDefaultIamAuthHttpApi": { + "Properties": { + "Body": { + "components": { + "securitySchemes": { + "AWS_IAM": { + "in": "header", + "name": "Authorization", + "type": "apiKey", + "x-amazon-apigateway-authtype": "awsSigv4" + } + } + }, + "info": { "title": { "Ref": "AWS::StackName" }, "version": "1.0" }, + "openapi": "3.0.1", + "paths": { + "/default-auth": { + "get": { + "responses": {}, + "security": [{ "AWS_IAM": [] }], + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + }, + "/iam-auth": { + "get": { + "responses": {}, + "security": [{ "AWS_IAM": [] }], + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + }, + "/no-auth": { + "get": { + "responses": {}, + "security": [{ "NONE": [] }], + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + } + }, + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyDefaultIamAuthHttpApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { "Ref": "MyDefaultIamAuthHttpApi" }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { "httpapi:createdBy": "SAM" } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyIamAuthEnabledHttpApi": { + "Properties": { + "Body": { + "components": { + "securitySchemes": { + "AWS_IAM": { + "in": "header", + "name": "Authorization", + "type": "apiKey", + "x-amazon-apigateway-authtype": "awsSigv4" + } + } + }, + "info": { "title": { "Ref": "AWS::StackName" }, "version": "1.0" }, + "openapi": "3.0.1", + "paths": { + "/default-auth": { + "get": { + "responses": {}, + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + }, + "/iam-auth": { + "get": { + "responses": {}, + "security": [{ "AWS_IAM": [] }], + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + } + }, + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyIamAuthEnabledHttpApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { "Ref": "MyIamAuthEnabledHttpApi" }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { "httpapi:createdBy": "SAM" } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-cn/http_api_local_iam_auth_enabled_with_existing_conflicting_authorizer.json b/tests/translator/output/aws-cn/http_api_local_iam_auth_enabled_with_existing_conflicting_authorizer.json new file mode 100644 index 0000000000..ceea480e89 --- /dev/null +++ b/tests/translator/output/aws-cn/http_api_local_iam_auth_enabled_with_existing_conflicting_authorizer.json @@ -0,0 +1,44 @@ +{ + "Resources": { + "MyApi": { + "Properties": { + "Body": { + "components": { + "securitySchemes": { + "AWS_IAM": { + "type": "oauth2", + "x-amazon-apigateway-authorizer": { + "identitySource": "$request.header.Authorization", + "jwtConfiguration": { + "audience": ["audience1", "audience2"], + "issuer": "https://www.example.com/v1/connect/oidc" + }, + "type": "jwt" + } + } + } + }, + "info": { "title": { "Ref": "AWS::StackName" }, "version": "1.0" }, + "openapi": "3.0.1", + "paths": {}, + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { "Ref": "MyApi" }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { "httpapi:createdBy": "SAM" } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-cn/http_api_multiple_authorizers.json b/tests/translator/output/aws-cn/http_api_multiple_authorizers.json index 97e5c24938..a42dc5f8a6 100644 --- a/tests/translator/output/aws-cn/http_api_multiple_authorizers.json +++ b/tests/translator/output/aws-cn/http_api_multiple_authorizers.json @@ -9,10 +9,7 @@ }, "Handler": "index.restapi", "Role": { - "Fn::GetAtt": [ - "HttpApiFunctionRole", - "Arn" - ] + "Fn::GetAtt": ["HttpApiFunctionRole", "Arn"] }, "Runtime": "python3.7", "Tags": [ @@ -30,14 +27,10 @@ "Version": "2012-10-17", "Statement": [ { - "Action": [ - "sts:AssumeRole" - ], + "Action": ["sts:AssumeRole"], "Effect": "Allow", "Principal": { - "Service": [ - "lambda.amazonaws.com" - ] + "Service": ["lambda.amazonaws.com"] } } ] @@ -83,10 +76,7 @@ }, "Handler": "index.handler", "Role": { - "Fn::GetAtt": [ - "MyAuthFnRole", - "Arn" - ] + "Fn::GetAtt": ["MyAuthFnRole", "Arn"] }, "Runtime": "nodejs12.x", "Tags": [ @@ -104,14 +94,10 @@ "Version": "2012-10-17", "Statement": [ { - "Action": [ - "sts:AssumeRole" - ], + "Action": ["sts:AssumeRole"], "Effect": "Allow", "Principal": { - "Service": [ - "lambda.amazonaws.com" - ] + "Service": ["lambda.amazonaws.com"] } } ] @@ -168,9 +154,7 @@ "responses": {}, "security": [ { - "MyOauth2Authorizer": [ - "scope" - ] + "MyOauth2Authorizer": ["scope"] } ] }, @@ -191,6 +175,24 @@ ] } }, + "/hello-aws-iam-auth": { + "get": { + "x-amazon-apigateway-integration": { + "type": "aws_proxy", + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + }, + "responses": {}, + "security": [ + { + "AWS_IAM": [] + } + ] + } + }, "$default": { "x-amazon-apigateway-any-method": { "x-amazon-apigateway-integration": { @@ -213,6 +215,12 @@ }, "components": { "securitySchemes": { + "AWS_IAM": { + "type": "apiKey", + "name": "Authorization", + "in": "header", + "x-amazon-apigateway-authtype": "awsSigv4" + }, "LambdaAuth": { "type": "apiKey", "name": "Unused", @@ -224,10 +232,7 @@ "arn:aws-cn:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", { "__FunctionArn__": { - "Fn::GetAtt": [ - "MyAuthFn", - "Arn" - ] + "Fn::GetAtt": ["MyAuthFn", "Arn"] } } ] @@ -239,10 +244,7 @@ "type": "oauth2", "x-amazon-apigateway-authorizer": { "jwtConfiguration": { - "audience": [ - "audience1", - "audience2" - ], + "audience": ["audience1", "audience2"], "issuer": "https://www.example.com/v1/connect/oidc" }, "identitySource": "$request.header.Authorization", @@ -284,4 +286,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/translator/output/aws-us-gov/http_api_custom_iam_auth.json b/tests/translator/output/aws-us-gov/http_api_custom_iam_auth.json new file mode 100644 index 0000000000..3266785221 --- /dev/null +++ b/tests/translator/output/aws-us-gov/http_api_custom_iam_auth.json @@ -0,0 +1,137 @@ +{ + "Resources": { + "HttpApiFunction": { + "Properties": { + "Code": { "S3Bucket": "sam-demo-bucket", "S3Key": "todo_list.zip" }, + "Handler": "index.restapi", + "Role": { "Fn::GetAtt": ["Arn", "HttpApiFunctionRole"] }, + "Runtime": "python3.7", + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::Lambda::Function" + }, + "HttpApiFunctionHelloAWSIAMAuthPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { "__ApiId__": { "Ref": "MyApi" }, "__Stage__": "*" }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/hello-aws-iam-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": ["sts:AssumeRole"], + "Effect": "Allow", + "Principal": { "Service": ["lambda.amazonaws.com"] } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::IAM::Role" + }, + "MyApi": { + "Properties": { + "Body": { + "components": { + "securitySchemes": { + "AWS_IAM": { + "type": "oauth2", + "x-amazon-apigateway-authorizer": { + "identitySource": "$request.header.Authorization", + "jwtConfiguration": { + "audience": ["audience1", "audience2"], + "issuer": "https://www.example.com/v1/connect/oidc" + }, + "type": "jwt" + } + } + } + }, + "info": { "title": { "Ref": "AWS::StackName" }, "version": "1.0" }, + "openapi": "3.0.1", + "paths": { + "/hello-aws-iam-auth": { + "get": { + "responses": {}, + "security": [{ "AWS_IAM": [] }], + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + } + }, + "tags": [ + { "name": "Tag1", "x-amazon-apigateway-tag-value": "value1" }, + { "name": "Tag2", "x-amazon-apigateway-tag-value": "value2" }, + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { "Ref": "MyApi" }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { + "Tag1": "value1", + "Tag2": "value2", + "httpapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyAuthFn": { + "Properties": { + "Code": { "S3Bucket": "bucket", "S3Key": "key" }, + "Handler": "index.handler", + "Role": { "Fn::GetAtt": ["Arn", "MyAuthFnRole"] }, + "Runtime": "nodejs12.x", + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::Lambda::Function" + }, + "MyAuthFnRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": ["sts:AssumeRole"], + "Effect": "Allow", + "Principal": { "Service": ["lambda.amazonaws.com"] } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/aws-us-gov/http_api_global_iam_auth_enabled.json b/tests/translator/output/aws-us-gov/http_api_global_iam_auth_enabled.json new file mode 100644 index 0000000000..de3f06ee56 --- /dev/null +++ b/tests/translator/output/aws-us-gov/http_api_global_iam_auth_enabled.json @@ -0,0 +1,124 @@ +{ + "Resources": { + "HttpApiFunction": { + "Properties": { + "Code": { "S3Bucket": "sam-demo-bucket", "S3Key": "todo_list.zip" }, + "Handler": "index.restapi", + "Role": { "Fn::GetAtt": ["Arn", "HttpApiFunctionRole"] }, + "Runtime": "python3.7", + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::Lambda::Function" + }, + "HttpApiFunctionImplicitApiDefaultAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { "__ApiId__": { "Ref": "ServerlessHttpApi" }, "__Stage__": "*" }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/default-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionImplicitApiIamAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { "__ApiId__": { "Ref": "ServerlessHttpApi" }, "__Stage__": "*" }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/iam-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": ["sts:AssumeRole"], + "Effect": "Allow", + "Principal": { "Service": ["lambda.amazonaws.com"] } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::IAM::Role" + }, + "ServerlessHttpApi": { + "Properties": { + "Body": { + "components": { + "securitySchemes": { + "AWS_IAM": { + "in": "header", + "name": "Authorization", + "type": "apiKey", + "x-amazon-apigateway-authtype": "awsSigv4" + } + } + }, + "info": { "title": { "Ref": "AWS::StackName" }, "version": "1.0" }, + "openapi": "3.0.1", + "paths": { + "/default-auth": { + "get": { + "responses": {}, + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + }, + "/iam-auth": { + "get": { + "responses": {}, + "security": [{ "AWS_IAM": [] }], + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + } + }, + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "ServerlessHttpApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { "Ref": "ServerlessHttpApi" }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { "httpapi:createdBy": "SAM" } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-us-gov/http_api_global_iam_auth_enabled_with_existing_conflicting_authorizer.json b/tests/translator/output/aws-us-gov/http_api_global_iam_auth_enabled_with_existing_conflicting_authorizer.json new file mode 100644 index 0000000000..ceea480e89 --- /dev/null +++ b/tests/translator/output/aws-us-gov/http_api_global_iam_auth_enabled_with_existing_conflicting_authorizer.json @@ -0,0 +1,44 @@ +{ + "Resources": { + "MyApi": { + "Properties": { + "Body": { + "components": { + "securitySchemes": { + "AWS_IAM": { + "type": "oauth2", + "x-amazon-apigateway-authorizer": { + "identitySource": "$request.header.Authorization", + "jwtConfiguration": { + "audience": ["audience1", "audience2"], + "issuer": "https://www.example.com/v1/connect/oidc" + }, + "type": "jwt" + } + } + } + }, + "info": { "title": { "Ref": "AWS::StackName" }, "version": "1.0" }, + "openapi": "3.0.1", + "paths": {}, + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { "Ref": "MyApi" }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { "httpapi:createdBy": "SAM" } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-us-gov/http_api_local_iam_auth_enabled.json b/tests/translator/output/aws-us-gov/http_api_local_iam_auth_enabled.json new file mode 100644 index 0000000000..c488588336 --- /dev/null +++ b/tests/translator/output/aws-us-gov/http_api_local_iam_auth_enabled.json @@ -0,0 +1,259 @@ +{ + "Resources": { + "HttpApiFunction": { + "Properties": { + "Code": { "S3Bucket": "sam-demo-bucket", "S3Key": "todo_list.zip" }, + "Handler": "index.restapi", + "Role": { "Fn::GetAtt": ["Arn", "HttpApiFunctionRole"] }, + "Runtime": "python3.7", + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::Lambda::Function" + }, + "HttpApiFunctionMyDefaultIamAuthHttpApiDefaultAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { + "__ApiId__": { "Ref": "MyDefaultIamAuthHttpApi" }, + "__Stage__": "*" + }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/default-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionMyDefaultIamAuthHttpApiIamAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { + "__ApiId__": { "Ref": "MyDefaultIamAuthHttpApi" }, + "__Stage__": "*" + }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/iam-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionMyDefaultIamAuthHttpApiNoAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { + "__ApiId__": { "Ref": "MyDefaultIamAuthHttpApi" }, + "__Stage__": "*" + }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/no-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionMyIamAuthEnabledHttpApiDefaultAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { + "__ApiId__": { "Ref": "MyIamAuthEnabledHttpApi" }, + "__Stage__": "*" + }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/default-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionMyIamAuthEnabledHttpApiIamAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { + "__ApiId__": { "Ref": "MyIamAuthEnabledHttpApi" }, + "__Stage__": "*" + }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/iam-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": ["sts:AssumeRole"], + "Effect": "Allow", + "Principal": { "Service": ["lambda.amazonaws.com"] } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws-us-gov:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::IAM::Role" + }, + "MyDefaultIamAuthHttpApi": { + "Properties": { + "Body": { + "components": { + "securitySchemes": { + "AWS_IAM": { + "in": "header", + "name": "Authorization", + "type": "apiKey", + "x-amazon-apigateway-authtype": "awsSigv4" + } + } + }, + "info": { "title": { "Ref": "AWS::StackName" }, "version": "1.0" }, + "openapi": "3.0.1", + "paths": { + "/default-auth": { + "get": { + "responses": {}, + "security": [{ "AWS_IAM": [] }], + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + }, + "/iam-auth": { + "get": { + "responses": {}, + "security": [{ "AWS_IAM": [] }], + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + }, + "/no-auth": { + "get": { + "responses": {}, + "security": [{ "NONE": [] }], + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + } + }, + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyDefaultIamAuthHttpApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { "Ref": "MyDefaultIamAuthHttpApi" }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { "httpapi:createdBy": "SAM" } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyIamAuthEnabledHttpApi": { + "Properties": { + "Body": { + "components": { + "securitySchemes": { + "AWS_IAM": { + "in": "header", + "name": "Authorization", + "type": "apiKey", + "x-amazon-apigateway-authtype": "awsSigv4" + } + } + }, + "info": { "title": { "Ref": "AWS::StackName" }, "version": "1.0" }, + "openapi": "3.0.1", + "paths": { + "/default-auth": { + "get": { + "responses": {}, + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + }, + "/iam-auth": { + "get": { + "responses": {}, + "security": [{ "AWS_IAM": [] }], + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + } + }, + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyIamAuthEnabledHttpApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { "Ref": "MyIamAuthEnabledHttpApi" }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { "httpapi:createdBy": "SAM" } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-us-gov/http_api_local_iam_auth_enabled_with_existing_conflicting_authorizer.json b/tests/translator/output/aws-us-gov/http_api_local_iam_auth_enabled_with_existing_conflicting_authorizer.json new file mode 100644 index 0000000000..ceea480e89 --- /dev/null +++ b/tests/translator/output/aws-us-gov/http_api_local_iam_auth_enabled_with_existing_conflicting_authorizer.json @@ -0,0 +1,44 @@ +{ + "Resources": { + "MyApi": { + "Properties": { + "Body": { + "components": { + "securitySchemes": { + "AWS_IAM": { + "type": "oauth2", + "x-amazon-apigateway-authorizer": { + "identitySource": "$request.header.Authorization", + "jwtConfiguration": { + "audience": ["audience1", "audience2"], + "issuer": "https://www.example.com/v1/connect/oidc" + }, + "type": "jwt" + } + } + } + }, + "info": { "title": { "Ref": "AWS::StackName" }, "version": "1.0" }, + "openapi": "3.0.1", + "paths": {}, + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { "Ref": "MyApi" }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { "httpapi:createdBy": "SAM" } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/aws-us-gov/http_api_multiple_authorizers.json b/tests/translator/output/aws-us-gov/http_api_multiple_authorizers.json index cf32096be2..3f705ca939 100644 --- a/tests/translator/output/aws-us-gov/http_api_multiple_authorizers.json +++ b/tests/translator/output/aws-us-gov/http_api_multiple_authorizers.json @@ -9,10 +9,7 @@ }, "Handler": "index.restapi", "Role": { - "Fn::GetAtt": [ - "HttpApiFunctionRole", - "Arn" - ] + "Fn::GetAtt": ["HttpApiFunctionRole", "Arn"] }, "Runtime": "python3.7", "Tags": [ @@ -30,14 +27,10 @@ "Version": "2012-10-17", "Statement": [ { - "Action": [ - "sts:AssumeRole" - ], + "Action": ["sts:AssumeRole"], "Effect": "Allow", "Principal": { - "Service": [ - "lambda.amazonaws.com" - ] + "Service": ["lambda.amazonaws.com"] } } ] @@ -83,10 +76,7 @@ }, "Handler": "index.handler", "Role": { - "Fn::GetAtt": [ - "MyAuthFnRole", - "Arn" - ] + "Fn::GetAtt": ["MyAuthFnRole", "Arn"] }, "Runtime": "nodejs12.x", "Tags": [ @@ -104,14 +94,10 @@ "Version": "2012-10-17", "Statement": [ { - "Action": [ - "sts:AssumeRole" - ], + "Action": ["sts:AssumeRole"], "Effect": "Allow", "Principal": { - "Service": [ - "lambda.amazonaws.com" - ] + "Service": ["lambda.amazonaws.com"] } } ] @@ -168,9 +154,7 @@ "responses": {}, "security": [ { - "MyOauth2Authorizer": [ - "scope" - ] + "MyOauth2Authorizer": ["scope"] } ] }, @@ -191,6 +175,24 @@ ] } }, + "/hello-aws-iam-auth": { + "get": { + "x-amazon-apigateway-integration": { + "type": "aws_proxy", + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + }, + "responses": {}, + "security": [ + { + "AWS_IAM": [] + } + ] + } + }, "$default": { "x-amazon-apigateway-any-method": { "x-amazon-apigateway-integration": { @@ -213,6 +215,12 @@ }, "components": { "securitySchemes": { + "AWS_IAM": { + "type": "apiKey", + "name": "Authorization", + "in": "header", + "x-amazon-apigateway-authtype": "awsSigv4" + }, "LambdaAuth": { "type": "apiKey", "name": "Unused", @@ -224,10 +232,7 @@ "arn:aws-us-gov:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", { "__FunctionArn__": { - "Fn::GetAtt": [ - "MyAuthFn", - "Arn" - ] + "Fn::GetAtt": ["MyAuthFn", "Arn"] } } ] @@ -239,10 +244,7 @@ "type": "oauth2", "x-amazon-apigateway-authorizer": { "jwtConfiguration": { - "audience": [ - "audience1", - "audience2" - ], + "audience": ["audience1", "audience2"], "issuer": "https://www.example.com/v1/connect/oidc" }, "identitySource": "$request.header.Authorization", @@ -284,4 +286,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/translator/output/http_api_custom_iam_auth.json b/tests/translator/output/http_api_custom_iam_auth.json new file mode 100644 index 0000000000..d4fb4acef7 --- /dev/null +++ b/tests/translator/output/http_api_custom_iam_auth.json @@ -0,0 +1,137 @@ +{ + "Resources": { + "HttpApiFunction": { + "Properties": { + "Code": { "S3Bucket": "sam-demo-bucket", "S3Key": "todo_list.zip" }, + "Handler": "index.restapi", + "Role": { "Fn::GetAtt": ["Arn", "HttpApiFunctionRole"] }, + "Runtime": "python3.7", + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::Lambda::Function" + }, + "HttpApiFunctionHelloAWSIAMAuthPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { "__ApiId__": { "Ref": "MyApi" }, "__Stage__": "*" }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/hello-aws-iam-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": ["sts:AssumeRole"], + "Effect": "Allow", + "Principal": { "Service": ["lambda.amazonaws.com"] } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::IAM::Role" + }, + "MyApi": { + "Properties": { + "Body": { + "components": { + "securitySchemes": { + "AWS_IAM": { + "type": "oauth2", + "x-amazon-apigateway-authorizer": { + "identitySource": "$request.header.Authorization", + "jwtConfiguration": { + "audience": ["audience1", "audience2"], + "issuer": "https://www.example.com/v1/connect/oidc" + }, + "type": "jwt" + } + } + } + }, + "info": { "title": { "Ref": "AWS::StackName" }, "version": "1.0" }, + "openapi": "3.0.1", + "paths": { + "/hello-aws-iam-auth": { + "get": { + "responses": {}, + "security": [{ "AWS_IAM": [] }], + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + } + }, + "tags": [ + { "name": "Tag1", "x-amazon-apigateway-tag-value": "value1" }, + { "name": "Tag2", "x-amazon-apigateway-tag-value": "value2" }, + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { "Ref": "MyApi" }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { + "Tag1": "value1", + "Tag2": "value2", + "httpapi:createdBy": "SAM" + } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyAuthFn": { + "Properties": { + "Code": { "S3Bucket": "bucket", "S3Key": "key" }, + "Handler": "index.handler", + "Role": { "Fn::GetAtt": ["Arn", "MyAuthFnRole"] }, + "Runtime": "nodejs12.x", + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::Lambda::Function" + }, + "MyAuthFnRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": ["sts:AssumeRole"], + "Effect": "Allow", + "Principal": { "Service": ["lambda.amazonaws.com"] } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::IAM::Role" + } + } +} diff --git a/tests/translator/output/http_api_global_iam_auth_enabled.json b/tests/translator/output/http_api_global_iam_auth_enabled.json new file mode 100644 index 0000000000..76c2cbe950 --- /dev/null +++ b/tests/translator/output/http_api_global_iam_auth_enabled.json @@ -0,0 +1,124 @@ +{ + "Resources": { + "HttpApiFunction": { + "Properties": { + "Code": { "S3Bucket": "sam-demo-bucket", "S3Key": "todo_list.zip" }, + "Handler": "index.restapi", + "Role": { "Fn::GetAtt": ["Arn", "HttpApiFunctionRole"] }, + "Runtime": "python3.7", + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::Lambda::Function" + }, + "HttpApiFunctionImplicitApiDefaultAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { "__ApiId__": { "Ref": "ServerlessHttpApi" }, "__Stage__": "*" }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/default-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionImplicitApiIamAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { "__ApiId__": { "Ref": "ServerlessHttpApi" }, "__Stage__": "*" }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/iam-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": ["sts:AssumeRole"], + "Effect": "Allow", + "Principal": { "Service": ["lambda.amazonaws.com"] } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::IAM::Role" + }, + "ServerlessHttpApi": { + "Properties": { + "Body": { + "components": { + "securitySchemes": { + "AWS_IAM": { + "in": "header", + "name": "Authorization", + "type": "apiKey", + "x-amazon-apigateway-authtype": "awsSigv4" + } + } + }, + "info": { "title": { "Ref": "AWS::StackName" }, "version": "1.0" }, + "openapi": "3.0.1", + "paths": { + "/default-auth": { + "get": { + "responses": {}, + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + }, + "/iam-auth": { + "get": { + "responses": {}, + "security": [{ "AWS_IAM": [] }], + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + } + }, + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "ServerlessHttpApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { "Ref": "ServerlessHttpApi" }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { "httpapi:createdBy": "SAM" } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/http_api_global_iam_auth_enabled_with_existing_conflicting_authorizer.json b/tests/translator/output/http_api_global_iam_auth_enabled_with_existing_conflicting_authorizer.json new file mode 100644 index 0000000000..ceea480e89 --- /dev/null +++ b/tests/translator/output/http_api_global_iam_auth_enabled_with_existing_conflicting_authorizer.json @@ -0,0 +1,44 @@ +{ + "Resources": { + "MyApi": { + "Properties": { + "Body": { + "components": { + "securitySchemes": { + "AWS_IAM": { + "type": "oauth2", + "x-amazon-apigateway-authorizer": { + "identitySource": "$request.header.Authorization", + "jwtConfiguration": { + "audience": ["audience1", "audience2"], + "issuer": "https://www.example.com/v1/connect/oidc" + }, + "type": "jwt" + } + } + } + }, + "info": { "title": { "Ref": "AWS::StackName" }, "version": "1.0" }, + "openapi": "3.0.1", + "paths": {}, + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { "Ref": "MyApi" }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { "httpapi:createdBy": "SAM" } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/http_api_local_iam_auth_enabled.json b/tests/translator/output/http_api_local_iam_auth_enabled.json new file mode 100644 index 0000000000..e79a9585ee --- /dev/null +++ b/tests/translator/output/http_api_local_iam_auth_enabled.json @@ -0,0 +1,259 @@ +{ + "Resources": { + "HttpApiFunction": { + "Properties": { + "Code": { "S3Bucket": "sam-demo-bucket", "S3Key": "todo_list.zip" }, + "Handler": "index.restapi", + "Role": { "Fn::GetAtt": ["Arn", "HttpApiFunctionRole"] }, + "Runtime": "python3.7", + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::Lambda::Function" + }, + "HttpApiFunctionMyDefaultIamAuthHttpApiDefaultAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { + "__ApiId__": { "Ref": "MyDefaultIamAuthHttpApi" }, + "__Stage__": "*" + }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/default-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionMyDefaultIamAuthHttpApiIamAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { + "__ApiId__": { "Ref": "MyDefaultIamAuthHttpApi" }, + "__Stage__": "*" + }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/iam-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionMyDefaultIamAuthHttpApiNoAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { + "__ApiId__": { "Ref": "MyDefaultIamAuthHttpApi" }, + "__Stage__": "*" + }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/no-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionMyIamAuthEnabledHttpApiDefaultAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { + "__ApiId__": { "Ref": "MyIamAuthEnabledHttpApi" }, + "__Stage__": "*" + }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/default-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionMyIamAuthEnabledHttpApiIamAuthEventPermission": { + "Properties": { + "Action": "lambda:InvokeFunction", + "FunctionName": { "Ref": "HttpApiFunction" }, + "Principal": "apigateway.amazonaws.com", + "SourceArn": { + "Fn::Sub": [ + { + "__ApiId__": { "Ref": "MyIamAuthEnabledHttpApi" }, + "__Stage__": "*" + }, + "arn:${AWS::Partition}:execute-api:${AWS::Region}:${AWS::AccountId}:${__ApiId__}/${__Stage__}/GET/iam-auth" + ] + } + }, + "Type": "AWS::Lambda::Permission" + }, + "HttpApiFunctionRole": { + "Properties": { + "AssumeRolePolicyDocument": { + "Statement": [ + { + "Action": ["sts:AssumeRole"], + "Effect": "Allow", + "Principal": { "Service": ["lambda.amazonaws.com"] } + } + ], + "Version": "2012-10-17" + }, + "ManagedPolicyArns": [ + "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole" + ], + "Tags": [{ "Key": "lambda:createdBy", "Value": "SAM" }] + }, + "Type": "AWS::IAM::Role" + }, + "MyDefaultIamAuthHttpApi": { + "Properties": { + "Body": { + "components": { + "securitySchemes": { + "AWS_IAM": { + "in": "header", + "name": "Authorization", + "type": "apiKey", + "x-amazon-apigateway-authtype": "awsSigv4" + } + } + }, + "info": { "title": { "Ref": "AWS::StackName" }, "version": "1.0" }, + "openapi": "3.0.1", + "paths": { + "/default-auth": { + "get": { + "responses": {}, + "security": [{ "AWS_IAM": [] }], + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + }, + "/iam-auth": { + "get": { + "responses": {}, + "security": [{ "AWS_IAM": [] }], + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + }, + "/no-auth": { + "get": { + "responses": {}, + "security": [{ "NONE": [] }], + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + } + }, + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyDefaultIamAuthHttpApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { "Ref": "MyDefaultIamAuthHttpApi" }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { "httpapi:createdBy": "SAM" } + }, + "Type": "AWS::ApiGatewayV2::Stage" + }, + "MyIamAuthEnabledHttpApi": { + "Properties": { + "Body": { + "components": { + "securitySchemes": { + "AWS_IAM": { + "in": "header", + "name": "Authorization", + "type": "apiKey", + "x-amazon-apigateway-authtype": "awsSigv4" + } + } + }, + "info": { "title": { "Ref": "AWS::StackName" }, "version": "1.0" }, + "openapi": "3.0.1", + "paths": { + "/default-auth": { + "get": { + "responses": {}, + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + }, + "/iam-auth": { + "get": { + "responses": {}, + "security": [{ "AWS_IAM": [] }], + "x-amazon-apigateway-integration": { + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "type": "aws_proxy", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + } + } + } + }, + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyIamAuthEnabledHttpApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { "Ref": "MyIamAuthEnabledHttpApi" }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { "httpapi:createdBy": "SAM" } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/http_api_local_iam_auth_enabled_with_existing_conflicting_authorizer.json b/tests/translator/output/http_api_local_iam_auth_enabled_with_existing_conflicting_authorizer.json new file mode 100644 index 0000000000..ceea480e89 --- /dev/null +++ b/tests/translator/output/http_api_local_iam_auth_enabled_with_existing_conflicting_authorizer.json @@ -0,0 +1,44 @@ +{ + "Resources": { + "MyApi": { + "Properties": { + "Body": { + "components": { + "securitySchemes": { + "AWS_IAM": { + "type": "oauth2", + "x-amazon-apigateway-authorizer": { + "identitySource": "$request.header.Authorization", + "jwtConfiguration": { + "audience": ["audience1", "audience2"], + "issuer": "https://www.example.com/v1/connect/oidc" + }, + "type": "jwt" + } + } + } + }, + "info": { "title": { "Ref": "AWS::StackName" }, "version": "1.0" }, + "openapi": "3.0.1", + "paths": {}, + "tags": [ + { + "name": "httpapi:createdBy", + "x-amazon-apigateway-tag-value": "SAM" + } + ] + } + }, + "Type": "AWS::ApiGatewayV2::Api" + }, + "MyApiApiGatewayDefaultStage": { + "Properties": { + "ApiId": { "Ref": "MyApi" }, + "AutoDeploy": true, + "StageName": "$default", + "Tags": { "httpapi:createdBy": "SAM" } + }, + "Type": "AWS::ApiGatewayV2::Stage" + } + } +} diff --git a/tests/translator/output/http_api_multiple_authorizers.json b/tests/translator/output/http_api_multiple_authorizers.json index 39eee42e4b..a18e784e79 100644 --- a/tests/translator/output/http_api_multiple_authorizers.json +++ b/tests/translator/output/http_api_multiple_authorizers.json @@ -9,10 +9,7 @@ }, "Handler": "index.restapi", "Role": { - "Fn::GetAtt": [ - "HttpApiFunctionRole", - "Arn" - ] + "Fn::GetAtt": ["HttpApiFunctionRole", "Arn"] }, "Runtime": "python3.7", "Tags": [ @@ -30,14 +27,10 @@ "Version": "2012-10-17", "Statement": [ { - "Action": [ - "sts:AssumeRole" - ], + "Action": ["sts:AssumeRole"], "Effect": "Allow", "Principal": { - "Service": [ - "lambda.amazonaws.com" - ] + "Service": ["lambda.amazonaws.com"] } } ] @@ -83,10 +76,7 @@ }, "Handler": "index.handler", "Role": { - "Fn::GetAtt": [ - "MyAuthFnRole", - "Arn" - ] + "Fn::GetAtt": ["MyAuthFnRole", "Arn"] }, "Runtime": "nodejs12.x", "Tags": [ @@ -104,14 +94,10 @@ "Version": "2012-10-17", "Statement": [ { - "Action": [ - "sts:AssumeRole" - ], + "Action": ["sts:AssumeRole"], "Effect": "Allow", "Principal": { - "Service": [ - "lambda.amazonaws.com" - ] + "Service": ["lambda.amazonaws.com"] } } ] @@ -168,9 +154,7 @@ "responses": {}, "security": [ { - "MyOauth2Authorizer": [ - "scope" - ] + "MyOauth2Authorizer": ["scope"] } ] }, @@ -191,6 +175,24 @@ ] } }, + "/hello-aws-iam-auth": { + "get": { + "x-amazon-apigateway-integration": { + "type": "aws_proxy", + "httpMethod": "POST", + "payloadFormatVersion": "2.0", + "uri": { + "Fn::Sub": "arn:${AWS::Partition}:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${HttpApiFunction.Arn}/invocations" + } + }, + "responses": {}, + "security": [ + { + "AWS_IAM": [] + } + ] + } + }, "$default": { "x-amazon-apigateway-any-method": { "x-amazon-apigateway-integration": { @@ -213,6 +215,12 @@ }, "components": { "securitySchemes": { + "AWS_IAM": { + "type": "apiKey", + "name": "Authorization", + "in": "header", + "x-amazon-apigateway-authtype": "awsSigv4" + }, "LambdaAuth": { "type": "apiKey", "name": "Unused", @@ -224,10 +232,7 @@ "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${__FunctionArn__}/invocations", { "__FunctionArn__": { - "Fn::GetAtt": [ - "MyAuthFn", - "Arn" - ] + "Fn::GetAtt": ["MyAuthFn", "Arn"] } } ] @@ -239,10 +244,7 @@ "type": "oauth2", "x-amazon-apigateway-authorizer": { "jwtConfiguration": { - "audience": [ - "audience1", - "audience2" - ], + "audience": ["audience1", "audience2"], "issuer": "https://www.example.com/v1/connect/oidc" }, "identitySource": "$request.header.Authorization", @@ -284,4 +286,4 @@ } } } -} \ No newline at end of file +} diff --git a/tests/translator/test_translator.py b/tests/translator/test_translator.py index afb2eb47e3..054df8d22b 100644 --- a/tests/translator/test_translator.py +++ b/tests/translator/test_translator.py @@ -515,10 +515,15 @@ def test_transform_success(self, testcase, partition_with_region): "http_api_explicit_stage", "http_api_def_uri", "explicit_http_api", + "http_api_custom_iam_auth", "http_api_with_cors", "http_api_description", + "http_api_global_iam_auth_enabled_with_existing_conflicting_authorizer", + "http_api_global_iam_auth_enabled", "http_api_lambda_auth", "http_api_lambda_auth_full", + "http_api_local_iam_auth_enabled_with_existing_conflicting_authorizer", + "http_api_local_iam_auth_enabled", "http_api_multiple_authorizers", ], [