From f8e161a181f0a3d780dcb7cdfc3467df754dcd67 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero Date: Fri, 15 Nov 2024 16:48:29 +0100 Subject: [PATCH 1/3] feat(rds): add fixer code for publicly accessible instances --- .../rds_instance_no_public_access_fixer.py | 43 +++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 prowler/providers/aws/services/rds/rds_instance_no_public_access/rds_instance_no_public_access_fixer.py diff --git a/prowler/providers/aws/services/rds/rds_instance_no_public_access/rds_instance_no_public_access_fixer.py b/prowler/providers/aws/services/rds/rds_instance_no_public_access/rds_instance_no_public_access_fixer.py new file mode 100644 index 00000000000..bf44b90b4de --- /dev/null +++ b/prowler/providers/aws/services/rds/rds_instance_no_public_access/rds_instance_no_public_access_fixer.py @@ -0,0 +1,43 @@ +from prowler.lib.logger import logger +from prowler.providers.aws.services.rds.rds_client import rds_client + + +def fixer(resource_id: str, region: str) -> bool: + """ + Modify the attributes of an RDS instance to disable public accessibility. + Specifically, this fixer sets the 'PubliclyAccessible' attribute to False + to prevent the RDS instance from being publicly accessible. + + Requires the rds:ModifyDBInstance permission: + { + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Action": "rds:ModifyDBInstance", + "Resource": "*" + } + ] + } + + Args: + resource_id (str): The DB instance identifier. + region (str): AWS region where the DB instance exists. + + Returns: + bool: True if the operation is successful (public access is disabled), False otherwise. + """ + try: + regional_client = rds_client.regional_clients[region] + regional_client.modify_db_instance( + DBInstanceIdentifier=resource_id, + PubliclyAccessible=False, + ApplyImmediately=True, + ) + except Exception as error: + logger.error( + f"{region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + return False + else: + return True From 4ab2753917a6f4c5fcdc2d244442a12509840577 Mon Sep 17 00:00:00 2001 From: Daniel Barranquero Date: Fri, 15 Nov 2024 16:49:38 +0100 Subject: [PATCH 2/3] feat(rds): add unit tests --- ...ds_instance_no_public_access_fixer_test.py | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) create mode 100644 tests/providers/aws/services/rds/rds_instance_no_public_access/rds_instance_no_public_access_fixer_test.py diff --git a/tests/providers/aws/services/rds/rds_instance_no_public_access/rds_instance_no_public_access_fixer_test.py b/tests/providers/aws/services/rds/rds_instance_no_public_access/rds_instance_no_public_access_fixer_test.py new file mode 100644 index 00000000000..87c5cf6c37c --- /dev/null +++ b/tests/providers/aws/services/rds/rds_instance_no_public_access/rds_instance_no_public_access_fixer_test.py @@ -0,0 +1,102 @@ +from unittest import mock + +from boto3 import client +from moto import mock_aws + +from tests.providers.aws.utils import AWS_REGION_US_EAST_1, set_mocked_aws_provider + + +class Test_rds_instance_no_public_access: + @mock_aws + def test_rds_private(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_instance( + DBInstanceIdentifier="db-primary-1", + AllocatedStorage=10, + Engine="postgres", + DBName="staging-postgres", + DBInstanceClass="db.m1.small", + ) + + from prowler.providers.aws.services.rds.rds_service import RDS + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ): + with mock.patch( + "prowler.providers.aws.services.rds.rds_instance_no_public_access.rds_instance_no_public_access_fixer.rds_client", + new=RDS(aws_provider), + ): + # Test Fixer + from prowler.providers.aws.services.rds.rds_instance_no_public_access.rds_instance_no_public_access_fixer import ( + fixer, + ) + + assert fixer("db-primary-1", AWS_REGION_US_EAST_1) + + @mock_aws + def test_rds_public(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_instance( + DBInstanceIdentifier="db-primary-1", + AllocatedStorage=10, + Engine="postgres", + DBName="staging-postgres", + DBInstanceClass="db.m1.small", + PubliclyAccessible=True, + ) + + from prowler.providers.aws.services.rds.rds_service import RDS + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ): + with mock.patch( + "prowler.providers.aws.services.rds.rds_instance_no_public_access.rds_instance_no_public_access_fixer.rds_client", + new=RDS(aws_provider), + ): + + # Test Fixer + from prowler.providers.aws.services.rds.rds_instance_no_public_access.rds_instance_no_public_access_fixer import ( + fixer, + ) + + assert fixer("db-primary-1", AWS_REGION_US_EAST_1) + + @mock_aws + def test_rds_cluster_public_snapshot_error(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_instance( + DBInstanceIdentifier="db-primary-1", + AllocatedStorage=10, + Engine="postgres", + DBName="staging-postgres", + DBInstanceClass="db.m1.small", + PubliclyAccessible=True, + ) + + from prowler.providers.aws.services.rds.rds_service import RDS + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ): + with mock.patch( + "prowler.providers.aws.services.rds.rds_instance_no_public_access.rds_instance_no_public_access_fixer.rds_client", + new=RDS(aws_provider), + ): + + # Test Fixer + from prowler.providers.aws.services.rds.rds_instance_no_public_access.rds_instance_no_public_access_fixer import ( + fixer, + ) + + assert not fixer("db-primary-2", AWS_REGION_US_EAST_1) From b643237e2f49ee62429757c988ed5c5089ee65bc Mon Sep 17 00:00:00 2001 From: Daniel Barranquero Date: Tue, 19 Nov 2024 11:16:59 +0100 Subject: [PATCH 3/3] fix(rds): add _fixer to the class name in the tests file --- .../rds_instance_no_public_access_fixer_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/providers/aws/services/rds/rds_instance_no_public_access/rds_instance_no_public_access_fixer_test.py b/tests/providers/aws/services/rds/rds_instance_no_public_access/rds_instance_no_public_access_fixer_test.py index 87c5cf6c37c..5577a5623ba 100644 --- a/tests/providers/aws/services/rds/rds_instance_no_public_access/rds_instance_no_public_access_fixer_test.py +++ b/tests/providers/aws/services/rds/rds_instance_no_public_access/rds_instance_no_public_access_fixer_test.py @@ -6,7 +6,7 @@ from tests.providers.aws.utils import AWS_REGION_US_EAST_1, set_mocked_aws_provider -class Test_rds_instance_no_public_access: +class Test_rds_instance_no_public_access_fixer: @mock_aws def test_rds_private(self): conn = client("rds", region_name=AWS_REGION_US_EAST_1)