diff --git a/prowler/providers/aws/services/rds/rds_cluster_backtrack_enabled/__init__.py b/prowler/providers/aws/services/rds/rds_cluster_backtrack_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/rds/rds_cluster_backtrack_enabled/rds_cluster_backtrack_enabled.metadata.json b/prowler/providers/aws/services/rds/rds_cluster_backtrack_enabled/rds_cluster_backtrack_enabled.metadata.json new file mode 100644 index 0000000000..3b4a87aa50 --- /dev/null +++ b/prowler/providers/aws/services/rds/rds_cluster_backtrack_enabled/rds_cluster_backtrack_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "aws", + "CheckID": "rds_cluster_backtrack_enabled", + "CheckTitle": "Check if RDS Aurora MySQL Clusters have backtrack enabled.", + "CheckType": [], + "ServiceName": "rds", + "SubServiceName": "", + "ResourceIdTemplate": "arn:aws:rds:region:account-id:db-cluster", + "Severity": "medium", + "ResourceType": "AwsRdsDbClsuter", + "Description": "Ensure that the Backtrack feature is enabled for your Amazon Aurora (with MySQL compatibility) database clusters in order to backtrack your clusters to a specific time, without using backups. Backtrack is an Amazon RDS feature that allows you to specify the amount of time that an Aurora MySQL database cluster needs to retain change records, in order to have a fast way to recover from user errors, such as dropping the wrong table or deleting the wrong row by moving your MySQL database to a prior point in time without the need to restore from a recent backup.", + "Risk": "Once the Backtrack feature is enabled, Amazon RDS can quickly 'rewind' your Aurora MySQL database cluster to a point in time that you specify. In contrast to the backup and restore method, with Backtrack you can easily undo a destructive action, such as a DELETE query without a WHERE clause, with minimal downtime, you can rewind your Aurora cluster in just few minutes, and you can repeatedly backtrack a database cluster back and forth in time to help determine when a particular data change occurred.", + "RelatedUrl": "https://docs.aws.amazon.com/securityhub/latest/userguide/rds-controls.html#rds-14", + "Remediation": { + "Code": { + "CLI": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/RDS/backtrack.html#", + "NativeIaC": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/RDS/backtrack.html#", + "Other": "", + "Terraform": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/RDS/backtrack.html#" + }, + "Recommendation": { + "Text": "Backups help you to recover more quickly from a security incident. They also strengthens the resilience of your systems. Aurora backtracking reduces the time to recover a database to a point in time. It does not require a database restore to do so. You cannot enable backtracking on an existing cluster. Instead, you can create a clone that has backtracking enabled.", + "Url": "https://docs.aws.amazon.com/securityhub/latest/userguide/rds-controls.html#rds-14" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/aws/services/rds/rds_cluster_backtrack_enabled/rds_cluster_backtrack_enabled.py b/prowler/providers/aws/services/rds/rds_cluster_backtrack_enabled/rds_cluster_backtrack_enabled.py new file mode 100644 index 0000000000..ade80b171e --- /dev/null +++ b/prowler/providers/aws/services/rds/rds_cluster_backtrack_enabled/rds_cluster_backtrack_enabled.py @@ -0,0 +1,24 @@ +from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.rds.rds_client import rds_client + + +class rds_cluster_backtrack_enabled(Check): + def execute(self): + findings = [] + for db_cluster in rds_client.db_clusters: + report = Check_Report_AWS(self.metadata()) + report.region = rds_client.db_clusters[db_cluster].region + report.resource_id = rds_client.db_clusters[db_cluster].id + report.resource_arn = db_cluster + report.resource_tags = rds_client.db_clusters[db_cluster].tags + report.status = "FAIL" + report.status_extended = f"RDS Cluster {rds_client.db_clusters[db_cluster].id} does not have backtrack enabled." + # Only RDS Aurora MySQL clusters support backtrack. + if rds_client.db_clusters[db_cluster].engine == "aurora-mysql": + if rds_client.db_clusters[db_cluster].backtrack > 0: + report.status = "PASS" + report.status_extended = f"RDS Cluster {rds_client.db_clusters[db_cluster].id} has backtrack enabled." + + findings.append(report) + + return findings diff --git a/prowler/providers/aws/services/rds/rds_instance_default_admin/__init__.py b/prowler/providers/aws/services/rds/rds_instance_default_admin/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/rds/rds_instance_default_admin/rds_instance_default_admin.metadata.json b/prowler/providers/aws/services/rds/rds_instance_default_admin/rds_instance_default_admin.metadata.json new file mode 100644 index 0000000000..b02809245e --- /dev/null +++ b/prowler/providers/aws/services/rds/rds_instance_default_admin/rds_instance_default_admin.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "aws", + "CheckID": "rds_instance_default_admin", + "CheckTitle": "Ensure that your Amazon RDS instances/clusters are not using the default master username.", + "CheckType": [], + "ServiceName": "rds", + "SubServiceName": "", + "ResourceIdTemplate": "arn:aws:rds:region:account-id:db-instance", + "Severity": "medium", + "ResourceType": "AwsRdsDbInstance", + "Description": "Ensure that your Amazon RDS instances/clusters are not using the default master username.", + "Risk": "Since admin is the Amazon's example for the RDS database master username and postgres is the default PostgreSQL master username. Many AWS customers will use this username for their RDS database instances in production. Malicious users can use this information to their advantage and frequently try to use default master username during brute-force attacks.", + "RelatedUrl": "https://docs.aws.amazon.com/securityhub/latest/userguide/rds-controls.html#rds-25", + "Remediation": { + "Code": { + "CLI": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/RDS/rds-master-username.html#", + "NativeIaC": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/RDS/rds-master-username.html#", + "Other": "", + "Terraform": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/RDS/rds-master-username.html#" + }, + "Recommendation": { + "Text": "To change the master username configured for your Amazon RDS database instances/clusters you must re-create them and migrate the existing data.", + "Url": "https://docs.aws.amazon.com/securityhub/latest/userguide/rds-controls.html#rds-25" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/aws/services/rds/rds_instance_default_admin/rds_instance_default_admin.py b/prowler/providers/aws/services/rds/rds_instance_default_admin/rds_instance_default_admin.py new file mode 100644 index 0000000000..a826a484da --- /dev/null +++ b/prowler/providers/aws/services/rds/rds_instance_default_admin/rds_instance_default_admin.py @@ -0,0 +1,47 @@ +from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.rds.rds_client import rds_client + + +class rds_instance_default_admin(Check): + def execute(self): + findings = [] + for db_instance in rds_client.db_instances: + report = Check_Report_AWS(self.metadata()) + report.region = db_instance.region + report.resource_id = db_instance.id + report.resource_arn = db_instance.arn + report.resource_tags = db_instance.tags + report.status = "FAIL" + report.status_extended = ( + f"RDS Instance {db_instance.id} is using the default master username." + ) + + # Check only RDS DB instances that are not clustered + if not db_instance.cluster_id: + if ( + db_instance.username != "admin" + and db_instance.username != "postgres" + ): + report.status = "PASS" + report.status_extended = f"RDS Instance {db_instance.id} is not using the default master username." + + findings.append(report) + + for db_cluster in rds_client.db_clusters: + report = Check_Report_AWS(self.metadata()) + report.region = rds_client.db_clusters[db_cluster].region + report.resource_id = rds_client.db_clusters[db_cluster].id + report.resource_arn = db_cluster + report.resource_tags = rds_client.db_clusters[db_cluster].tags + report.status = "FAIL" + report.status_extended = f"RDS Cluster {rds_client.db_clusters[db_cluster].id} is using the default master username." + if ( + rds_client.db_clusters[db_cluster].username != "admin" + and rds_client.db_clusters[db_cluster].username != "postgres" + ): + report.status = "PASS" + report.status_extended = f"RDS Cluster {rds_client.db_clusters[db_cluster].id} is not using the default master username." + + findings.append(report) + + return findings diff --git a/prowler/providers/aws/services/rds/rds_instance_iam_authentication_enabled/__init__.py b/prowler/providers/aws/services/rds/rds_instance_iam_authentication_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/rds/rds_instance_iam_authentication_enabled/rds_instance_iam_authentication_enabled.metadata.json b/prowler/providers/aws/services/rds/rds_instance_iam_authentication_enabled/rds_instance_iam_authentication_enabled.metadata.json new file mode 100644 index 0000000000..bc0fd7c674 --- /dev/null +++ b/prowler/providers/aws/services/rds/rds_instance_iam_authentication_enabled/rds_instance_iam_authentication_enabled.metadata.json @@ -0,0 +1,30 @@ +{ + "Provider": "aws", + "CheckID": "rds_instance_iam_authentication_enabled", + "CheckTitle": "Check if RDS instances/clusters have IAM authentication enabled.", + "CheckType": [], + "ServiceName": "rds", + "SubServiceName": "", + "ResourceIdTemplate": "arn:aws:rds:region:account-id:db-instance", + "Severity": "medium", + "ResourceType": "AwsRdsDbInstance", + "Description": "Check if RDS instances/clusters have IAM authentication enabled.", + "Risk": "Ensure that the IAM Database Authentication feature is enabled for your RDS database instances in order to use the Identity and Access Management (IAM) service to manage database access to your MySQL and PostgreSQL database instances. With this feature enabled, you don't have to use a password when you connect to your MySQL/PostgreSQL database, instead you can use an authentication token. An authentication token is a unique string of characters with a lifetime of 15 minutes that Amazon RDS generates on your request. IAM Database Authentication removes the need of storing user credentials within the database configuration, because authentication is managed externally using Amazon IAM.", + "RelatedUrl": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.Enabling.html", + "Remediation": { + "Code": { + "CLI": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/RDS/iam-database-authentication.html#", + "NativeIaC": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/RDS/iam-database-authentication.html#", + "Other": "", + "Terraform": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/RDS/iam-database-authentication.html#" + }, + "Recommendation": { + "Text": "Enable IAM authentication for supported RDS instances/clusters.", + "Url": "https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/UsingWithRDS.IAMDBAuth.Enabling.html" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/aws/services/rds/rds_instance_iam_authentication_enabled/rds_instance_iam_authentication_enabled.py b/prowler/providers/aws/services/rds/rds_instance_iam_authentication_enabled/rds_instance_iam_authentication_enabled.py new file mode 100644 index 0000000000..2a531e62ed --- /dev/null +++ b/prowler/providers/aws/services/rds/rds_instance_iam_authentication_enabled/rds_instance_iam_authentication_enabled.py @@ -0,0 +1,51 @@ +from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.rds.rds_client import rds_client + + +class rds_instance_iam_authentication_enabled(Check): + def execute(self): + supported_engines = [ + "postgres", + "aurora-postgresql", + "mysql", + "mariadb", + "aurora-mysql", + "aurora", + ] + findings = [] + for db_instance in rds_client.db_instances: + report = Check_Report_AWS(self.metadata()) + report.region = db_instance.region + report.resource_id = db_instance.id + report.resource_arn = db_instance.arn + report.resource_tags = db_instance.tags + report.status = "FAIL" + report.status_extended = f"RDS Instance {db_instance.id} does not have IAM authentication enabled." + + # Check DB Instance to make sure its not part of a cluster. + if not db_instance.cluster_id and any( + engine in db_instance.engine for engine in supported_engines + ): + if db_instance.iam_auth: + report.status = "PASS" + report.status_extended = ( + f"RDS Instance {db_instance.id} has IAM authentication enabled." + ) + + findings.append(report) + + for db_cluster in rds_client.db_clusters: + report = Check_Report_AWS(self.metadata()) + report.region = rds_client.db_clusters[db_cluster].region + report.resource_id = rds_client.db_clusters[db_cluster].id + report.resource_arn = db_cluster + report.resource_tags = rds_client.db_clusters[db_cluster].tags + report.status = "FAIL" + report.status_extended = f"RDS Cluster {rds_client.db_clusters[db_cluster].id} does not have IAM authentication enabled." + if rds_client.db_clusters[db_cluster].iam_auth: + report.status = "PASS" + report.status_extended = f"RDS Cluster {rds_client.db_clusters[db_cluster].id} has IAM authentication enabled." + + findings.append(report) + + return findings diff --git a/prowler/providers/aws/services/rds/rds_service.py b/prowler/providers/aws/services/rds/rds_service.py index bbae552f84..469a3f19db 100644 --- a/prowler/providers/aws/services/rds/rds_service.py +++ b/prowler/providers/aws/services/rds/rds_service.py @@ -81,6 +81,10 @@ class RDS(AWSService): for item in instance["DBParameterGroups"] ], multi_az=instance["MultiAZ"], + username=instance["MasterUsername"], + iam_auth=instance.get( + "IAMDatabaseAuthenticationEnabled", False + ), security_groups=[ sg["VpcSecurityGroupId"] for sg in instance["VpcSecurityGroups"] @@ -170,6 +174,7 @@ class RDS(AWSService): id=snapshot["DBSnapshotIdentifier"], arn=arn, instance_id=snapshot["DBInstanceIdentifier"], + encrypted=snapshot.get("Encrypted", False), region=regional_client.region, tags=snapshot.get("TagList", []), ) @@ -232,6 +237,7 @@ class RDS(AWSService): backup_retention_period=cluster.get( "BackupRetentionPeriod" ), + backtrack=cluster.get("BacktrackWindow", 0), cloudwatch_logs=cluster.get( "EnabledCloudwatchLogsExports" ), @@ -242,6 +248,10 @@ class RDS(AWSService): "DBClusterParameterGroup" ], multi_az=cluster["MultiAZ"], + username=cluster["MasterUsername"], + iam_auth=cluster.get( + "IAMDatabaseAuthenticationEnabled", False + ), region=regional_client.region, tags=cluster.get("TagList", []), ) @@ -330,6 +340,7 @@ class RDS(AWSService): id=snapshot["DBClusterSnapshotIdentifier"], arn=arn, cluster_id=snapshot["DBClusterIdentifier"], + encrypted=snapshot.get("StorageEncrypted", False), region=regional_client.region, tags=snapshot.get("TagList", []), ) @@ -476,6 +487,8 @@ class DBInstance(BaseModel): auto_minor_version_upgrade: bool enhanced_monitoring_arn: Optional[str] multi_az: bool + username: str + iam_auth: bool parameter_groups: list[str] = [] parameters: list[dict] = [] security_groups: list[str] = [] @@ -497,10 +510,13 @@ class DBCluster(BaseModel): public: bool encrypted: bool backup_retention_period: int = 0 + backtrack: int cloudwatch_logs: Optional[list] deletion_protection: bool auto_minor_version_upgrade: bool multi_az: bool + username: str + iam_auth: bool parameter_group: str force_ssl: str = "0" require_secure_transport: str = "OFF" @@ -514,6 +530,7 @@ class DBSnapshot(BaseModel): arn: str instance_id: str public: bool = False + encrypted: bool region: str tags: Optional[list] = [] @@ -524,6 +541,7 @@ class ClusterSnapshot(BaseModel): # arn:{partition}:rds:{region}:{account}:cluster-snapshot:{resource_id} arn: str public: bool = False + encrypted: bool region: str tags: Optional[list] = [] diff --git a/prowler/providers/aws/services/rds/rds_snapshots_encrypted/__init__.py b/prowler/providers/aws/services/rds/rds_snapshots_encrypted/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/rds/rds_snapshots_encrypted/rds_snapshots_encrypted.metadata.json b/prowler/providers/aws/services/rds/rds_snapshots_encrypted/rds_snapshots_encrypted.metadata.json new file mode 100644 index 0000000000..422ceed2af --- /dev/null +++ b/prowler/providers/aws/services/rds/rds_snapshots_encrypted/rds_snapshots_encrypted.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "aws", + "CheckID": "rds_snapshots_encrypted", + "CheckTitle": "Check if RDS Snapshots and Cluster Snapshots are encrypted.", + "CheckType": [], + "ServiceName": "rds", + "SubServiceName": "", + "ResourceIdTemplate": "arn:aws:rds:region:account-id:snapshot", + "Severity": "medium", + "ResourceType": "AwsRdsDbSnapshot", + "Description": "Check if RDS Snapshots and Cluster Snapshots are encrypted.", + "Risk": "Ensure that your manual Amazon RDS database snapshots are encrypted in order to achieve compliance for data-at-rest encryption within your organization.", + "RelatedUrl": "https://docs.aws.amazon.com/securityhub/latest/userguide/rds-controls.html#rds-4", + "Remediation": { + "Code": { + "CLI": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/RDS/snapshot-encrypted.html#", + "NativeIaC": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/RDS/snapshot-encrypted.html#", + "Other": "", + "Terraform": "https://www.trendmicro.com/cloudoneconformity/knowledge-base/aws/RDS/snapshot-encrypted.html#" + }, + "Recommendation": { + "Text": "When working with production databases that hold sensitive and critical data, it is strongly recommended to implement encryption at rest and protect your data from attackers or unauthorized personnel. ", + "Url": "https://docs.aws.amazon.com/securityhub/latest/userguide/rds-controls.html#rds-4" + } + }, + "Categories": [ + "encryption" + ], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/aws/services/rds/rds_snapshots_encrypted/rds_snapshots_encrypted.py b/prowler/providers/aws/services/rds/rds_snapshots_encrypted/rds_snapshots_encrypted.py new file mode 100644 index 0000000000..e820792b6c --- /dev/null +++ b/prowler/providers/aws/services/rds/rds_snapshots_encrypted/rds_snapshots_encrypted.py @@ -0,0 +1,46 @@ +from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.rds.rds_client import rds_client + + +class rds_snapshots_encrypted(Check): + def execute(self): + findings = [] + for db_snap in rds_client.db_snapshots: + report = Check_Report_AWS(self.metadata()) + report.region = db_snap.region + report.resource_id = db_snap.id + report.resource_arn = db_snap.arn + report.resource_tags = db_snap.tags + if db_snap.encrypted: + report.status = "PASS" + report.status_extended = ( + f"RDS Instance Snapshot {db_snap.id} is encrypted." + ) + else: + report.status = "FAIL" + report.status_extended = ( + f"RDS Instance Snapshot {db_snap.id} is not encrypted." + ) + + findings.append(report) + + for db_snap in rds_client.db_cluster_snapshots: + report = Check_Report_AWS(self.metadata()) + report.region = db_snap.region + report.resource_id = db_snap.id + report.resource_arn = db_snap.arn + report.resource_tags = db_snap.tags + if db_snap.encrypted: + report.status = "PASS" + report.status_extended = ( + f"RDS Cluster Snapshot {db_snap.id} is encrypted." + ) + else: + report.status = "FAIL" + report.status_extended = ( + f"RDS Cluster Snapshot {db_snap.id} is not encrypted." + ) + + findings.append(report) + + return findings diff --git a/tests/providers/aws/services/rds/rds_cluster_backtrack_enabled/rds_cluster_backtrack_enabled_test.py b/tests/providers/aws/services/rds/rds_cluster_backtrack_enabled/rds_cluster_backtrack_enabled_test.py new file mode 100644 index 0000000000..d060efbc68 --- /dev/null +++ b/tests/providers/aws/services/rds/rds_cluster_backtrack_enabled/rds_cluster_backtrack_enabled_test.py @@ -0,0 +1,181 @@ +from unittest import mock + +import botocore +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, +) + +make_api_call = botocore.client.BaseClient._make_api_call + + +def mock_make_api_call(self, operation_name, kwarg): + if operation_name == "DescribeDBEngineVersions": + return { + "DBEngineVersions": [ + { + "Engine": "mysql", + "EngineVersion": "8.0.32", + "DBEngineDescription": "description", + "DBEngineVersionDescription": "description", + }, + ] + } + return make_api_call(self, operation_name, kwarg) + + +# Currently have to mock the tests as moto does not return the value for backtrack. Issue: https://github.com/getmoto/moto/issues/7734 +@mock.patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call) +class Test_rds_cluster_backtrack_enabled: + @mock_aws + def test_no_rds_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_backtrack_enabled.rds_cluster_backtrack_enabled.rds_client", + new=RDS(aws_provider), + ): + from prowler.providers.aws.services.rds.rds_cluster_backtrack_enabled.rds_cluster_backtrack_enabled import ( + rds_cluster_backtrack_enabled, + ) + + check = rds_cluster_backtrack_enabled() + result = check.execute() + + assert len(result) == 0 + + @mock_aws + def test_rds_cluster_aurora_mysql_backtrack_disabled(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_parameter_group( + DBParameterGroupName="test", + DBParameterGroupFamily="default.mysql8.0", + Description="test parameter group", + ) + conn.create_db_cluster( + DBClusterIdentifier="db-cluster-1", + AllocatedStorage=10, + Engine="aurora-mysql", + DatabaseName="staging-mysql", + DeletionProtection=True, + DBClusterParameterGroupName="test", + MasterUsername="test", + MasterUserPassword="password", + Tags=[], + ) + conn.modify_db_parameter_group( + DBParameterGroupName="test", + Parameters=[ + { + "ParameterName": "require_secure_transport", + "ParameterValue": "ON", + "ApplyMethod": "immediate", + }, + ], + ) + 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_backtrack_enabled.rds_cluster_backtrack_enabled.rds_client", + new=RDS(aws_provider), + ): + from prowler.providers.aws.services.rds.rds_cluster_backtrack_enabled.rds_cluster_backtrack_enabled import ( + rds_cluster_backtrack_enabled, + ) + + check = rds_cluster_backtrack_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "RDS Cluster db-cluster-1 does not have backtrack enabled." + ) + 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 == [] + + @mock_aws + def test_rds_cluster_aurora_mysql_backtrack_enabled(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_parameter_group( + DBParameterGroupName="test", + DBParameterGroupFamily="default.mysql8.0", + Description="test parameter group", + ) + conn.create_db_cluster( + DBClusterIdentifier="db-cluster-1", + AllocatedStorage=10, + Engine="aurora-mysql", + DatabaseName="staging-mysql", + DeletionProtection=True, + DBClusterParameterGroupName="test", + MasterUsername="test", + MasterUserPassword="password", + Tags=[], + ) + conn.modify_db_parameter_group( + DBParameterGroupName="test", + Parameters=[ + { + "ParameterName": "require_secure_transport", + "ParameterValue": "ON", + "ApplyMethod": "immediate", + }, + ], + ) + db_cluster = f"arn:aws:rds:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:cluster:db-cluster-1" + 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_backtrack_enabled.rds_cluster_backtrack_enabled.rds_client", + new=RDS(aws_provider), + ) as service_client: + from prowler.providers.aws.services.rds.rds_cluster_backtrack_enabled.rds_cluster_backtrack_enabled import ( + rds_cluster_backtrack_enabled, + ) + + service_client.db_clusters[db_cluster].backtrack = 1 + check = rds_cluster_backtrack_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "RDS Cluster db-cluster-1 has backtrack enabled." + ) + 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 == [] diff --git a/tests/providers/aws/services/rds/rds_instance_certificate_expiration/rds_instance_certificate_expiration_test.py b/tests/providers/aws/services/rds/rds_instance_certificate_expiration/rds_instance_certificate_expiration_test.py index 075a84ac3f..48dfc37884 100644 --- a/tests/providers/aws/services/rds/rds_instance_certificate_expiration/rds_instance_certificate_expiration_test.py +++ b/tests/providers/aws/services/rds/rds_instance_certificate_expiration/rds_instance_certificate_expiration_test.py @@ -76,6 +76,8 @@ class Test_rds_instance_certificate_expiration: deletion_protection=True, auto_minor_version_upgrade=False, multi_az=True, + username="test", + iam_auth=False, region=AWS_REGION, ca_cert="rds-ca-rsa2048-g1", cert=[ @@ -145,6 +147,8 @@ class Test_rds_instance_certificate_expiration: deletion_protection=True, auto_minor_version_upgrade=False, multi_az=True, + username="test", + iam_auth=False, region=AWS_REGION, ca_cert="rds-ca-rsa2048-g1", cert=[ @@ -213,6 +217,8 @@ class Test_rds_instance_certificate_expiration: deletion_protection=True, auto_minor_version_upgrade=False, multi_az=True, + username="test", + iam_auth=False, region=AWS_REGION, ca_cert="rds-ca-rsa2048-g1", cert=[ @@ -281,6 +287,8 @@ class Test_rds_instance_certificate_expiration: deletion_protection=True, auto_minor_version_upgrade=False, multi_az=True, + username="test", + iam_auth=False, region=AWS_REGION, ca_cert="rds-ca-rsa2048-g1", cert=[ @@ -349,6 +357,8 @@ class Test_rds_instance_certificate_expiration: deletion_protection=True, auto_minor_version_upgrade=False, multi_az=True, + username="test", + iam_auth=False, region=AWS_REGION, ca_cert="rds-ca-rsa2048-g1", cert=[ @@ -417,6 +427,8 @@ class Test_rds_instance_certificate_expiration: deletion_protection=True, auto_minor_version_upgrade=False, multi_az=True, + username="test", + iam_auth=False, region=AWS_REGION, ca_cert="rds-ca-rsa2048-g1", cert=[ @@ -485,6 +497,8 @@ class Test_rds_instance_certificate_expiration: deletion_protection=True, auto_minor_version_upgrade=False, multi_az=True, + username="test", + iam_auth=False, region=AWS_REGION, ca_cert="rds-ca-rsa2048-g1", cert=[ @@ -553,6 +567,8 @@ class Test_rds_instance_certificate_expiration: deletion_protection=True, auto_minor_version_upgrade=False, multi_az=True, + username="test", + iam_auth=False, region=AWS_REGION, ca_cert="rds-ca-rsa2048-g1", cert=[ @@ -621,6 +637,8 @@ class Test_rds_instance_certificate_expiration: deletion_protection=True, auto_minor_version_upgrade=False, multi_az=True, + username="test", + iam_auth=False, region=AWS_REGION, ca_cert="rds-ca-rsa2048-g1", cert=[ diff --git a/tests/providers/aws/services/rds/rds_instance_default_admin/rds_instance_default_admin_test.py b/tests/providers/aws/services/rds/rds_instance_default_admin/rds_instance_default_admin_test.py new file mode 100644 index 0000000000..216a19f6ce --- /dev/null +++ b/tests/providers/aws/services/rds/rds_instance_default_admin/rds_instance_default_admin_test.py @@ -0,0 +1,264 @@ +from unittest import mock + +import botocore +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, +) + +make_api_call = botocore.client.BaseClient._make_api_call + + +def mock_make_api_call(self, operation_name, kwarg): + if operation_name == "DescribeDBEngineVersions": + return { + "DBEngineVersions": [ + { + "Engine": "mysql", + "EngineVersion": "8.0.32", + "DBEngineDescription": "description", + "DBEngineVersionDescription": "description", + }, + ] + } + return make_api_call(self, operation_name, kwarg) + + +@mock.patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call) +class Test_rds_instance_default_admin: + @mock_aws + def test_rds_no_instances(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_instance_default_admin.rds_instance_default_admin.rds_client", + new=RDS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.rds.rds_instance_default_admin.rds_instance_default_admin import ( + rds_instance_default_admin, + ) + + check = rds_instance_default_admin() + result = check.execute() + + assert len(result) == 0 + + @mock_aws + def test_rds_instance_with_default_username(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_parameter_group( + DBParameterGroupName="test", + DBParameterGroupFamily="default.aurora-postgresql14", + Description="test parameter group", + ) + conn.create_db_instance( + DBInstanceIdentifier="db-master-1", + AllocatedStorage=10, + Engine="aurora-postgresql", + DBName="aurora-postgres", + MasterUsername="postgres", + DBInstanceClass="db.m1.small", + DBParameterGroupName="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_instance_default_admin.rds_instance_default_admin.rds_client", + new=RDS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.rds.rds_instance_default_admin.rds_instance_default_admin import ( + rds_instance_default_admin, + ) + + check = rds_instance_default_admin() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "RDS Instance db-master-1 is using the default master username." + ) + assert result[0].resource_id == "db-master-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}:db:db-master-1" + ) + assert result[0].resource_tags == [] + + @mock_aws + def test_rds_instance_without_default_username(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_parameter_group( + DBParameterGroupName="test", + DBParameterGroupFamily="default.aurora-postgresql14", + Description="test parameter group", + ) + conn.create_db_instance( + DBInstanceIdentifier="db-master-1", + AllocatedStorage=10, + Engine="aurora-postgresql", + DBName="aurora-postgres", + MasterUsername="postgres2", + DBInstanceClass="db.m1.small", + DBParameterGroupName="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_instance_default_admin.rds_instance_default_admin.rds_client", + new=RDS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.rds.rds_instance_default_admin.rds_instance_default_admin import ( + rds_instance_default_admin, + ) + + check = rds_instance_default_admin() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "RDS Instance db-master-1 is not using the default master username." + ) + assert result[0].resource_id == "db-master-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}:db:db-master-1" + ) + assert result[0].resource_tags == [] + + @mock_aws + def test_rds_clustered_with_default_username(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_parameter_group( + DBParameterGroupName="test", + DBParameterGroupFamily="default.aurora-postgresql14", + Description="test parameter group", + ) + conn.create_db_cluster( + DBClusterIdentifier="db-cluster-1", + AllocatedStorage=10, + Engine="aurora-postgresql", + DatabaseName="staging-postgres", + DeletionProtection=True, + DBClusterParameterGroupName="test", + MasterUsername="admin", + MasterUserPassword="password", + Tags=[], + ) + + 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_default_admin.rds_instance_default_admin.rds_client", + new=RDS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.rds.rds_instance_default_admin.rds_instance_default_admin import ( + rds_instance_default_admin, + ) + + check = rds_instance_default_admin() + 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 master username." + ) + 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 == [] + + @mock_aws + def test_rds_clustered_without_default_username(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_parameter_group( + DBParameterGroupName="test", + DBParameterGroupFamily="default.mysql8.0", + Description="test parameter group", + ) + conn.create_db_cluster( + DBClusterIdentifier="db-cluster-1", + AllocatedStorage=10, + Engine="aurora-mysql", + DatabaseName="staging-mysql", + DeletionProtection=True, + DBClusterParameterGroupName="test", + MasterUsername="test", + MasterUserPassword="password", + Tags=[], + ) + 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_default_admin.rds_instance_default_admin.rds_client", + new=RDS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.rds.rds_instance_default_admin.rds_instance_default_admin import ( + rds_instance_default_admin, + ) + + check = rds_instance_default_admin() + 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 master username." + ) + 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 == [] diff --git a/tests/providers/aws/services/rds/rds_instance_iam_authentication_enabled/rds_instance_iam_authentication_enabled_test.py b/tests/providers/aws/services/rds/rds_instance_iam_authentication_enabled/rds_instance_iam_authentication_enabled_test.py new file mode 100644 index 0000000000..bdaa27bfcf --- /dev/null +++ b/tests/providers/aws/services/rds/rds_instance_iam_authentication_enabled/rds_instance_iam_authentication_enabled_test.py @@ -0,0 +1,408 @@ +from unittest import mock + +import botocore +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, +) + +make_api_call = botocore.client.BaseClient._make_api_call + + +def mock_make_api_call(self, operation_name, kwarg): + if operation_name == "DescribeDBEngineVersions": + return { + "DBEngineVersions": [ + { + "Engine": "mysql", + "EngineVersion": "8.0.32", + "DBEngineDescription": "description", + "DBEngineVersionDescription": "description", + }, + ] + } + + return make_api_call(self, operation_name, kwarg) + + +@mock.patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call) +class Test_rds_instance_iam_authentication_enabled: + @mock_aws + def test_rds_no_instances(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_instance_iam_authentication_enabled.rds_instance_iam_authentication_enabled.rds_client", + new=RDS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.rds.rds_instance_iam_authentication_enabled.rds_instance_iam_authentication_enabled import ( + rds_instance_iam_authentication_enabled, + ) + + check = rds_instance_iam_authentication_enabled() + result = check.execute() + + assert len(result) == 0 + + @mock_aws + def test_rds_aurora_instance_without_iam_auth(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_parameter_group( + DBParameterGroupName="test", + DBParameterGroupFamily="default.aurora-postgresql14", + Description="test parameter group", + ) + conn.create_db_instance( + DBInstanceIdentifier="db-master-1", + AllocatedStorage=10, + Engine="aurora-postgresql", + DBName="aurora-postgres", + EnableIAMDatabaseAuthentication=False, + DBInstanceClass="db.m1.small", + DBParameterGroupName="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_instance_iam_authentication_enabled.rds_instance_iam_authentication_enabled.rds_client", + new=RDS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.rds.rds_instance_iam_authentication_enabled.rds_instance_iam_authentication_enabled import ( + rds_instance_iam_authentication_enabled, + ) + + check = rds_instance_iam_authentication_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "RDS Instance db-master-1 does not have IAM authentication enabled." + ) + assert result[0].resource_id == "db-master-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}:db:db-master-1" + ) + assert result[0].resource_tags == [] + + @mock_aws + def test_rds_postgres_instance_with_iam_auth(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_parameter_group( + DBParameterGroupName="test", + DBParameterGroupFamily="default.postgres9.3", + Description="test parameter group", + ) + conn.create_db_instance( + DBInstanceIdentifier="db-master-1", + AllocatedStorage=10, + Engine="postgres", + DBName="staging-postgres", + DBInstanceClass="db.m1.small", + EnableIAMDatabaseAuthentication=True, + DBParameterGroupName="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_instance_iam_authentication_enabled.rds_instance_iam_authentication_enabled.rds_client", + new=RDS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.rds.rds_instance_iam_authentication_enabled.rds_instance_iam_authentication_enabled import ( + rds_instance_iam_authentication_enabled, + ) + + check = rds_instance_iam_authentication_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "RDS Instance db-master-1 has IAM authentication enabled." + ) + assert result[0].resource_id == "db-master-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}:db:db-master-1" + ) + assert result[0].resource_tags == [] + + @mock_aws + def test_rds_mysql_instance_with_iam_auth(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_parameter_group( + DBParameterGroupName="test", + DBParameterGroupFamily="default.mysql", + Description="test parameter group", + ) + conn.create_db_instance( + DBInstanceIdentifier="db-master-1", + AllocatedStorage=10, + Engine="mysql", + DBName="staging-mysql", + DBInstanceClass="db.m1.small", + EnableIAMDatabaseAuthentication=True, + DBParameterGroupName="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_instance_iam_authentication_enabled.rds_instance_iam_authentication_enabled.rds_client", + new=RDS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.rds.rds_instance_iam_authentication_enabled.rds_instance_iam_authentication_enabled import ( + rds_instance_iam_authentication_enabled, + ) + + check = rds_instance_iam_authentication_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "RDS Instance db-master-1 has IAM authentication enabled." + ) + assert result[0].resource_id == "db-master-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}:db:db-master-1" + ) + assert result[0].resource_tags == [] + + @mock_aws + def test_rds_mariadb_instance_with_iam_auth(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_parameter_group( + DBParameterGroupName="test", + DBParameterGroupFamily="default.mariadb", + Description="test parameter group", + ) + conn.create_db_instance( + DBInstanceIdentifier="db-master-1", + AllocatedStorage=10, + Engine="mariadb", + DBName="staging-mariadb", + DBInstanceClass="db.m1.small", + EnableIAMDatabaseAuthentication=True, + DBParameterGroupName="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_instance_iam_authentication_enabled.rds_instance_iam_authentication_enabled.rds_client", + new=RDS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.rds.rds_instance_iam_authentication_enabled.rds_instance_iam_authentication_enabled import ( + rds_instance_iam_authentication_enabled, + ) + + check = rds_instance_iam_authentication_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "RDS Instance db-master-1 has IAM authentication enabled." + ) + assert result[0].resource_id == "db-master-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}:db:db-master-1" + ) + assert result[0].resource_tags == [] + + @mock_aws + def test_rds_sqlserver_instance(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_parameter_group( + DBParameterGroupName="test", + DBParameterGroupFamily="default.sqlserver18", + Description="test parameter group", + ) + conn.create_db_instance( + DBInstanceIdentifier="db-master-1", + AllocatedStorage=10, + Engine="sqlserver-ee", + DBName="staging-sqlserver", + DBInstanceClass="db.m1.small", + DBParameterGroupName="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_instance_iam_authentication_enabled.rds_instance_iam_authentication_enabled.rds_client", + new=RDS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.rds.rds_instance_iam_authentication_enabled.rds_instance_iam_authentication_enabled import ( + rds_instance_iam_authentication_enabled, + ) + + check = rds_instance_iam_authentication_enabled() + result = check.execute() + + assert len(result) == 0 + + @mock_aws + def test_rds_aurora_postgres_clustered_without_iam_auth(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_parameter_group( + DBParameterGroupName="test", + DBParameterGroupFamily="default.aurora-postgresql14", + Description="test parameter group", + ) + conn.create_db_cluster( + DBClusterIdentifier="db-cluster-1", + AllocatedStorage=10, + Engine="aurora-postgresql", + DatabaseName="staging-postgres", + DeletionProtection=True, + DBClusterParameterGroupName="test", + MasterUsername="test", + MasterUserPassword="password", + Tags=[], + ) + 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_iam_authentication_enabled.rds_instance_iam_authentication_enabled.rds_client", + new=RDS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.rds.rds_instance_iam_authentication_enabled.rds_instance_iam_authentication_enabled import ( + rds_instance_iam_authentication_enabled, + ) + + check = rds_instance_iam_authentication_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "RDS Cluster db-cluster-1 does not have IAM authentication enabled." + ) + 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 == [] + + @mock_aws + def test_rds_aurora_mysql_clustered_without_iam_auth(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_parameter_group( + DBParameterGroupName="test", + DBParameterGroupFamily="default.mysql8.0", + Description="test parameter group", + ) + conn.create_db_cluster( + DBClusterIdentifier="db-cluster-1", + AllocatedStorage=10, + Engine="aurora-mysql", + DatabaseName="staging-mysql", + DeletionProtection=True, + DBClusterParameterGroupName="test", + MasterUsername="test", + MasterUserPassword="password", + Tags=[], + ) + 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_iam_authentication_enabled.rds_instance_iam_authentication_enabled.rds_client", + new=RDS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.rds.rds_instance_iam_authentication_enabled.rds_instance_iam_authentication_enabled import ( + rds_instance_iam_authentication_enabled, + ) + + check = rds_instance_iam_authentication_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "RDS Cluster db-cluster-1 does not have IAM authentication enabled." + ) + 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 == [] diff --git a/tests/providers/aws/services/rds/rds_instance_multi_az/rds_instance_multi_az_test.py b/tests/providers/aws/services/rds/rds_instance_multi_az/rds_instance_multi_az_test.py index ca5718cea5..ae51ec62e4 100644 --- a/tests/providers/aws/services/rds/rds_instance_multi_az/rds_instance_multi_az_test.py +++ b/tests/providers/aws/services/rds/rds_instance_multi_az/rds_instance_multi_az_test.py @@ -163,6 +163,9 @@ class Test_rds_instance_multi_az: deletion_protection=False, parameter_group="", multi_az=True, + username="test", + iam_auth=False, + backtrack=0, region=AWS_REGION_US_EAST_1, tags=[], ) @@ -183,6 +186,8 @@ class Test_rds_instance_multi_az: deletion_protection=False, parameter_group=[], multi_az=False, + username="test", + iam_auth=False, cluster_id="test-cluster", cluster_arn=cluster_arn, region=AWS_REGION_US_EAST_1, @@ -240,6 +245,9 @@ class Test_rds_instance_multi_az: deletion_protection=False, parameter_group="", multi_az=False, + username="test", + iam_auth=False, + backtrack=0, region=AWS_REGION_US_EAST_1, tags=[], ) @@ -260,6 +268,8 @@ class Test_rds_instance_multi_az: deletion_protection=False, parameter_group=[], multi_az=False, + username="test", + iam_auth=False, cluster_id="test-cluster", cluster_arn=cluster_arn, region=AWS_REGION_US_EAST_1, diff --git a/tests/providers/aws/services/rds/rds_snapshots_encrypted/rds_snapshots_encrypted_test.py b/tests/providers/aws/services/rds/rds_snapshots_encrypted/rds_snapshots_encrypted_test.py new file mode 100644 index 0000000000..748bdace13 --- /dev/null +++ b/tests/providers/aws/services/rds/rds_snapshots_encrypted/rds_snapshots_encrypted_test.py @@ -0,0 +1,251 @@ +from unittest import mock + +import botocore +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, +) + +make_api_call = botocore.client.BaseClient._make_api_call + + +def mock_make_api_call(self, operation_name, kwarg): + if operation_name == "DescribeDBEngineVersions": + return { + "DBEngineVersions": [ + { + "Engine": "mysql", + "EngineVersion": "8.0.32", + "DBEngineDescription": "description", + "DBEngineVersionDescription": "description", + }, + ] + } + return make_api_call(self, operation_name, kwarg) + + +class Test_rds_snapshots_encrypted: + @mock_aws + @mock.patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call) + def test_rds_no_snapshots(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_snapshots_encrypted.rds_snapshots_encrypted.rds_client", + new=RDS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.rds.rds_snapshots_encrypted.rds_snapshots_encrypted import ( + rds_snapshots_encrypted, + ) + + check = rds_snapshots_encrypted() + result = check.execute() + + assert len(result) == 0 + + @mock_aws + @mock.patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call) + def test_rds_snapshot_not_encrypted(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", + ) + + conn.create_db_snapshot( + DBInstanceIdentifier="db-primary-1", DBSnapshotIdentifier="snapshot-1" + ) + + 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_snapshots_encrypted.rds_snapshots_encrypted.rds_client", + new=RDS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.rds.rds_snapshots_encrypted.rds_snapshots_encrypted import ( + rds_snapshots_encrypted, + ) + + check = rds_snapshots_encrypted() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "RDS Instance Snapshot snapshot-1 is not encrypted." + ) + assert result[0].resource_id == "snapshot-1" + + @mock_aws + @mock.patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call) + def test_rds_snapshot_encrypted(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", + ) + + conn.create_db_snapshot( + DBInstanceIdentifier="db-primary-1", DBSnapshotIdentifier="snapshot-1" + ) + + 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_snapshots_encrypted.rds_snapshots_encrypted.rds_client", + new=RDS(aws_provider), + ) as service_client: + # Test Check + from prowler.providers.aws.services.rds.rds_snapshots_encrypted.rds_snapshots_encrypted import ( + rds_snapshots_encrypted, + ) + + service_client.db_snapshots[0].encrypted = True + check = rds_snapshots_encrypted() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "RDS Instance Snapshot snapshot-1 is encrypted." + ) + assert result[0].resource_id == "snapshot-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}:snapshot:snapshot-1" + ) + assert result[0].resource_tags == [] + + @mock_aws + @mock.patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call) + def test_rds_cluster_snapshot_encrypted(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_cluster( + DBClusterIdentifier="db-primary-1", + AllocatedStorage=10, + Engine="postgres", + DBClusterInstanceClass="db.m1.small", + MasterUsername="root", + MasterUserPassword="hunter2000", + ) + + conn.create_db_cluster_snapshot( + DBClusterIdentifier="db-primary-1", DBClusterSnapshotIdentifier="snapshot-1" + ) + 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_snapshots_encrypted.rds_snapshots_encrypted.rds_client", + new=RDS(aws_provider), + ) as service_client: + # Test Check + from prowler.providers.aws.services.rds.rds_snapshots_encrypted.rds_snapshots_encrypted import ( + rds_snapshots_encrypted, + ) + + service_client.db_cluster_snapshots[0].encrypted = True + check = rds_snapshots_encrypted() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "RDS Cluster Snapshot snapshot-1 is encrypted." + ) + assert result[0].resource_id == "snapshot-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-snapshot:snapshot-1" + ) + assert result[0].resource_tags == [] + + @mock_aws + @mock.patch("botocore.client.BaseClient._make_api_call", new=mock_make_api_call) + def test_rds_cluster_snapshot_not_encrypted(self): + conn = client("rds", region_name=AWS_REGION_US_EAST_1) + conn.create_db_cluster( + DBClusterIdentifier="db-primary-1", + AllocatedStorage=10, + Engine="postgres", + DBClusterInstanceClass="db.m1.small", + MasterUsername="root", + MasterUserPassword="hunter2000", + ) + + conn.create_db_cluster_snapshot( + DBClusterIdentifier="db-primary-1", DBClusterSnapshotIdentifier="snapshot-1" + ) + 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_snapshots_encrypted.rds_snapshots_encrypted.rds_client", + new=RDS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.rds.rds_snapshots_encrypted.rds_snapshots_encrypted import ( + rds_snapshots_encrypted, + ) + + check = rds_snapshots_encrypted() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "RDS Cluster Snapshot snapshot-1 is not encrypted." + ) + assert result[0].resource_id == "snapshot-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-snapshot:snapshot-1" + ) + assert result[0].resource_tags == []