From 00054b5cd90d177bc97fe7c5111a86314bb237ad Mon Sep 17 00:00:00 2001 From: Daniel Barranquero <74871504+danibarranqueroo@users.noreply.github.com> Date: Thu, 21 Nov 2024 17:40:28 +0100 Subject: [PATCH] feat(ec2): add new fixer `ec2_ebs_public_snapshot_fixer` (#5825) Co-authored-by: Sergio Garcia --- .../ec2_ebs_public_snapshot_fixer.py | 41 ++++++++ .../ec2_ebs_public_snapshot_fixer_test.py | 93 +++++++++++++++++++ 2 files changed, 134 insertions(+) create mode 100644 prowler/providers/aws/services/ec2/ec2_ebs_public_snapshot/ec2_ebs_public_snapshot_fixer.py create mode 100644 tests/providers/aws/services/ec2/ec2_ebs_public_snapshot/ec2_ebs_public_snapshot_fixer_test.py diff --git a/prowler/providers/aws/services/ec2/ec2_ebs_public_snapshot/ec2_ebs_public_snapshot_fixer.py b/prowler/providers/aws/services/ec2/ec2_ebs_public_snapshot/ec2_ebs_public_snapshot_fixer.py new file mode 100644 index 0000000000..792783e4a5 --- /dev/null +++ b/prowler/providers/aws/services/ec2/ec2_ebs_public_snapshot/ec2_ebs_public_snapshot_fixer.py @@ -0,0 +1,41 @@ +from prowler.lib.logger import logger +from prowler.providers.aws.services.ec2.ec2_client import ec2_client + + +def fixer(resource_id: str, region: str) -> bool: + """ + Modify the attributes of an EBS snapshot to remove public access. + Specifically, this fixer removes the 'all' value from the 'createVolumePermission' attribute to + prevent the snapshot from being publicly accessible. + Requires the ec2:ModifySnapshotAttribute permission. + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "ec2:ModifySnapshotAttribute", + "Resource": "*" + } + ] + } + Args: + resource_id (str): The snapshot identifier. + region (str): AWS region where the snapshot exists. + Returns: + bool: True if the operation is successful (public access is removed), False otherwise. + """ + try: + regional_client = ec2_client.regional_clients[region] + regional_client.modify_snapshot_attribute( + SnapshotId=resource_id, + Attribute="createVolumePermission", + OperationType="remove", + GroupNames=["all"], + ) + except Exception as error: + logger.error( + f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return False + else: + return True diff --git a/tests/providers/aws/services/ec2/ec2_ebs_public_snapshot/ec2_ebs_public_snapshot_fixer_test.py b/tests/providers/aws/services/ec2/ec2_ebs_public_snapshot/ec2_ebs_public_snapshot_fixer_test.py new file mode 100644 index 0000000000..905d85956b --- /dev/null +++ b/tests/providers/aws/services/ec2/ec2_ebs_public_snapshot/ec2_ebs_public_snapshot_fixer_test.py @@ -0,0 +1,93 @@ +from unittest import mock + +import botocore +import botocore.client +from moto import mock_aws + +from tests.providers.aws.utils import ( + AWS_REGION_EU_WEST_1, + AWS_REGION_US_EAST_1, + set_mocked_aws_provider, +) + +mock_make_api_call = botocore.client.BaseClient._make_api_call + + +def mock_make_api_call_public_snapshot(self, operation_name, kwarg): + if operation_name == "ModifySnapshotAttribute": + return { + "SnapshotId": "testsnap", + "Attribute": "createVolumePermission", + "OperationType": "remove", + "GroupNames": ["all"], + } + return mock_make_api_call(self, operation_name, kwarg) + + +def mock_make_api_call_error(self, operation_name, kwarg): + if operation_name == "ModifySnapshotAttribute": + raise botocore.exceptions.ClientError( + { + "Error": { + "Code": "UnauthorizedOperation", + "Message": "You are not authorized to perform this operation.", + } + }, + operation_name, + ) + return mock_make_api_call(self, operation_name, kwarg) + + +class Test_ec2_ebs_public_snapshot_fixer_test: + @mock_aws + def test_ebs_public_snapshot(self): + with mock.patch( + "botocore.client.BaseClient._make_api_call", + new=mock_make_api_call_public_snapshot, + ): + + from prowler.providers.aws.services.ec2.ec2_service import EC2 + + aws_provider = set_mocked_aws_provider( + [AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1] + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.ec2.ec2_ebs_public_snapshot.ec2_ebs_public_snapshot_fixer.ec2_client", + new=EC2(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.ec2.ec2_ebs_public_snapshot.ec2_ebs_public_snapshot_fixer import ( + fixer, + ) + + assert fixer("testsnap", AWS_REGION_US_EAST_1) + + @mock_aws + def test_ebs_public_snapshot_error(self): + with mock.patch( + "botocore.client.BaseClient._make_api_call", new=mock_make_api_call_error + ): + + from prowler.providers.aws.services.ec2.ec2_service import EC2 + + aws_provider = set_mocked_aws_provider( + [AWS_REGION_EU_WEST_1, AWS_REGION_US_EAST_1] + ) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.ec2.ec2_ebs_public_snapshot.ec2_ebs_public_snapshot_fixer.ec2_client", + new=EC2(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.ec2.ec2_ebs_public_snapshot.ec2_ebs_public_snapshot_fixer import ( + fixer, + ) + + assert not fixer("testsnap", AWS_REGION_US_EAST_1)