diff --git a/prowler/providers/aws/services/dms/dms_endpoint_neptune_iam_authorization_enabled/__init__.py b/prowler/providers/aws/services/dms/dms_endpoint_neptune_iam_authorization_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/dms/dms_endpoint_neptune_iam_authorization_enabled/dms_endpoint_neptune_iam_authorization_enabled.metadata.json b/prowler/providers/aws/services/dms/dms_endpoint_neptune_iam_authorization_enabled/dms_endpoint_neptune_iam_authorization_enabled.metadata.json new file mode 100644 index 0000000000..45471a9268 --- /dev/null +++ b/prowler/providers/aws/services/dms/dms_endpoint_neptune_iam_authorization_enabled/dms_endpoint_neptune_iam_authorization_enabled.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "aws", + "CheckID": "dms_endpoint_neptune_iam_authorization_enabled", + "CheckTitle": "Check if DMS endpoints for Neptune databases have IAM authorization enabled.", + "CheckType": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "ServiceName": "dms", + "SubServiceName": "", + "ResourceIdTemplate": "arn:aws:dms:region:account-id:endpoint/endpoint-id", + "Severity": "medium", + "ResourceType": "AwsDmsEndpoint", + "Description": "This control checks whether an AWS DMS endpoint for an Amazon Neptune database is configured with IAM authorization. The control fails if the DMS endpoint doesn't have IAM authorization enabled.", + "Risk": "Without IAM authorization, DMS endpoints for Neptune databases may lack granular access control, increasing the risk of unauthorized access to sensitive data.", + "RelatedUrl": "https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Neptune.html", + "Remediation": { + "Code": { + "CLI": "aws dms modify-endpoint --endpoint-arn --service-access-role-arn ", + "NativeIaC": "", + "Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/dms-controls.html#dms-10", + "Terraform": "" + }, + "Recommendation": { + "Text": "Enable IAM authorization on DMS endpoints for Neptune databases by specifying a service role in the ServiceAccessRoleARN parameter.", + "Url": "https://docs.aws.amazon.com/dms/latest/userguide/CHAP_Target.Neptune.html" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/aws/services/dms/dms_endpoint_neptune_iam_authorization_enabled/dms_endpoint_neptune_iam_authorization_enabled.py b/prowler/providers/aws/services/dms/dms_endpoint_neptune_iam_authorization_enabled/dms_endpoint_neptune_iam_authorization_enabled.py new file mode 100644 index 0000000000..e66e033284 --- /dev/null +++ b/prowler/providers/aws/services/dms/dms_endpoint_neptune_iam_authorization_enabled/dms_endpoint_neptune_iam_authorization_enabled.py @@ -0,0 +1,41 @@ +from typing import List + +from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.dms.dms_client import dms_client + + +class dms_endpoint_neptune_iam_authorization_enabled(Check): + """ + Check if AWS DMS Endpoints for Neptune have IAM authorization enabled. + + This class verifies whether each AWS DMS Endpoint configured for Neptune has IAM authorization enabled + by checking the `NeptuneSettings.IamAuthEnabled` property in the endpoint's configuration. + """ + + def execute(self) -> List[Check_Report_AWS]: + """ + Execute the DMS Neptune IAM authorization enabled check. + + Iterates over all DMS Endpoints and generates a report indicating whether + each Neptune endpoint has IAM authorization enabled. + + Returns: + List[Check_Report_AWS]: A list of report objects with the results of the check. + """ + findings = [] + for endpoint_arn, endpoint in dms_client.endpoints.items(): + if endpoint.engine_name == "neptune": + report = Check_Report_AWS(self.metadata()) + report.resource_id = endpoint.id + report.resource_arn = endpoint_arn + report.region = endpoint.region + report.resource_tags = endpoint.tags + report.status = "FAIL" + report.status_extended = f"DMS Endpoint {endpoint.id} for Neptune databases does not have IAM authorization enabled." + if endpoint.neptune_iam_auth_enabled: + report.status = "PASS" + report.status_extended = f"DMS Endpoint {endpoint.id} for Neptune databases has IAM authorization enabled." + + findings.append(report) + + return findings diff --git a/prowler/providers/aws/services/dms/dms_service.py b/prowler/providers/aws/services/dms/dms_service.py index a424c23037..27ec105ea3 100644 --- a/prowler/providers/aws/services/dms/dms_service.py +++ b/prowler/providers/aws/services/dms/dms_service.py @@ -71,6 +71,10 @@ class DMS(AWSService): id=endpoint["EndpointIdentifier"], region=regional_client.region, ssl_mode=endpoint.get("SslMode", False), + neptune_iam_auth_enabled=endpoint.get( + "NeptuneSettings", {} + ).get("IamAuthEnabled", False), + engine_name=endpoint["EngineName"], ) except Exception as error: logger.error( @@ -94,6 +98,8 @@ class Endpoint(BaseModel): region: str ssl_mode: str tags: Optional[list] + neptune_iam_auth_enabled: bool = False + engine_name: str class RepInstance(BaseModel): @@ -106,4 +112,4 @@ class RepInstance(BaseModel): security_groups: list[str] = [] multi_az: bool region: str - tags: Optional[list] + tags: Optional[list] = [] diff --git a/tests/providers/aws/services/dms/dms_endpoint_neptune_iam_authorization_enabled/dms_endpoint_neptune_iam_authorization_enabled_test.py b/tests/providers/aws/services/dms/dms_endpoint_neptune_iam_authorization_enabled/dms_endpoint_neptune_iam_authorization_enabled_test.py new file mode 100644 index 0000000000..ee9316b0dd --- /dev/null +++ b/tests/providers/aws/services/dms/dms_endpoint_neptune_iam_authorization_enabled/dms_endpoint_neptune_iam_authorization_enabled_test.py @@ -0,0 +1,271 @@ +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 + +DMS_ENDPOINT_NAME = "dms-endpoint" +DMS_ENDPOINT_ARN = f"arn:aws:dms:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:endpoint:{DMS_ENDPOINT_NAME}" +DMS_INSTANCE_NAME = "rep-instance" +DMS_INSTANCE_ARN = ( + f"arn:aws:dms:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:rep:{DMS_INSTANCE_NAME}" +) + + +def mock_make_api_call_enabled_not_neptune(self, operation_name, kwarg): + if operation_name == "DescribeEndpoints": + return { + "Endpoints": [ + { + "EndpointIdentifier": DMS_ENDPOINT_NAME, + "EndpointArn": DMS_ENDPOINT_ARN, + "SslMode": "require", + "NeptuneSettings": { + "IamAuthEnabled": True, + }, + "EngineName": "oracle", + } + ] + } + elif operation_name == "ListTagsForResource": + if kwarg["ResourceArn"] == DMS_INSTANCE_ARN: + return { + "TagList": [ + {"Key": "Name", "Value": "rep-instance"}, + {"Key": "Owner", "Value": "admin"}, + ] + } + elif kwarg["ResourceArn"] == DMS_ENDPOINT_ARN: + return { + "TagList": [ + {"Key": "Name", "Value": "dms-endpoint"}, + {"Key": "Owner", "Value": "admin"}, + ] + } + return make_api_call(self, operation_name, kwarg) + + +def mock_make_api_call_enabled(self, operation_name, kwarg): + if operation_name == "DescribeEndpoints": + return { + "Endpoints": [ + { + "EndpointIdentifier": DMS_ENDPOINT_NAME, + "EndpointArn": DMS_ENDPOINT_ARN, + "SslMode": "require", + "NeptuneSettings": { + "IamAuthEnabled": True, + }, + "EngineName": "neptune", + } + ] + } + elif operation_name == "ListTagsForResource": + if kwarg["ResourceArn"] == DMS_INSTANCE_ARN: + return { + "TagList": [ + {"Key": "Name", "Value": "rep-instance"}, + {"Key": "Owner", "Value": "admin"}, + ] + } + elif kwarg["ResourceArn"] == DMS_ENDPOINT_ARN: + return { + "TagList": [ + {"Key": "Name", "Value": "dms-endpoint"}, + {"Key": "Owner", "Value": "admin"}, + ] + } + return make_api_call(self, operation_name, kwarg) + + +def mock_make_api_call_not_enabled(self, operation_name, kwarg): + if operation_name == "DescribeEndpoints": + return { + "Endpoints": [ + { + "EndpointIdentifier": DMS_ENDPOINT_NAME, + "EndpointArn": DMS_ENDPOINT_ARN, + "SslMode": "require", + "NeptuneSettings": { + "IamAuthEnabled": False, + }, + "EngineName": "neptune", + } + ] + } + elif operation_name == "ListTagsForResource": + if kwarg["ResourceArn"] == DMS_INSTANCE_ARN: + return { + "TagList": [ + {"Key": "Name", "Value": "rep-instance"}, + {"Key": "Owner", "Value": "admin"}, + ] + } + elif kwarg["ResourceArn"] == DMS_ENDPOINT_ARN: + return { + "TagList": [ + {"Key": "Name", "Value": "dms-endpoint"}, + {"Key": "Owner", "Value": "admin"}, + ] + } + return make_api_call(self, operation_name, kwarg) + + +class Test_dms_endpoint_neptune_iam_authorization_enabled: + @mock_aws + def test_no_dms_endpoints(self): + dms_client = client("dms", region_name=AWS_REGION_US_EAST_1) + dms_client.endpoints = {} + + from prowler.providers.aws.services.dms.dms_service import DMS + + 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, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_endpoint_neptune_iam_authorization_enabled.dms_endpoint_neptune_iam_authorization_enabled.dms_client", + new=DMS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.dms.dms_endpoint_neptune_iam_authorization_enabled.dms_endpoint_neptune_iam_authorization_enabled import ( + dms_endpoint_neptune_iam_authorization_enabled, + ) + + check = dms_endpoint_neptune_iam_authorization_enabled() + result = check.execute() + + assert len(result) == 0 + + @mock_aws + def test_dms_not_neptune_iam_auth_enabled(self): + with mock.patch( + "botocore.client.BaseClient._make_api_call", + new=mock_make_api_call_enabled_not_neptune, + ): + + from prowler.providers.aws.services.dms.dms_service import DMS + + 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, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_endpoint_neptune_iam_authorization_enabled.dms_endpoint_neptune_iam_authorization_enabled.dms_client", + new=DMS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.dms.dms_endpoint_neptune_iam_authorization_enabled.dms_endpoint_neptune_iam_authorization_enabled import ( + dms_endpoint_neptune_iam_authorization_enabled, + ) + + check = dms_endpoint_neptune_iam_authorization_enabled() + result = check.execute() + + assert len(result) == 0 + + @mock_aws + def test_dms_neptune_iam_auth_not_enabled(self): + with mock.patch( + "botocore.client.BaseClient._make_api_call", + new=mock_make_api_call_not_enabled, + ): + + from prowler.providers.aws.services.dms.dms_service import DMS + + 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, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_endpoint_neptune_iam_authorization_enabled.dms_endpoint_neptune_iam_authorization_enabled.dms_client", + new=DMS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.dms.dms_endpoint_neptune_iam_authorization_enabled.dms_endpoint_neptune_iam_authorization_enabled import ( + dms_endpoint_neptune_iam_authorization_enabled, + ) + + check = dms_endpoint_neptune_iam_authorization_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert result[0].status_extended == ( + "DMS Endpoint dms-endpoint for Neptune databases does not have IAM authorization enabled." + ) + assert result[0].resource_id == "dms-endpoint" + assert ( + result[0].resource_arn + == "arn:aws:dms:us-east-1:123456789012:endpoint:dms-endpoint" + ) + assert result[0].resource_tags == [ + { + "Key": "Name", + "Value": "dms-endpoint", + }, + { + "Key": "Owner", + "Value": "admin", + }, + ] + assert result[0].region == "us-east-1" + + @mock_aws + def test_dms_neptune_iam_auth_enabled(self): + with mock.patch( + "botocore.client.BaseClient._make_api_call", + new=mock_make_api_call_enabled, + ): + + from prowler.providers.aws.services.dms.dms_service import DMS + + 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, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_endpoint_neptune_iam_authorization_enabled.dms_endpoint_neptune_iam_authorization_enabled.dms_client", + new=DMS(aws_provider), + ): + # Test Check + from prowler.providers.aws.services.dms.dms_endpoint_neptune_iam_authorization_enabled.dms_endpoint_neptune_iam_authorization_enabled import ( + dms_endpoint_neptune_iam_authorization_enabled, + ) + + check = dms_endpoint_neptune_iam_authorization_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert result[0].status_extended == ( + "DMS Endpoint dms-endpoint for Neptune databases has IAM authorization enabled." + ) + assert result[0].resource_id == "dms-endpoint" + assert ( + result[0].resource_arn + == "arn:aws:dms:us-east-1:123456789012:endpoint:dms-endpoint" + ) + assert result[0].resource_tags == [ + { + "Key": "Name", + "Value": "dms-endpoint", + }, + { + "Key": "Owner", + "Value": "admin", + }, + ] + assert result[0].region == "us-east-1" diff --git a/tests/providers/aws/services/dms/dms_endpoint_ssl_enabled_test/dms_endpoint_ssl_enabled_test.py b/tests/providers/aws/services/dms/dms_endpoint_ssl_enabled_test/dms_endpoint_ssl_enabled_test.py index 4d4f087fce..f9cd64921c 100644 --- a/tests/providers/aws/services/dms/dms_endpoint_ssl_enabled_test/dms_endpoint_ssl_enabled_test.py +++ b/tests/providers/aws/services/dms/dms_endpoint_ssl_enabled_test/dms_endpoint_ssl_enabled_test.py @@ -12,6 +12,9 @@ class Test_dms_endpoint_ssl_enabled: with mock.patch( "prowler.providers.aws.services.dms.dms_service.DMS", new=dms_client, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_client.dms_client", + new=dms_client, ): from prowler.providers.aws.services.dms.dms_endpoint_ssl_enabled.dms_endpoint_ssl_enabled import ( dms_endpoint_ssl_enabled, @@ -28,6 +31,7 @@ class Test_dms_endpoint_ssl_enabled: endpoint_arn: Endpoint( arn=endpoint_arn, id="test-endpoint-no-ssl", + engine_name="test-engine", region=AWS_REGION_US_EAST_1, ssl_mode="none", tags=[{"Key": "Name", "Value": "test-endpoint-no-ssl"}], @@ -40,6 +44,9 @@ class Test_dms_endpoint_ssl_enabled: with mock.patch( "prowler.providers.aws.services.dms.dms_service.DMS", new=dms_client, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_client.dms_client", + new=dms_client, ): from prowler.providers.aws.services.dms.dms_endpoint_ssl_enabled.dms_endpoint_ssl_enabled import ( dms_endpoint_ssl_enabled, @@ -71,6 +78,7 @@ class Test_dms_endpoint_ssl_enabled: endpoint_arn: Endpoint( arn=endpoint_arn, id="test-endpoint-ssl-require", + engine_name="test-engine", region=AWS_REGION_US_EAST_1, ssl_mode="require", tags=[{"Key": "Name", "Value": "test-endpoint-ssl-require"}], @@ -83,6 +91,9 @@ class Test_dms_endpoint_ssl_enabled: with mock.patch( "prowler.providers.aws.services.dms.dms_service.DMS", new=dms_client, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_client.dms_client", + new=dms_client, ): from prowler.providers.aws.services.dms.dms_endpoint_ssl_enabled.dms_endpoint_ssl_enabled import ( dms_endpoint_ssl_enabled, @@ -111,6 +122,7 @@ class Test_dms_endpoint_ssl_enabled: endpoint_arn: Endpoint( arn=endpoint_arn, id="test-endpoint-ssl-verify-ca", + engine_name="test-engine", region=AWS_REGION_US_EAST_1, ssl_mode="verify-ca", tags=[{"Key": "Name", "Value": "test-endpoint-ssl-verify-ca"}], @@ -123,6 +135,9 @@ class Test_dms_endpoint_ssl_enabled: with mock.patch( "prowler.providers.aws.services.dms.dms_service.DMS", new=dms_client, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_client.dms_client", + new=dms_client, ): from prowler.providers.aws.services.dms.dms_endpoint_ssl_enabled.dms_endpoint_ssl_enabled import ( dms_endpoint_ssl_enabled, @@ -151,6 +166,7 @@ class Test_dms_endpoint_ssl_enabled: endpoint_arn: Endpoint( arn=endpoint_arn, id="test-endpoint-ssl-verify-full", + engine_name="test-engine", region=AWS_REGION_US_EAST_1, ssl_mode="verify-full", tags=[{"Key": "Name", "Value": "test-endpoint-ssl-verify-full"}], @@ -163,6 +179,9 @@ class Test_dms_endpoint_ssl_enabled: with mock.patch( "prowler.providers.aws.services.dms.dms_service.DMS", new=dms_client, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_client.dms_client", + new=dms_client, ): from prowler.providers.aws.services.dms.dms_endpoint_ssl_enabled.dms_endpoint_ssl_enabled import ( dms_endpoint_ssl_enabled, diff --git a/tests/providers/aws/services/dms/dms_instance_minor_version_upgrade_enabled/dms_instance_minor_version_upgrade_enabled_test.py b/tests/providers/aws/services/dms/dms_instance_minor_version_upgrade_enabled/dms_instance_minor_version_upgrade_enabled_test.py index 1022a54bbd..b5a9c98716 100644 --- a/tests/providers/aws/services/dms/dms_instance_minor_version_upgrade_enabled/dms_instance_minor_version_upgrade_enabled_test.py +++ b/tests/providers/aws/services/dms/dms_instance_minor_version_upgrade_enabled/dms_instance_minor_version_upgrade_enabled_test.py @@ -18,6 +18,9 @@ class Test_dms_instance_minor_version_upgrade_enabled: with mock.patch( "prowler.providers.aws.services.dms.dms_service.DMS", new=dms_client, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_client.dms_client", + new=dms_client, ): from prowler.providers.aws.services.dms.dms_instance_minor_version_upgrade_enabled.dms_instance_minor_version_upgrade_enabled import ( dms_instance_minor_version_upgrade_enabled, @@ -47,6 +50,9 @@ class Test_dms_instance_minor_version_upgrade_enabled: with mock.patch( "prowler.providers.aws.services.dms.dms_service.DMS", new=dms_client, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_client.dms_client", + new=dms_client, ): from prowler.providers.aws.services.dms.dms_instance_minor_version_upgrade_enabled.dms_instance_minor_version_upgrade_enabled import ( dms_instance_minor_version_upgrade_enabled, @@ -87,6 +93,9 @@ class Test_dms_instance_minor_version_upgrade_enabled: with mock.patch( "prowler.providers.aws.services.dms.dms_service.DMS", new=dms_client, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_client.dms_client", + new=dms_client, ): from prowler.providers.aws.services.dms.dms_instance_minor_version_upgrade_enabled.dms_instance_minor_version_upgrade_enabled import ( dms_instance_minor_version_upgrade_enabled, diff --git a/tests/providers/aws/services/dms/dms_instance_multi_az/dms_instance_multi_az_test.py b/tests/providers/aws/services/dms/dms_instance_multi_az/dms_instance_multi_az_test.py index 3ba0c3befc..86ce420427 100644 --- a/tests/providers/aws/services/dms/dms_instance_multi_az/dms_instance_multi_az_test.py +++ b/tests/providers/aws/services/dms/dms_instance_multi_az/dms_instance_multi_az_test.py @@ -18,6 +18,9 @@ class Test_dms_instance_multi_az: with mock.patch( "prowler.providers.aws.services.dms.dms_service.DMS", new=dms_client, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_client.dms_client", + new=dms_client, ): from prowler.providers.aws.services.dms.dms_instance_multi_az_enabled.dms_instance_multi_az_enabled import ( dms_instance_multi_az_enabled, @@ -47,6 +50,9 @@ class Test_dms_instance_multi_az: with mock.patch( "prowler.providers.aws.services.dms.dms_service.DMS", new=dms_client, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_client.dms_client", + new=dms_client, ): from prowler.providers.aws.services.dms.dms_instance_multi_az_enabled.dms_instance_multi_az_enabled import ( dms_instance_multi_az_enabled, @@ -87,6 +93,9 @@ class Test_dms_instance_multi_az: with mock.patch( "prowler.providers.aws.services.dms.dms_service.DMS", new=dms_client, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_client.dms_client", + new=dms_client, ): from prowler.providers.aws.services.dms.dms_instance_multi_az_enabled.dms_instance_multi_az_enabled import ( dms_instance_multi_az_enabled, diff --git a/tests/providers/aws/services/dms/dms_instance_no_public_access/dms_no_public_access_test.py b/tests/providers/aws/services/dms/dms_instance_no_public_access/dms_no_public_access_test.py index 82e54bbda3..0b9a5209c5 100644 --- a/tests/providers/aws/services/dms/dms_instance_no_public_access/dms_no_public_access_test.py +++ b/tests/providers/aws/services/dms/dms_instance_no_public_access/dms_no_public_access_test.py @@ -1,5 +1,6 @@ from unittest import mock +import botocore from boto3 import client from moto import mock_aws @@ -16,62 +17,91 @@ DMS_INSTANCE_ARN = ( ) KMS_KEY_ID = f"arn:aws:kms:{AWS_REGION_US_EAST_1}:{AWS_ACCOUNT_NUMBER}:key/abcdabcd-1234-abcd-1234-abcdabcdabcd" +make_api_call = botocore.client.BaseClient._make_api_call + + +def mock_make_api_call_public(self, operation_name, kwargs): + if operation_name == "DescribeReplicationInstances": + return { + "ReplicationInstances": [ + { + "ReplicationInstanceIdentifier": DMS_INSTANCE_NAME, + "ReplicationInstanceStatus": "available", + "AutoMinorVersionUpgrade": True, + "PubliclyAccessible": True, + "ReplicationInstanceArn": DMS_INSTANCE_ARN, + "MultiAZ": True, + "VpcSecurityGroups": [], + "KmsKeyId": KMS_KEY_ID, + }, + ] + } + + return make_api_call(self, operation_name, kwargs) + + +def mock_make_api_call_private(self, operation_name, kwargs): + if operation_name == "DescribeReplicationInstances": + return { + "ReplicationInstances": [ + { + "ReplicationInstanceIdentifier": DMS_INSTANCE_NAME, + "ReplicationInstanceStatus": "available", + "AutoMinorVersionUpgrade": True, + "PubliclyAccessible": False, + "ReplicationInstanceArn": DMS_INSTANCE_ARN, + "MultiAZ": True, + "VpcSecurityGroups": [], + "KmsKeyId": KMS_KEY_ID, + }, + ] + } + + return make_api_call(self, operation_name, kwargs) + class Test_dms_instance_no_public_access: + @mock_aws def test_dms_no_instances(self): - dms_client = mock.MagicMock + dms_client = client("dms", region_name=AWS_REGION_US_EAST_1) dms_client.instances = [] - from prowler.providers.aws.services.ec2.ec2_service import EC2 - aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + from prowler.providers.aws.services.dms.dms_service import DMS + with mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_instance_no_public_access.dms_instance_no_public_access.dms_client", + new=DMS(aws_provider), ): - with mock.patch( - "prowler.providers.aws.services.dms.dms_service.DMS", - new=dms_client, - ), mock.patch( - "prowler.providers.aws.services.rds.rds_instance_no_public_access.rds_instance_no_public_access.ec2_client", - new=EC2(aws_provider), - ): - from prowler.providers.aws.services.dms.dms_instance_no_public_access.dms_instance_no_public_access import ( - dms_instance_no_public_access, - ) - - check = dms_instance_no_public_access() - result = check.execute() - assert len(result) == 0 - - def test_dms_private(self): - dms_client = mock.MagicMock - dms_client.instances = [] - dms_client.instances.append( - RepInstance( - id=DMS_INSTANCE_NAME, - arn=DMS_INSTANCE_ARN, - status="available", - public=False, - security_groups=[], - kms_key=KMS_KEY_ID, - auto_minor_version_upgrade=False, - multi_az=False, - region=AWS_REGION_US_EAST_1, - tags=[{"Key": "Name", "Value": DMS_INSTANCE_NAME}], + from prowler.providers.aws.services.dms.dms_instance_no_public_access.dms_instance_no_public_access import ( + dms_instance_no_public_access, ) - ) - aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + check = dms_instance_no_public_access() + result = check.execute() + assert len(result) == 0 + @mock_aws + def test_dms_private(self): with mock.patch( - "prowler.providers.common.provider.Provider.get_global_provider", - return_value=aws_provider, + "botocore.client.BaseClient._make_api_call", + new=mock_make_api_call_private, ): + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + from prowler.providers.aws.services.dms.dms_service import DMS + with mock.patch( - "prowler.providers.aws.services.dms.dms_service.DMS", - new=dms_client, + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_instance_no_public_access.dms_instance_no_public_access.dms_client", + new=DMS(aws_provider), ): from prowler.providers.aws.services.dms.dms_instance_no_public_access.dms_instance_no_public_access import ( dms_instance_no_public_access, @@ -88,40 +118,25 @@ class Test_dms_instance_no_public_access: assert result[0].region == AWS_REGION_US_EAST_1 assert result[0].resource_id == DMS_INSTANCE_NAME assert result[0].resource_arn == DMS_INSTANCE_ARN - assert result[0].resource_tags == [ - { - "Key": "Name", - "Value": DMS_INSTANCE_NAME, - } - ] + assert result[0].resource_tags == [] + @mock_aws def test_dms_public(self): - dms_client = mock.MagicMock - dms_client.instances = [] - dms_client.instances.append( - RepInstance( - id=DMS_INSTANCE_NAME, - arn=DMS_INSTANCE_ARN, - status="available", - public=True, - security_groups=[], - kms_key=KMS_KEY_ID, - auto_minor_version_upgrade=False, - multi_az=False, - region=AWS_REGION_US_EAST_1, - tags=[{"Key": "Name", "Value": DMS_INSTANCE_NAME}], - ) - ) - - 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, + "botocore.client.BaseClient._make_api_call", + new=mock_make_api_call_public, ): + + aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) + + from prowler.providers.aws.services.dms.dms_service import DMS + with mock.patch( - "prowler.providers.aws.services.dms.dms_service.DMS", - new=dms_client, + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_instance_no_public_access.dms_instance_no_public_access.dms_client", + new=DMS(aws_provider), ): from prowler.providers.aws.services.dms.dms_instance_no_public_access.dms_instance_no_public_access import ( dms_instance_no_public_access, @@ -138,12 +153,7 @@ class Test_dms_instance_no_public_access: assert result[0].region == AWS_REGION_US_EAST_1 assert result[0].resource_id == DMS_INSTANCE_NAME assert result[0].resource_arn == DMS_INSTANCE_ARN - assert result[0].resource_tags == [ - { - "Key": "Name", - "Value": DMS_INSTANCE_NAME, - } - ] + assert result[0].resource_tags == [] @mock_aws def test_dms_public_with_public_sg(self): @@ -163,6 +173,7 @@ class Test_dms_instance_no_public_access: ], ) dms_client = mock.MagicMock + dms_client = mock.MagicMock() dms_client.instances = [] dms_client.instances.append( RepInstance( @@ -178,20 +189,21 @@ class Test_dms_instance_no_public_access: tags=[{"Key": "Name", "Value": DMS_INSTANCE_NAME}], ) ) - from prowler.providers.aws.services.ec2.ec2_service import EC2 aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) aws_provider.audit_metadata.expected_checks = [ "ec2_securitygroup_allow_ingress_from_internet_to_any_port" ] - with mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", return_value=aws_provider, ): with mock.patch( - "prowler.providers.aws.services.dms.dms_service.DMS", + "prowler.providers.aws.services.dms.dms_instance_no_public_access.dms_instance_no_public_access.dms_client", + new=dms_client, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_client.dms_client", new=dms_client, ), mock.patch( "prowler.providers.aws.services.dms.dms_instance_no_public_access.dms_instance_no_public_access.ec2_client", @@ -204,7 +216,6 @@ class Test_dms_instance_no_public_access: check = dms_instance_no_public_access() result = check.execute() - assert len(result) == 1 assert result[0].status == "FAIL" assert ( @@ -254,20 +265,21 @@ class Test_dms_instance_no_public_access: tags=[{"Key": "Name", "Value": DMS_INSTANCE_NAME}], ) ) - from prowler.providers.aws.services.ec2.ec2_service import EC2 aws_provider = set_mocked_aws_provider([AWS_REGION_US_EAST_1]) aws_provider.audit_metadata.expected_checks = [ "ec2_securitygroup_allow_ingress_from_internet_to_any_port" ] - with mock.patch( "prowler.providers.common.provider.Provider.get_global_provider", return_value=aws_provider, ): with mock.patch( - "prowler.providers.aws.services.dms.dms_service.DMS", + "prowler.providers.aws.services.dms.dms_instance_no_public_access.dms_instance_no_public_access.dms_client", + new=dms_client, + ), mock.patch( + "prowler.providers.aws.services.dms.dms_client.dms_client", new=dms_client, ), mock.patch( "prowler.providers.aws.services.dms.dms_instance_no_public_access.dms_instance_no_public_access.ec2_client", @@ -280,7 +292,6 @@ class Test_dms_instance_no_public_access: check = dms_instance_no_public_access() result = check.execute() - assert len(result) == 1 assert result[0].status == "PASS" assert ( diff --git a/tests/providers/aws/services/dms/dms_service_test.py b/tests/providers/aws/services/dms/dms_service_test.py index 7a13e8a872..e89311406c 100644 --- a/tests/providers/aws/services/dms/dms_service_test.py +++ b/tests/providers/aws/services/dms/dms_service_test.py @@ -44,6 +44,10 @@ def mock_make_api_call(self, operation_name, kwargs): "EndpointIdentifier": DMS_ENDPOINT_NAME, "EndpointArn": DMS_ENDPOINT_ARN, "SslMode": "require", + "NeptuneSettings": { + "IamAuthEnabled": True, + }, + "EngineName": "neptune", } ] } @@ -121,6 +125,8 @@ class Test_DMS_Service: assert len(dms.endpoints) == 1 assert dms.endpoints[DMS_ENDPOINT_ARN].id == DMS_ENDPOINT_NAME assert dms.endpoints[DMS_ENDPOINT_ARN].ssl_mode == "require" + assert dms.endpoints[DMS_ENDPOINT_ARN].neptune_iam_auth_enabled + assert dms.endpoints[DMS_ENDPOINT_ARN].engine_name == "neptune" def test_list_tags(self): aws_provider = set_mocked_aws_provider()