diff --git a/prowler/providers/aws/services/awslambda/awslambda_function_inside_vpc/awslambda_function_inside_vpc.metadata.json b/prowler/providers/aws/services/awslambda/awslambda_function_inside_vpc/awslambda_function_inside_vpc.metadata.json index ed9b02372e..b25df32ee0 100644 --- a/prowler/providers/aws/services/awslambda/awslambda_function_inside_vpc/awslambda_function_inside_vpc.metadata.json +++ b/prowler/providers/aws/services/awslambda/awslambda_function_inside_vpc/awslambda_function_inside_vpc.metadata.json @@ -3,7 +3,7 @@ "CheckID": "awslambda_function_inside_vpc", "CheckTitle": "Ensure AWS Lambda Functions Are Deployed Inside a VPC", "CheckType": [], - "ServiceName": "lambda", + "ServiceName": "awslambda", "SubServiceName": "", "ResourceIdTemplate": "arn:partition:lambda:region:account-id:function/function-name", "Severity": "low", diff --git a/prowler/providers/aws/services/awslambda/awslambda_function_invoke_api_operations_cloudtrail_logging_enabled/awslambda_function_invoke_api_operations_cloudtrail_logging_enabled.metadata.json b/prowler/providers/aws/services/awslambda/awslambda_function_invoke_api_operations_cloudtrail_logging_enabled/awslambda_function_invoke_api_operations_cloudtrail_logging_enabled.metadata.json index 1782488f9c..4354b042c3 100644 --- a/prowler/providers/aws/services/awslambda/awslambda_function_invoke_api_operations_cloudtrail_logging_enabled/awslambda_function_invoke_api_operations_cloudtrail_logging_enabled.metadata.json +++ b/prowler/providers/aws/services/awslambda/awslambda_function_invoke_api_operations_cloudtrail_logging_enabled/awslambda_function_invoke_api_operations_cloudtrail_logging_enabled.metadata.json @@ -3,7 +3,7 @@ "CheckID": "awslambda_function_invoke_api_operations_cloudtrail_logging_enabled", "CheckTitle": "Check if Lambda functions invoke API operations are being recorded by CloudTrail.", "CheckType": [], - "ServiceName": "lambda", + "ServiceName": "awslambda", "SubServiceName": "", "ResourceIdTemplate": "arn:partition:lambda:region:account-id:function/function-name", "Severity": "low", diff --git a/prowler/providers/aws/services/awslambda/awslambda_function_no_secrets_in_code/awslambda_function_no_secrets_in_code.metadata.json b/prowler/providers/aws/services/awslambda/awslambda_function_no_secrets_in_code/awslambda_function_no_secrets_in_code.metadata.json index 4fd1e9dc57..43cb61491d 100644 --- a/prowler/providers/aws/services/awslambda/awslambda_function_no_secrets_in_code/awslambda_function_no_secrets_in_code.metadata.json +++ b/prowler/providers/aws/services/awslambda/awslambda_function_no_secrets_in_code/awslambda_function_no_secrets_in_code.metadata.json @@ -3,7 +3,7 @@ "CheckID": "awslambda_function_no_secrets_in_code", "CheckTitle": "Find secrets in Lambda functions code.", "CheckType": [], - "ServiceName": "lambda", + "ServiceName": "awslambda", "SubServiceName": "", "ResourceIdTemplate": "arn:partition:lambda:region:account-id:function/function-name", "Severity": "critical", diff --git a/prowler/providers/aws/services/awslambda/awslambda_function_no_secrets_in_variables/awslambda_function_no_secrets_in_variables.metadata.json b/prowler/providers/aws/services/awslambda/awslambda_function_no_secrets_in_variables/awslambda_function_no_secrets_in_variables.metadata.json index 39365275f1..640d977fea 100644 --- a/prowler/providers/aws/services/awslambda/awslambda_function_no_secrets_in_variables/awslambda_function_no_secrets_in_variables.metadata.json +++ b/prowler/providers/aws/services/awslambda/awslambda_function_no_secrets_in_variables/awslambda_function_no_secrets_in_variables.metadata.json @@ -3,7 +3,7 @@ "CheckID": "awslambda_function_no_secrets_in_variables", "CheckTitle": "Find secrets in Lambda functions variables.", "CheckType": [], - "ServiceName": "lambda", + "ServiceName": "awslambda", "SubServiceName": "", "ResourceIdTemplate": "arn:partition:lambda:region:account-id:function/function-name", "Severity": "critical", diff --git a/prowler/providers/aws/services/awslambda/awslambda_function_not_publicly_accessible/awslambda_function_not_publicly_accessible.metadata.json b/prowler/providers/aws/services/awslambda/awslambda_function_not_publicly_accessible/awslambda_function_not_publicly_accessible.metadata.json index 8bff12f44d..874d8aca1a 100644 --- a/prowler/providers/aws/services/awslambda/awslambda_function_not_publicly_accessible/awslambda_function_not_publicly_accessible.metadata.json +++ b/prowler/providers/aws/services/awslambda/awslambda_function_not_publicly_accessible/awslambda_function_not_publicly_accessible.metadata.json @@ -3,7 +3,7 @@ "CheckID": "awslambda_function_not_publicly_accessible", "CheckTitle": "Check if Lambda functions have resource-based policy set as Public.", "CheckType": [], - "ServiceName": "lambda", + "ServiceName": "awslambda", "SubServiceName": "", "ResourceIdTemplate": "arn:partition:lambda:region:account-id:function/function-name", "Severity": "critical", diff --git a/prowler/providers/aws/services/awslambda/awslambda_function_not_publicly_accessible/awslambda_function_not_publicly_accessible_fixer.py b/prowler/providers/aws/services/awslambda/awslambda_function_not_publicly_accessible/awslambda_function_not_publicly_accessible_fixer.py new file mode 100644 index 0000000000..3a74fb17d6 --- /dev/null +++ b/prowler/providers/aws/services/awslambda/awslambda_function_not_publicly_accessible/awslambda_function_not_publicly_accessible_fixer.py @@ -0,0 +1,61 @@ +import json + +from prowler.lib.logger import logger +from prowler.providers.aws.services.awslambda.awslambda_client import awslambda_client + + +def fixer(resource_id: str, region: str) -> bool: + """ + Remove the Lambda function's resource-based policy to prevent public access and add a new permission for the account. + Specifically, this fixer deletes all permission statements associated with the Lambda function's policy and then adds a new permission. + Requires the lambda:RemovePermission and lambda:AddPermission permissions. + Permissions: + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "lambda:RemovePermission", + "Resource": "*" + }, + { + "Effect": "Allow", + "Action": "lambda:AddPermission", + "Resource": "*" + } + ] + } + Args: + resource_id (str): The Lambda function name or ARN. + region (str): AWS region where the Lambda function exists. + Returns: + bool: True if the operation is successful (policy removed and permission added), False otherwise. + """ + try: + account_id = awslambda_client.audited_account + + regional_client = awslambda_client.regional_clients[region] + policy_response = regional_client.get_policy(FunctionName=resource_id) + policy = json.loads(policy_response.get("Policy")) + + for statement in policy.get("Statement", []): + statement_id = statement.get("Sid") + if statement_id: + regional_client.remove_permission( + FunctionName=resource_id, StatementId=statement_id + ) + + regional_client.add_permission( + FunctionName=resource_id, + StatementId="ProwlerFixerStatement", + Principal=account_id, + Action="lambda:InvokeFunction", + ) + + except Exception as error: + logger.error( + f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return False + else: + return True diff --git a/prowler/providers/aws/services/awslambda/awslambda_function_url_cors_policy/awslambda_function_url_cors_policy.metadata.json b/prowler/providers/aws/services/awslambda/awslambda_function_url_cors_policy/awslambda_function_url_cors_policy.metadata.json index 582aed2f9d..77d0d0fa19 100644 --- a/prowler/providers/aws/services/awslambda/awslambda_function_url_cors_policy/awslambda_function_url_cors_policy.metadata.json +++ b/prowler/providers/aws/services/awslambda/awslambda_function_url_cors_policy/awslambda_function_url_cors_policy.metadata.json @@ -3,7 +3,7 @@ "CheckID": "awslambda_function_url_cors_policy", "CheckTitle": "Check Lambda Function URL CORS configuration.", "CheckType": [], - "ServiceName": "lambda", + "ServiceName": "awslambda", "SubServiceName": "", "ResourceIdTemplate": "arn:partition:lambda:region:account-id:function/function-name", "Severity": "medium", diff --git a/prowler/providers/aws/services/awslambda/awslambda_function_url_public/awslambda_function_url_public.metadata.json b/prowler/providers/aws/services/awslambda/awslambda_function_url_public/awslambda_function_url_public.metadata.json index 3e7f1a2eac..74fa75f1f7 100644 --- a/prowler/providers/aws/services/awslambda/awslambda_function_url_public/awslambda_function_url_public.metadata.json +++ b/prowler/providers/aws/services/awslambda/awslambda_function_url_public/awslambda_function_url_public.metadata.json @@ -3,7 +3,7 @@ "CheckID": "awslambda_function_url_public", "CheckTitle": "Check Public Lambda Function URL.", "CheckType": [], - "ServiceName": "lambda", + "ServiceName": "awslambda", "SubServiceName": "", "ResourceIdTemplate": "arn:partition:lambda:region:account-id:function/function-name", "Severity": "high", diff --git a/prowler/providers/aws/services/awslambda/awslambda_function_using_supported_runtimes/awslambda_function_using_supported_runtimes.metadata.json b/prowler/providers/aws/services/awslambda/awslambda_function_using_supported_runtimes/awslambda_function_using_supported_runtimes.metadata.json index b8a1c5a013..a3048e5b9e 100644 --- a/prowler/providers/aws/services/awslambda/awslambda_function_using_supported_runtimes/awslambda_function_using_supported_runtimes.metadata.json +++ b/prowler/providers/aws/services/awslambda/awslambda_function_using_supported_runtimes/awslambda_function_using_supported_runtimes.metadata.json @@ -3,7 +3,7 @@ "CheckID": "awslambda_function_using_supported_runtimes", "CheckTitle": "Find obsolete Lambda runtimes.", "CheckType": [], - "ServiceName": "lambda", + "ServiceName": "awslambda", "SubServiceName": "", "ResourceIdTemplate": "arn:partition:lambda:region:account-id:function/function-name", "Severity": "medium", diff --git a/prowler/providers/aws/services/awslambda/awslambda_function_vpc_multi_az/awslambda_function_vpc_multi_az.metadata.json b/prowler/providers/aws/services/awslambda/awslambda_function_vpc_multi_az/awslambda_function_vpc_multi_az.metadata.json index 312023e4da..6c6cfff74e 100644 --- a/prowler/providers/aws/services/awslambda/awslambda_function_vpc_multi_az/awslambda_function_vpc_multi_az.metadata.json +++ b/prowler/providers/aws/services/awslambda/awslambda_function_vpc_multi_az/awslambda_function_vpc_multi_az.metadata.json @@ -3,7 +3,7 @@ "CheckID": "awslambda_function_vpc_multi_az", "CheckTitle": "Check if AWS Lambda Function VPC is deployed Across Multiple Availability Zones", "CheckType": [], - "ServiceName": "lambda", + "ServiceName": "awslambda", "SubServiceName": "", "ResourceIdTemplate": "arn:partition:lambda:region:account-id:function/function-name", "Severity": "medium", diff --git a/tests/providers/aws/services/awslambda/awslambda_function_not_publicly_accessible/awslambda_function_not_publicly_accessible_fixer_test.py b/tests/providers/aws/services/awslambda/awslambda_function_not_publicly_accessible/awslambda_function_not_publicly_accessible_fixer_test.py new file mode 100644 index 0000000000..958a77c00e --- /dev/null +++ b/tests/providers/aws/services/awslambda/awslambda_function_not_publicly_accessible/awslambda_function_not_publicly_accessible_fixer_test.py @@ -0,0 +1,268 @@ +from json import dumps +from unittest import mock + +from boto3 import client +from moto import mock_aws + +from tests.providers.aws.utils import ( + AWS_ACCOUNT_NUMBER, + AWS_REGION_EU_WEST_1, + set_mocked_aws_provider, +) + + +class Test_awslambda_function_not_publicly_accessible_fixer: + @mock_aws + def test_function_public(self): + # Create the mock IAM role + iam_client = client("iam", region_name=AWS_REGION_EU_WEST_1) + role_name = "test-role" + assume_role_policy_document = { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": {"Service": "lambda.amazonaws.com"}, + "Action": "sts:AssumeRole", + } + ], + } + role_arn = iam_client.create_role( + RoleName=role_name, + AssumeRolePolicyDocument=dumps(assume_role_policy_document), + )["Role"]["Arn"] + + function_name = "test-lambda" + + # Create the lambda function using boto3 client + lambda_client = client("lambda", region_name=AWS_REGION_EU_WEST_1) + lambda_client.create_function( + FunctionName=function_name, + Runtime="nodejs4.3", + Role=role_arn, + Handler="index.handler", + Code={"ZipFile": b"fileb://file-path/to/your-deployment-package.zip"}, + Description="Test Lambda function", + Timeout=3, + MemorySize=128, + Publish=True, + Tags={"tag1": "value1", "tag2": "value2"}, + )["FunctionArn"] + + # Attach the policy to the lambda function with a wildcard principal + lambda_client.add_permission( + FunctionName=function_name, + StatementId="public-access", + Action="lambda:InvokeFunction", + Principal="*", + ) + + aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) + + from prowler.providers.aws.services.awslambda.awslambda_service import Lambda + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible_fixer.awslambda_client", + new=Lambda(aws_provider), + ): + # Test Fixer + from prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible_fixer import ( + fixer, + ) + + assert fixer(function_name, AWS_REGION_EU_WEST_1) + + @mock_aws + def test_function_public_with_source_account(self): + # Create the mock IAM role + iam_client = client("iam", region_name=AWS_REGION_EU_WEST_1) + role_name = "test-role" + assume_role_policy_document = { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": {"Service": "lambda.amazonaws.com"}, + "Action": "sts:AssumeRole", + } + ], + } + role_arn = iam_client.create_role( + RoleName=role_name, + AssumeRolePolicyDocument=dumps(assume_role_policy_document), + )["Role"]["Arn"] + + function_name = "test-lambda" + + # Create the lambda function using boto3 client + lambda_client = client("lambda", region_name=AWS_REGION_EU_WEST_1) + function_arn = lambda_client.create_function( + FunctionName=function_name, + Runtime="nodejs4.3", + Role=role_arn, + Handler="index.handler", + Code={"ZipFile": b"fileb://file-path/to/your-deployment-package.zip"}, + Description="Test Lambda function", + Timeout=3, + MemorySize=128, + Publish=True, + Tags={"tag1": "value1", "tag2": "value2"}, + )["FunctionArn"] + + # Attach the policy to the lambda function with a wildcard principal + lambda_client.add_permission( + FunctionName=function_name, + StatementId="public-access", + Action="lambda:InvokeFunction", + Principal="*", + SourceArn=function_arn, + SourceAccount=AWS_ACCOUNT_NUMBER, + ) + + aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) + + from prowler.providers.aws.services.awslambda.awslambda_service import Lambda + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible_fixer.awslambda_client", + new=Lambda(aws_provider), + ): + # Test Fixer + from prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible_fixer import ( + fixer, + ) + + assert fixer(function_name, AWS_REGION_EU_WEST_1) + + @mock_aws + def test_function_not_public(self): + # Create the mock IAM role + iam_client = client("iam", region_name=AWS_REGION_EU_WEST_1) + role_name = "test-role" + assume_role_policy_document = { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": {"Service": "lambda.amazonaws.com"}, + "Action": "sts:AssumeRole", + } + ], + } + role_arn = iam_client.create_role( + RoleName=role_name, + AssumeRolePolicyDocument=dumps(assume_role_policy_document), + )["Role"]["Arn"] + + function_name = "test-lambda" + + # Create the lambda function using boto3 client + lambda_client = client("lambda", region_name=AWS_REGION_EU_WEST_1) + function_arn = lambda_client.create_function( + FunctionName=function_name, + Runtime="nodejs4.3", + Role=role_arn, + Handler="index.handler", + Code={"ZipFile": b"fileb://file-path/to/your-deployment-package.zip"}, + Description="Test Lambda function", + Timeout=3, + MemorySize=128, + Publish=True, + Tags={"tag1": "value1", "tag2": "value2"}, + )["FunctionArn"] + + # Attach the policy to the lambda function with a specific AWS account number as principal + lambda_client.add_permission( + FunctionName=function_name, + StatementId="public-access", + Action="lambda:InvokeFunction", + Principal=AWS_ACCOUNT_NUMBER, + SourceArn=function_arn, + ) + + aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) + + from prowler.providers.aws.services.awslambda.awslambda_service import Lambda + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible_fixer.awslambda_client", + new=Lambda(aws_provider), + ): + # Test Fixer + from prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible_fixer import ( + fixer, + ) + + assert fixer(function_name, AWS_REGION_EU_WEST_1) + + @mock_aws + def test_function_public_error(self): + # Create the mock IAM role + iam_client = client("iam", region_name=AWS_REGION_EU_WEST_1) + role_name = "test-role" + assume_role_policy_document = { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": {"Service": "lambda.amazonaws.com"}, + "Action": "sts:AssumeRole", + } + ], + } + role_arn = iam_client.create_role( + RoleName=role_name, + AssumeRolePolicyDocument=dumps(assume_role_policy_document), + )["Role"]["Arn"] + + function_name = "test-lambda" + + # Create the lambda function using boto3 client + lambda_client = client("lambda", region_name=AWS_REGION_EU_WEST_1) + lambda_client.create_function( + FunctionName=function_name, + Runtime="nodejs4.3", + Role=role_arn, + Handler="index.handler", + Code={"ZipFile": b"fileb://file-path/to/your-deployment-package.zip"}, + Description="Test Lambda function", + Timeout=3, + MemorySize=128, + Publish=True, + Tags={"tag1": "value1", "tag2": "value2"}, + )["FunctionArn"] + + # Attach the policy to the lambda function with a wildcard principal + lambda_client.add_permission( + FunctionName=function_name, + StatementId="public-access", + Action="lambda:InvokeFunction", + Principal="*", + ) + + aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) + + from prowler.providers.aws.services.awslambda.awslambda_service import Lambda + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible_fixer.awslambda_client", + new=Lambda(aws_provider), + ): + # Test Fixer + from prowler.providers.aws.services.awslambda.awslambda_function_not_publicly_accessible.awslambda_function_not_publicly_accessible_fixer import ( + fixer, + ) + + assert not fixer("non-exsting", AWS_REGION_EU_WEST_1)