diff --git a/.cfnlintrc.yaml b/.cfnlintrc.yaml index 67cdeeac3..23172d076 100644 --- a/.cfnlintrc.yaml +++ b/.cfnlintrc.yaml @@ -1,9 +1,6 @@ templates: - tests/translator/output/**/*.json ignore_templates: - - tests/translator/output/**/function_with_function_url_config.json - - tests/translator/output/**/function_with_function_url_config_and_autopublishalias.json - - tests/translator/output/**/function_with_function_url_config_without_cors_config.json - tests/translator/output/**/error_*.json # Fail by design - tests/translator/output/**/api_http_paths_with_if_condition.json - tests/translator/output/**/api_http_paths_with_if_condition_no_value_else_case.json diff --git a/integration/resources/expected/single/basic_function_with_function_url_dual_auth.json b/integration/resources/expected/single/basic_function_with_function_url_dual_auth.json deleted file mode 100644 index e1132a952..000000000 --- a/integration/resources/expected/single/basic_function_with_function_url_dual_auth.json +++ /dev/null @@ -1,22 +0,0 @@ -[ - { - "LogicalResourceId": "MyLambdaFunction", - "ResourceType": "AWS::Lambda::Function" - }, - { - "LogicalResourceId": "MyLambdaFunctionUrl", - "ResourceType": "AWS::Lambda::Url" - }, - { - "LogicalResourceId": "MyLambdaFunctionUrlPublicPermissions", - "ResourceType": "AWS::Lambda::Permission" - }, - { - "LogicalResourceId": "MyLambdaFunctionURLInvokeAllowPublicAccess", - "ResourceType": "AWS::Lambda::Permission" - }, - { - "LogicalResourceId": "MyLambdaFunctionRole", - "ResourceType": "AWS::IAM::Role" - } -] diff --git a/integration/resources/expected/single/basic_function_with_function_url_with_autopuplishalias_dual_auth.json b/integration/resources/expected/single/basic_function_with_function_url_with_autopuplishalias_dual_auth.json deleted file mode 100644 index fef523859..000000000 --- a/integration/resources/expected/single/basic_function_with_function_url_with_autopuplishalias_dual_auth.json +++ /dev/null @@ -1,30 +0,0 @@ -[ - { - "LogicalResourceId": "MyLambdaFunction", - "ResourceType": "AWS::Lambda::Function" - }, - { - "LogicalResourceId": "MyLambdaFunctionRole", - "ResourceType": "AWS::IAM::Role" - }, - { - "LogicalResourceId": "MyLambdaFunctionVersion", - "ResourceType": "AWS::Lambda::Version" - }, - { - "LogicalResourceId": "MyLambdaFunctionAliaslive", - "ResourceType": "AWS::Lambda::Alias" - }, - { - "LogicalResourceId": "MyLambdaFunctionUrlPublicPermissions", - "ResourceType": "AWS::Lambda::Permission" - }, - { - "LogicalResourceId": "MyLambdaFunctionURLInvokeAllowPublicAccess", - "ResourceType": "AWS::Lambda::Permission" - }, - { - "LogicalResourceId": "MyLambdaFunctionUrl", - "ResourceType": "AWS::Lambda::Url" - } -] diff --git a/integration/resources/templates/single/basic_function_with_function_url_dual_auth.yaml b/integration/resources/templates/single/basic_function_with_function_url_dual_auth.yaml deleted file mode 100644 index 4274a3947..000000000 --- a/integration/resources/templates/single/basic_function_with_function_url_dual_auth.yaml +++ /dev/null @@ -1,27 +0,0 @@ -Resources: - MyLambdaFunction: - Type: AWS::Serverless::Function - Properties: - Handler: index.handler - Runtime: nodejs18.x - CodeUri: ${codeuri} - MemorySize: 128 - FunctionUrlConfig: - AuthType: NONE - Cors: - AllowOrigins: - - https://foo.com - AllowMethods: - - POST - AllowCredentials: true - AllowHeaders: - - x-Custom-Header - ExposeHeaders: - - x-amzn-header - MaxAge: 10 -Outputs: - FunctionUrl: - Description: URL of the Lambda function - Value: !GetAtt MyLambdaFunctionUrl.FunctionUrl -Metadata: - SamTransformTest: true diff --git a/integration/resources/templates/single/basic_function_with_function_url_with_autopuplishalias_dual_auth.yaml b/integration/resources/templates/single/basic_function_with_function_url_with_autopuplishalias_dual_auth.yaml deleted file mode 100644 index c78bbb3e3..000000000 --- a/integration/resources/templates/single/basic_function_with_function_url_with_autopuplishalias_dual_auth.yaml +++ /dev/null @@ -1,28 +0,0 @@ -Resources: - MyLambdaFunction: - Type: AWS::Serverless::Function - Properties: - Handler: index.handler - Runtime: nodejs18.x - CodeUri: ${codeuri} - MemorySize: 128 - AutoPublishAlias: live - FunctionUrlConfig: - AuthType: NONE - Cors: - AllowOrigins: - - https://foo.com - AllowMethods: - - POST - AllowCredentials: true - AllowHeaders: - - x-Custom-Header - ExposeHeaders: - - x-amzn-header - MaxAge: 10 -Outputs: - FunctionUrl: - Description: URL of the Lambda function alias - Value: !GetAtt MyLambdaFunctionUrl.FunctionUrl -Metadata: - SamTransformTest: true diff --git a/integration/single/test_basic_function.py b/integration/single/test_basic_function.py index ee00524ab..5678130c6 100644 --- a/integration/single/test_basic_function.py +++ b/integration/single/test_basic_function.py @@ -130,73 +130,6 @@ def test_basic_function_with_url_config(self, file_name, qualifier): self.assertEqual(function_url_config["Cors"], cors_config) self._assert_invoke(lambda_client, function_name, qualifier, 200) - @parameterized.expand( - [ - ("single/basic_function_with_function_url_dual_auth", None), - ("single/basic_function_with_function_url_with_autopuplishalias_dual_auth", "live"), - ] - ) - @skipIf(current_region_does_not_support([LAMBDA_URL]), "Lambda Url is not supported in this testing region") - def test_basic_function_with_url_dual_auth(self, file_name, qualifier): - """ - Creates a basic lambda function with Function Url with authtype: None - Verifies that 2 AWS::Lambda::Permission resources are created: - - lambda:InvokeFunctionUrl - - lambda:InvokeFunction with InvokedViaFunctionUrl: True - """ - self.create_and_verify_stack(file_name) - - # Get Lambda permissions - lambda_permissions = self.get_stack_resources("AWS::Lambda::Permission") - - # Verify we have exactly 2 permissions - self.assertEqual(len(lambda_permissions), 2, "Expected exactly 2 Lambda permissions") - - # Check for the expected permission logical IDs - invoke_function_url_permission = None - invoke_permission = None - - for permission in lambda_permissions: - logical_id = permission["LogicalResourceId"] - if "MyLambdaFunctionUrlPublicPermissions" in logical_id: - invoke_function_url_permission = permission - elif "MyLambdaFunctionURLInvokeAllowPublicAccess" in logical_id: - invoke_permission = permission - - # Verify both permissions exist - self.assertIsNotNone(invoke_function_url_permission, "Expected MyLambdaFunctionUrlPublicPermissions to exist") - self.assertIsNotNone(invoke_permission, "Expected MyLambdaFunctionURLInvokeAllowPublicAccess to exist") - - # Get the function name and URL - function_name = self.get_physical_id_by_type("AWS::Lambda::Function") - lambda_client = self.client_provider.lambda_client - - # Get the function URL configuration to verify auth type - function_url_config = ( - lambda_client.get_function_url_config(FunctionName=function_name, Qualifier=qualifier) - if qualifier - else lambda_client.get_function_url_config(FunctionName=function_name) - ) - - # Verify the auth type is NONE - self.assertEqual(function_url_config["AuthType"], "NONE", "Expected AuthType to be NONE") - - # Get the template to check for InvokedViaFunctionUrl property - cfn_client = self.client_provider.cfn_client - template = cfn_client.get_template(StackName=self.stack_name, TemplateStage="Processed") - template_body = template["TemplateBody"] - - # Check if the InvokePermission has InvokedViaFunctionUrl: True - # This is a bit hacky but we don't have direct access to the resource properties - # We're checking if the string representation of the template contains this property - template_str = str(template_body) - self.assertIn("InvokedViaFunctionUrl", template_str, "Expected InvokedViaFunctionUrl property in the template") - - # Get the function URL from stack outputs - function_url = self.get_stack_output("FunctionUrl")["OutputValue"] - # Invoke the function URL and verify the response - self._verify_get_request(function_url, self.FUNCTION_OUTPUT) - @skipIf(current_region_does_not_support([CODE_DEPLOY]), "CodeDeploy is not supported in this testing region") def test_function_with_deployment_preference_alarms_intrinsic_if(self): self.create_and_verify_stack("single/function_with_deployment_preference_alarms_intrinsic_if") diff --git a/samtranslator/model/lambda_.py b/samtranslator/model/lambda_.py index c6fecd242..27e9636ed 100644 --- a/samtranslator/model/lambda_.py +++ b/samtranslator/model/lambda_.py @@ -139,7 +139,6 @@ class LambdaPermission(Resource): "SourceArn": GeneratedProperty(), "EventSourceToken": GeneratedProperty(), "FunctionUrlAuthType": GeneratedProperty(), - "InvokedViaFunctionUrl": GeneratedProperty(), } diff --git a/samtranslator/model/sam_resources.py b/samtranslator/model/sam_resources.py index 70e7ef675..2cdbc3c8b 100644 --- a/samtranslator/model/sam_resources.py +++ b/samtranslator/model/sam_resources.py @@ -321,12 +321,8 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] # noqa: P lambda_url = self._construct_function_url(lambda_function, lambda_alias, self.FunctionUrlConfig) resources.append(lambda_url) url_permission = self._construct_url_permission(lambda_function, lambda_alias, self.FunctionUrlConfig) - invoke_dual_auth_permission = self._construct_invoke_permission( - lambda_function, lambda_alias, self.FunctionUrlConfig - ) - if url_permission and invoke_dual_auth_permission: + if url_permission: resources.append(url_permission) - resources.append(invoke_dual_auth_permission) self._validate_deployment_preference_and_add_update_policy( kwargs.get("deployment_preference_collection"), @@ -336,6 +332,7 @@ def to_cloudformation(self, **kwargs): # type: ignore[no-untyped-def] # noqa: P self.get_passthrough_resource_attributes(), feature_toggle, ) + event_invoke_policies: List[Dict[str, Any]] = [] if self.EventInvokeConfig: function_name = lambda_function.logical_id @@ -1228,13 +1225,9 @@ def _construct_url_permission( lambda_function : LambdaUrl Lambda Function resource - lambda_alias : LambdaAlias + llambda_alias : LambdaAlias Lambda Alias resource - - function_url_config: Dict - Function url config used to create FURL - Returns ------- LambdaPermission @@ -1256,47 +1249,6 @@ def _construct_url_permission( lambda_permission.FunctionUrlAuthType = auth_type return lambda_permission - def _construct_invoke_permission( - self, lambda_function: LambdaFunction, lambda_alias: Optional[LambdaAlias], function_url_config: Dict[str, Any] - ) -> Optional[LambdaPermission]: - """ - Construct the lambda permission associated with the function invoke resource in a case - for public access when AuthType is NONE - - Parameters - ---------- - lambda_function : LambdaUrl - Lambda Function resource - - lambda_alias : LambdaAlias - Lambda Alias resource - - function_url_config: Dict - Function url config used to create FURL - - Returns - ------- - LambdaPermission - The lambda permission appended to a function that allow function invoke only from Function URL - """ - # create lambda:InvokeFunction with InvokedViaFunctionUrl=True - auth_type = function_url_config.get("AuthType") - - if auth_type not in ["NONE"] or is_intrinsic(function_url_config): - return None - - logical_id = f"{lambda_function.logical_id}URLInvokeAllowPublicAccess" - lambda_permission_attributes = self.get_passthrough_resource_attributes() - lambda_invoke_permission = LambdaPermission(logical_id=logical_id, attributes=lambda_permission_attributes) - lambda_invoke_permission.Action = "lambda:InvokeFunction" - lambda_invoke_permission.Principal = "*" - lambda_invoke_permission.FunctionName = ( - lambda_alias.get_runtime_attr("arn") if lambda_alias else lambda_function.get_runtime_attr("name") - ) - lambda_invoke_permission.InvokedViaFunctionUrl = True - - return lambda_invoke_permission - class SamApi(SamResourceMacro): """SAM rest API macro.""" diff --git a/tests/model/test_sam_resources.py b/tests/model/test_sam_resources.py index b53649f10..9b6c28908 100644 --- a/tests/model/test_sam_resources.py +++ b/tests/model/test_sam_resources.py @@ -583,29 +583,11 @@ def test_with_valid_function_url_config_with_lambda_permission(self): cfnResources = function.to_cloudformation(**self.kwargs) generatedUrlList = [x for x in cfnResources if isinstance(x, LambdaPermission)] - self.assertEqual(generatedUrlList.__len__(), 2) - for permission in generatedUrlList: - self.assertEqual(permission.FunctionName, {"Ref": "foo"}) - self.assertEqual(permission.Principal, "*") - self.assertTrue(permission.Action in ["lambda:InvokeFunctionUrl", "lambda:InvokeFunction"]) - if permission.Action == "lambda:InvokeFunctionUrl": - self.assertEqual(permission.FunctionUrlAuthType, "NONE") - if permission.Action == "lambda:InvokeFunction": - self.assertEqual(permission.InvokedViaFunctionUrl, True) - - @patch("boto3.session.Session.region_name", "ap-southeast-1") - def test_with_aws_iam_function_url_config_with_lambda_permission(self): - function = SamFunction("foo") - function.CodeUri = "s3://foobar/foo.zip" - function.Runtime = "foo" - function.Handler = "bar" - # When create FURL with AWS_IAM - function.FunctionUrlConfig = {"AuthType": "AWS_IAM"} - - cfnResources = function.to_cloudformation(**self.kwargs) - generatedUrlList = [x for x in cfnResources if isinstance(x, LambdaPermission)] - # Then no permisssion should be auto created - self.assertEqual(generatedUrlList.__len__(), 0) + self.assertEqual(generatedUrlList.__len__(), 1) + self.assertEqual(generatedUrlList[0].Action, "lambda:InvokeFunctionUrl") + self.assertEqual(generatedUrlList[0].FunctionName, {"Ref": "foo"}) + self.assertEqual(generatedUrlList[0].Principal, "*") + self.assertEqual(generatedUrlList[0].FunctionUrlAuthType, "NONE") @patch("boto3.session.Session.region_name", "ap-southeast-1") def test_with_invalid_function_url_config_with_authorization_type_value_as_None(self): diff --git a/tests/translator/output/aws-cn/function_with_function_url_config.json b/tests/translator/output/aws-cn/function_with_function_url_config.json index bd007a362..7404f943e 100644 --- a/tests/translator/output/aws-cn/function_with_function_url_config.json +++ b/tests/translator/output/aws-cn/function_with_function_url_config.json @@ -58,17 +58,6 @@ }, "Type": "AWS::IAM::Role" }, - "MyFunctionURLInvokeAllowPublicAccess": { - "Properties": { - "Action": "lambda:InvokeFunction", - "FunctionName": { - "Ref": "MyFunction" - }, - "InvokedViaFunctionUrl": true, - "Principal": "*" - }, - "Type": "AWS::Lambda::Permission" - }, "MyFunctionUrl": { "Properties": { "AuthType": "NONE", diff --git a/tests/translator/output/aws-cn/function_with_function_url_config_and_autopublishalias.json b/tests/translator/output/aws-cn/function_with_function_url_config_and_autopublishalias.json index e648b9460..b12e0271c 100644 --- a/tests/translator/output/aws-cn/function_with_function_url_config_and_autopublishalias.json +++ b/tests/translator/output/aws-cn/function_with_function_url_config_and_autopublishalias.json @@ -73,17 +73,6 @@ }, "Type": "AWS::IAM::Role" }, - "MyFunctionURLInvokeAllowPublicAccess": { - "Properties": { - "Action": "lambda:InvokeFunction", - "FunctionName": { - "Ref": "MyFunctionAliaslive" - }, - "InvokedViaFunctionUrl": true, - "Principal": "*" - }, - "Type": "AWS::Lambda::Permission" - }, "MyFunctionUrl": { "Properties": { "AuthType": "NONE", diff --git a/tests/translator/output/aws-cn/function_with_function_url_config_conditions.json b/tests/translator/output/aws-cn/function_with_function_url_config_conditions.json index 3f2fcbda6..5cb30218d 100644 --- a/tests/translator/output/aws-cn/function_with_function_url_config_conditions.json +++ b/tests/translator/output/aws-cn/function_with_function_url_config_conditions.json @@ -68,18 +68,6 @@ }, "Type": "AWS::IAM::Role" }, - "MyFunctionURLInvokeAllowPublicAccess": { - "Condition": "MyCondition", - "Properties": { - "Action": "lambda:InvokeFunction", - "FunctionName": { - "Ref": "MyFunction" - }, - "InvokedViaFunctionUrl": true, - "Principal": "*" - }, - "Type": "AWS::Lambda::Permission" - }, "MyFunctionUrl": { "Condition": "MyCondition", "Properties": { diff --git a/tests/translator/output/aws-cn/function_with_function_url_config_without_cors_config.json b/tests/translator/output/aws-cn/function_with_function_url_config_without_cors_config.json index 11393799b..b20af083f 100644 --- a/tests/translator/output/aws-cn/function_with_function_url_config_without_cors_config.json +++ b/tests/translator/output/aws-cn/function_with_function_url_config_without_cors_config.json @@ -58,17 +58,6 @@ }, "Type": "AWS::IAM::Role" }, - "MyFunctionURLInvokeAllowPublicAccess": { - "Properties": { - "Action": "lambda:InvokeFunction", - "FunctionName": { - "Ref": "MyFunction" - }, - "InvokedViaFunctionUrl": true, - "Principal": "*" - }, - "Type": "AWS::Lambda::Permission" - }, "MyFunctionUrl": { "Properties": { "AuthType": "NONE", diff --git a/tests/translator/output/aws-us-gov/function_with_function_url_config.json b/tests/translator/output/aws-us-gov/function_with_function_url_config.json index 717276ba4..2d04a4c32 100644 --- a/tests/translator/output/aws-us-gov/function_with_function_url_config.json +++ b/tests/translator/output/aws-us-gov/function_with_function_url_config.json @@ -58,17 +58,6 @@ }, "Type": "AWS::IAM::Role" }, - "MyFunctionURLInvokeAllowPublicAccess": { - "Properties": { - "Action": "lambda:InvokeFunction", - "FunctionName": { - "Ref": "MyFunction" - }, - "InvokedViaFunctionUrl": true, - "Principal": "*" - }, - "Type": "AWS::Lambda::Permission" - }, "MyFunctionUrl": { "Properties": { "AuthType": "NONE", diff --git a/tests/translator/output/aws-us-gov/function_with_function_url_config_and_autopublishalias.json b/tests/translator/output/aws-us-gov/function_with_function_url_config_and_autopublishalias.json index ab22babe3..5d558e29e 100644 --- a/tests/translator/output/aws-us-gov/function_with_function_url_config_and_autopublishalias.json +++ b/tests/translator/output/aws-us-gov/function_with_function_url_config_and_autopublishalias.json @@ -73,17 +73,6 @@ }, "Type": "AWS::IAM::Role" }, - "MyFunctionURLInvokeAllowPublicAccess": { - "Properties": { - "Action": "lambda:InvokeFunction", - "FunctionName": { - "Ref": "MyFunctionAliaslive" - }, - "InvokedViaFunctionUrl": true, - "Principal": "*" - }, - "Type": "AWS::Lambda::Permission" - }, "MyFunctionUrl": { "Properties": { "AuthType": "NONE", diff --git a/tests/translator/output/aws-us-gov/function_with_function_url_config_conditions.json b/tests/translator/output/aws-us-gov/function_with_function_url_config_conditions.json index 98bd4aeda..e2763bcd9 100644 --- a/tests/translator/output/aws-us-gov/function_with_function_url_config_conditions.json +++ b/tests/translator/output/aws-us-gov/function_with_function_url_config_conditions.json @@ -68,18 +68,6 @@ }, "Type": "AWS::IAM::Role" }, - "MyFunctionURLInvokeAllowPublicAccess": { - "Condition": "MyCondition", - "Properties": { - "Action": "lambda:InvokeFunction", - "FunctionName": { - "Ref": "MyFunction" - }, - "InvokedViaFunctionUrl": true, - "Principal": "*" - }, - "Type": "AWS::Lambda::Permission" - }, "MyFunctionUrl": { "Condition": "MyCondition", "Properties": { diff --git a/tests/translator/output/aws-us-gov/function_with_function_url_config_without_cors_config.json b/tests/translator/output/aws-us-gov/function_with_function_url_config_without_cors_config.json index 34e72dd45..c274150d6 100644 --- a/tests/translator/output/aws-us-gov/function_with_function_url_config_without_cors_config.json +++ b/tests/translator/output/aws-us-gov/function_with_function_url_config_without_cors_config.json @@ -58,17 +58,6 @@ }, "Type": "AWS::IAM::Role" }, - "MyFunctionURLInvokeAllowPublicAccess": { - "Properties": { - "Action": "lambda:InvokeFunction", - "FunctionName": { - "Ref": "MyFunction" - }, - "InvokedViaFunctionUrl": true, - "Principal": "*" - }, - "Type": "AWS::Lambda::Permission" - }, "MyFunctionUrl": { "Properties": { "AuthType": "NONE", diff --git a/tests/translator/output/function_with_function_url_config.json b/tests/translator/output/function_with_function_url_config.json index f8470b199..a185781cb 100644 --- a/tests/translator/output/function_with_function_url_config.json +++ b/tests/translator/output/function_with_function_url_config.json @@ -58,17 +58,6 @@ }, "Type": "AWS::IAM::Role" }, - "MyFunctionURLInvokeAllowPublicAccess": { - "Properties": { - "Action": "lambda:InvokeFunction", - "FunctionName": { - "Ref": "MyFunction" - }, - "InvokedViaFunctionUrl": true, - "Principal": "*" - }, - "Type": "AWS::Lambda::Permission" - }, "MyFunctionUrl": { "Properties": { "AuthType": "NONE", diff --git a/tests/translator/output/function_with_function_url_config_and_autopublishalias.json b/tests/translator/output/function_with_function_url_config_and_autopublishalias.json index 29f8dd5b4..d62e34565 100644 --- a/tests/translator/output/function_with_function_url_config_and_autopublishalias.json +++ b/tests/translator/output/function_with_function_url_config_and_autopublishalias.json @@ -73,17 +73,6 @@ }, "Type": "AWS::IAM::Role" }, - "MyFunctionURLInvokeAllowPublicAccess": { - "Properties": { - "Action": "lambda:InvokeFunction", - "FunctionName": { - "Ref": "MyFunctionAliaslive" - }, - "InvokedViaFunctionUrl": true, - "Principal": "*" - }, - "Type": "AWS::Lambda::Permission" - }, "MyFunctionUrl": { "Properties": { "AuthType": "NONE", diff --git a/tests/translator/output/function_with_function_url_config_conditions.json b/tests/translator/output/function_with_function_url_config_conditions.json index 736511c8b..94cc22817 100644 --- a/tests/translator/output/function_with_function_url_config_conditions.json +++ b/tests/translator/output/function_with_function_url_config_conditions.json @@ -68,18 +68,6 @@ }, "Type": "AWS::IAM::Role" }, - "MyFunctionURLInvokeAllowPublicAccess": { - "Condition": "MyCondition", - "Properties": { - "Action": "lambda:InvokeFunction", - "FunctionName": { - "Ref": "MyFunction" - }, - "InvokedViaFunctionUrl": true, - "Principal": "*" - }, - "Type": "AWS::Lambda::Permission" - }, "MyFunctionUrl": { "Condition": "MyCondition", "Properties": { diff --git a/tests/translator/output/function_with_function_url_config_without_cors_config.json b/tests/translator/output/function_with_function_url_config_without_cors_config.json index 4f1a321b7..07520fa01 100644 --- a/tests/translator/output/function_with_function_url_config_without_cors_config.json +++ b/tests/translator/output/function_with_function_url_config_without_cors_config.json @@ -58,17 +58,6 @@ }, "Type": "AWS::IAM::Role" }, - "MyFunctionURLInvokeAllowPublicAccess": { - "Properties": { - "Action": "lambda:InvokeFunction", - "FunctionName": { - "Ref": "MyFunction" - }, - "InvokedViaFunctionUrl": true, - "Principal": "*" - }, - "Type": "AWS::Lambda::Permission" - }, "MyFunctionUrl": { "Properties": { "AuthType": "NONE",