diff --git a/prowler/providers/aws/services/rds/rds_cluster_non_default_port/__init__.py b/prowler/providers/aws/services/rds/rds_cluster_non_default_port/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/rds/rds_cluster_non_default_port/rds_cluster_non_default_port.metadata.json b/prowler/providers/aws/services/rds/rds_cluster_non_default_port/rds_cluster_non_default_port.metadata.json new file mode 100644 index 0000000000..8e7122b2fb --- /dev/null +++ b/prowler/providers/aws/services/rds/rds_cluster_non_default_port/rds_cluster_non_default_port.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "aws", + "CheckID": "rds_cluster_non_default_port", + "CheckTitle": "Check if RDS clusters are using non-default ports.", + "CheckType": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "ServiceName": "rds", + "SubServiceName": "", + "ResourceIdTemplate": "arn:aws:rds:region:account-id:cluster:db-cluster", + "Severity": "low", + "ResourceType": "AwsRdsDbCluster", + "Description": "Checks if an cluster uses a port other than the default port of the database engine. The control fails if the RDS cluster uses the default port.", + "Risk": "Using a default database port exposes the cluster to potential security vulnerabilities, as attackers are more likely to target known, commonly-used ports. This may result in unauthorized access to the database or increased susceptibility to automated attacks.", + "RelatedUrl": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html", + "Remediation": { + "Code": { + "CLI": "aws rds modify-db-cluster --db-cluster-identifier --port ", + "NativeIaC": "", + "Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/rds-controls.html#rds-23", + "Terraform": "" + }, + "Recommendation": { + "Text": "Modify the RDS cluster to use a non-default port, and ensure that the security group permits access to the new port.", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/aws/services/rds/rds_cluster_non_default_port/rds_cluster_non_default_port.py b/prowler/providers/aws/services/rds/rds_cluster_non_default_port/rds_cluster_non_default_port.py new file mode 100644 index 0000000000..dfbb39fb77 --- /dev/null +++ b/prowler/providers/aws/services/rds/rds_cluster_non_default_port/rds_cluster_non_default_port.py @@ -0,0 +1,38 @@ +from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.rds.rds_client import rds_client + + +class rds_cluster_non_default_port(Check): + def execute(self): + findings = [] + default_ports = { + 3306: ["mysql", "mariadb"], + 5432: ["postgres"], + 1521: ["oracle"], + 1433: ["sqlserver"], + 50000: ["db2"], + } + for db_cluster_arn, db_cluster in rds_client.db_clusters.items(): + report = Check_Report_AWS(self.metadata()) + report.region = db_cluster.region + report.resource_id = db_cluster.id + report.resource_arn = db_cluster_arn + report.resource_tags = db_cluster.tags + report.status = "PASS" + report.status_extended = ( + f"RDS Cluster {db_cluster.id} is not using the default port " + f"{db_cluster.port} for {db_cluster.engine}." + ) + if db_cluster.port in default_ports: + default_engines = default_ports[db_cluster.port] + for default_engine in default_engines: + if default_engine in db_cluster.engine.lower(): + report.status = "FAIL" + report.status_extended = ( + f"RDS Cluster {db_cluster.id} is using the default port " + f"{db_cluster.port} for {db_cluster.engine}." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/aws/services/rds/rds_instance_non_default_port/rds_instance_non_default_port.metadata.json b/prowler/providers/aws/services/rds/rds_instance_non_default_port/rds_instance_non_default_port.metadata.json index 84ff5db321..eba9298365 100644 --- a/prowler/providers/aws/services/rds/rds_instance_non_default_port/rds_instance_non_default_port.metadata.json +++ b/prowler/providers/aws/services/rds/rds_instance_non_default_port/rds_instance_non_default_port.metadata.json @@ -10,7 +10,7 @@ "ResourceIdTemplate": "arn:aws:rds:region:account-id:db-instance", "Severity": "low", "ResourceType": "AwsRdsDbInstance", - "Description": "Checks if an instance uses a port other than the default port of the database engine. The control fails if the RDS instance uses the default port or a non-default port that is not configured in the security group.", + "Description": "Checks if an instance uses a port other than the default port of the database engine. The control fails if the RDS instance uses the default port.", "Risk": "Using a default database port exposes the instance to potential security vulnerabilities, as attackers are more likely to target known, commonly-used ports. This may result in unauthorized access to the database or increased susceptibility to automated attacks.", "RelatedUrl": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Overview.DBInstance.Modifying.html", "Remediation": { diff --git a/tests/providers/aws/services/rds/rds_cluster_non_default_port/rds_cluster_non_default_port_test.py b/tests/providers/aws/services/rds/rds_cluster_non_default_port/rds_cluster_non_default_port_test.py new file mode 100644 index 0000000000..5315b16965 --- /dev/null +++ b/tests/providers/aws/services/rds/rds_cluster_non_default_port/rds_cluster_non_default_port_test.py @@ -0,0 +1,227 @@ +from unittest import mock + +from boto3 import client +from moto import mock_aws + +from tests.providers.aws.utils import ( + AWS_ACCOUNT_NUMBER, + AWS_REGION_US_EAST_1, + set_mocked_aws_provider, +) + + +class Test_rds_cluster_non_default_port: + @mock_aws + def test_rds_no_clusters(self): + 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_cluster_non_default_port.rds_cluster_non_default_port.rds_client", + new=RDS(aws_provider), + ): + from prowler.providers.aws.services.rds.rds_cluster_non_default_port.rds_cluster_non_default_port import ( + rds_cluster_non_default_port, + ) + + check = rds_cluster_non_default_port() + result = check.execute() + + assert len(result) == 0 + + @mock_aws + def test_rds_cluster_using_default_port(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_cluster( + DBClusterIdentifier="db-cluster-1", + Engine="aurora-postgresql", + StorageEncrypted=True, + DeletionProtection=True, + MasterUsername="cluster", + MasterUserPassword="password", + Port=5432, + Tags=[{"Key": "test", "Value": "test"}], + ) + + 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_cluster_non_default_port.rds_cluster_non_default_port.rds_client", + new=RDS(aws_provider), + ): + from prowler.providers.aws.services.rds.rds_cluster_non_default_port.rds_cluster_non_default_port import ( + rds_cluster_non_default_port, + ) + + check = rds_cluster_non_default_port() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "RDS Cluster db-cluster-1 is using the default port 5432 for aurora-postgresql." + ) + assert result[0].resource_id == "db-cluster-1" + assert result[0].region == AWS_REGION_US_EAST_1 + assert ( + result[0].resource_arn + == f"arn:aws:rds:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:cluster:db-cluster-1" + ) + assert result[0].resource_tags == [{"Key": "test", "Value": "test"}] + + @mock_aws + def test_rds_cluster_using_non_default_port(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_cluster( + DBClusterIdentifier="db-cluster-1", + Engine="aurora-postgresql", + StorageEncrypted=True, + DeletionProtection=True, + MasterUsername="cluster", + MasterUserPassword="password", + Port=5433, + Tags=[{"Key": "env", "Value": "production"}], + ) + + 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_cluster_non_default_port.rds_cluster_non_default_port.rds_client", + new=RDS(aws_provider), + ): + from prowler.providers.aws.services.rds.rds_cluster_non_default_port.rds_cluster_non_default_port import ( + rds_cluster_non_default_port, + ) + + check = rds_cluster_non_default_port() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "RDS Cluster db-cluster-1 is not using the default port 5433 for aurora-postgresql." + ) + assert result[0].resource_id == "db-cluster-1" + assert result[0].region == AWS_REGION_US_EAST_1 + assert ( + result[0].resource_arn + == f"arn:aws:rds:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:cluster:db-cluster-1" + ) + assert result[0].resource_tags == [ + {"Key": "env", "Value": "production"} + ] + + @mock_aws + def test_rds_cluster_mysql_default_port(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_cluster( + DBClusterIdentifier="db-cluster-1", + Engine="mysql", + StorageEncrypted=True, + DeletionProtection=True, + MasterUsername="cluster", + MasterUserPassword="password", + Port=3306, + Tags=[{"Key": "env", "Value": "staging"}], + ) + + 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_cluster_non_default_port.rds_cluster_non_default_port.rds_client", + new=RDS(aws_provider), + ): + from prowler.providers.aws.services.rds.rds_cluster_non_default_port.rds_cluster_non_default_port import ( + rds_cluster_non_default_port, + ) + + check = rds_cluster_non_default_port() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "RDS Cluster db-cluster-1 is using the default port 3306 for mysql." + ) + assert result[0].resource_id == "db-cluster-1" + assert result[0].region == AWS_REGION_US_EAST_1 + assert ( + result[0].resource_arn + == f"arn:aws:rds:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:cluster:db-cluster-1" + ) + assert result[0].resource_tags == [{"Key": "env", "Value": "staging"}] + + @mock_aws + def test_rds_cluster_mysql_non_default_port(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_cluster( + DBClusterIdentifier="db-cluster-1", + Engine="mysql", + StorageEncrypted=True, + DeletionProtection=True, + MasterUsername="cluster", + MasterUserPassword="password", + Port=3307, + Tags=[{"Key": "env", "Value": "production"}], + ) + + 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_cluster_non_default_port.rds_cluster_non_default_port.rds_client", + new=RDS(aws_provider), + ): + from prowler.providers.aws.services.rds.rds_cluster_non_default_port.rds_cluster_non_default_port import ( + rds_cluster_non_default_port, + ) + + check = rds_cluster_non_default_port() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "RDS Cluster db-cluster-1 is not using the default port 3307 for mysql." + ) + assert result[0].resource_id == "db-cluster-1" + assert result[0].region == AWS_REGION_US_EAST_1 + assert ( + result[0].resource_arn + == f"arn:aws:rds:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:cluster:db-cluster-1" + ) + assert result[0].resource_tags == [ + {"Key": "env", "Value": "production"} + ] diff --git a/tests/providers/aws/services/rds/rds_instance_non_default_port/rds_instance_non_default_port_test.py b/tests/providers/aws/services/rds/rds_instance_non_default_port/rds_instance_non_default_port_test.py index 9959c85a42..97775dc847 100644 --- a/tests/providers/aws/services/rds/rds_instance_non_default_port/rds_instance_non_default_port_test.py +++ b/tests/providers/aws/services/rds/rds_instance_non_default_port/rds_instance_non_default_port_test.py @@ -25,7 +25,6 @@ class Test_rds_instance_non_default_port: "prowler.providers.aws.services.rds.rds_instance_non_default_port.rds_instance_non_default_port.rds_client", new=RDS(aws_provider), ): - # Test del check from prowler.providers.aws.services.rds.rds_instance_non_default_port.rds_instance_non_default_port import ( rds_instance_non_default_port, ) @@ -49,7 +48,7 @@ class Test_rds_instance_non_default_port: PubliclyAccessible=True, AutoMinorVersionUpgrade=True, BackupRetentionPeriod=10, - Port=5432, # Puerto por defecto para postgres + Port=5432, Tags=[{"Key": "test", "Value": "test"}], ) @@ -65,7 +64,6 @@ class Test_rds_instance_non_default_port: "prowler.providers.aws.services.rds.rds_instance_non_default_port.rds_instance_non_default_port.rds_client", new=RDS(aws_provider), ): - # Test del check from prowler.providers.aws.services.rds.rds_instance_non_default_port.rds_instance_non_default_port import ( rds_instance_non_default_port, ) @@ -101,7 +99,7 @@ class Test_rds_instance_non_default_port: PubliclyAccessible=True, AutoMinorVersionUpgrade=True, BackupRetentionPeriod=10, - Port=5433, # Puerto no por defecto para postgres + Port=5433, Tags=[{"Key": "env", "Value": "production"}], ) @@ -117,7 +115,6 @@ class Test_rds_instance_non_default_port: "prowler.providers.aws.services.rds.rds_instance_non_default_port.rds_instance_non_default_port.rds_client", new=RDS(aws_provider), ): - # Test del check from prowler.providers.aws.services.rds.rds_instance_non_default_port.rds_instance_non_default_port import ( rds_instance_non_default_port, ) @@ -155,7 +152,7 @@ class Test_rds_instance_non_default_port: PubliclyAccessible=True, AutoMinorVersionUpgrade=True, BackupRetentionPeriod=10, - Port=3306, # Puerto por defecto para mariadb + Port=3306, Tags=[{"Key": "env", "Value": "staging"}], ) @@ -171,7 +168,6 @@ class Test_rds_instance_non_default_port: "prowler.providers.aws.services.rds.rds_instance_non_default_port.rds_instance_non_default_port.rds_client", new=RDS(aws_provider), ): - # Test del check from prowler.providers.aws.services.rds.rds_instance_non_default_port.rds_instance_non_default_port import ( rds_instance_non_default_port, ) @@ -207,7 +203,7 @@ class Test_rds_instance_non_default_port: PubliclyAccessible=True, AutoMinorVersionUpgrade=True, BackupRetentionPeriod=10, - Port=3307, # Puerto no por defecto para mariadb + Port=3307, Tags=[{"Key": "env", "Value": "production"}], ) @@ -223,7 +219,6 @@ class Test_rds_instance_non_default_port: "prowler.providers.aws.services.rds.rds_instance_non_default_port.rds_instance_non_default_port.rds_client", new=RDS(aws_provider), ): - # Test del check from prowler.providers.aws.services.rds.rds_instance_non_default_port.rds_instance_non_default_port import ( rds_instance_non_default_port, )