diff --git a/permissions/create_role_to_assume_cfn.yaml b/permissions/create_role_to_assume_cfn.yaml index 2c47da5cca..3dd162c3aa 100644 --- a/permissions/create_role_to_assume_cfn.yaml +++ b/permissions/create_role_to_assume_cfn.yaml @@ -82,6 +82,7 @@ Resources: - 'logs:FilterLogEvents' - 'lightsail:GetRelationalDatabases' - 'macie2:GetMacieSession' + - 'macie2:GetAutomatedDiscoveryConfiguration' - 's3:GetAccountPublicAccessBlock' - 'shield:DescribeProtection' - 'shield:GetSubscriptionState' diff --git a/permissions/prowler-additions-policy.json b/permissions/prowler-additions-policy.json index d1c8ea29c1..1a311b2db3 100644 --- a/permissions/prowler-additions-policy.json +++ b/permissions/prowler-additions-policy.json @@ -30,6 +30,7 @@ "logs:FilterLogEvents", "lightsail:GetRelationalDatabases", "macie2:GetMacieSession", + "macie2:GetAutomatedDiscoveryConfiguration", "s3:GetAccountPublicAccessBlock", "shield:DescribeProtection", "shield:GetSubscriptionState", diff --git a/prowler/providers/aws/services/macie/macie_automated_sensitive_data_discovery_enabled/__init__.py b/prowler/providers/aws/services/macie/macie_automated_sensitive_data_discovery_enabled/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/prowler/providers/aws/services/macie/macie_automated_sensitive_data_discovery_enabled/macie_automated_sensitive_data_discovery_enabled.metadata.json b/prowler/providers/aws/services/macie/macie_automated_sensitive_data_discovery_enabled/macie_automated_sensitive_data_discovery_enabled.metadata.json new file mode 100644 index 0000000000..8162d18f73 --- /dev/null +++ b/prowler/providers/aws/services/macie/macie_automated_sensitive_data_discovery_enabled/macie_automated_sensitive_data_discovery_enabled.metadata.json @@ -0,0 +1,32 @@ +{ + "Provider": "aws", + "CheckID": "macie_automated_sensitive_data_discovery_enabled", + "CheckTitle": "Check if Macie automated sensitive data discovery is enabled.", + "CheckType": [ + "Software and Configuration Checks/AWS Security Best Practices" + ], + "ServiceName": "macie", + "SubServiceName": "", + "ResourceIdTemplate": "arn:partition:service:region:account-id:resource-id", + "Severity": "high", + "ResourceType": "AwsAccount", + "Description": "Check if automated sensitive data discovery is enabled for an Amazon Macie account. The control fails if it isn't enabled.", + "Risk": "Without automated sensitive data discovery, there could be delays in identifying sensitive data, leading to data exposure risks in Amazon S3 buckets.", + "RelatedUrl": "https://docs.aws.amazon.com/config/latest/developerguide/macie-auto-sensitive-data-discovery-check.html", + "Remediation": { + "Code": { + "CLI": "aws macie2 update-automated-discovery-configuration --status ENABLED", + "NativeIaC": "", + "Other": "https://docs.aws.amazon.com/securityhub/latest/userguide/macie-controls.html#macie-2", + "Terraform": "" + }, + "Recommendation": { + "Text": "To enable and configure automated sensitive data discovery jobs for S3 buckets, refer to the Configuring automated sensitive data discovery tutorial.", + "Url": "https://docs.aws.amazon.com/macie/latest/user/discovery-asdd-account-enable.html" + } + }, + "Categories": [], + "DependsOn": [], + "RelatedTo": [], + "Notes": "" +} diff --git a/prowler/providers/aws/services/macie/macie_automated_sensitive_data_discovery_enabled/macie_automated_sensitive_data_discovery_enabled.py b/prowler/providers/aws/services/macie/macie_automated_sensitive_data_discovery_enabled/macie_automated_sensitive_data_discovery_enabled.py new file mode 100644 index 0000000000..19abe9104b --- /dev/null +++ b/prowler/providers/aws/services/macie/macie_automated_sensitive_data_discovery_enabled/macie_automated_sensitive_data_discovery_enabled.py @@ -0,0 +1,27 @@ +from prowler.lib.check.models import Check, Check_Report_AWS +from prowler.providers.aws.services.macie.macie_client import macie_client + + +class macie_automated_sensitive_data_discovery_enabled(Check): + def execute(self): + findings = [] + for session in macie_client.sessions: + if session.status == "ENABLED": + report = Check_Report_AWS(self.metadata()) + report.region = session.region + report.resource_arn = macie_client._get_session_arn_template( + session.region + ) + report.resource_id = macie_client.audited_account + report.status = "FAIL" + report.status_extended = "Macie is enabled but it does not have automated sensitive data discovery." + + if session.automated_discovery_status == "ENABLED": + report.status = "PASS" + report.status_extended = ( + "Macie has automated sensitive data discovery enabled." + ) + + findings.append(report) + + return findings diff --git a/prowler/providers/aws/services/macie/macie_service.py b/prowler/providers/aws/services/macie/macie_service.py index 90d55a3e07..9327946c64 100644 --- a/prowler/providers/aws/services/macie/macie_service.py +++ b/prowler/providers/aws/services/macie/macie_service.py @@ -11,6 +11,9 @@ class Macie(AWSService): super().__init__("macie2", provider) self.sessions = [] self.__threading_call__(self._get_macie_session) + self.__threading_call__( + self._get_automated_discovery_configuration, self.sessions + ) def _get_session_arn_template(self, region): return f"arn:{self.audited_partition}:macie:{region}:{self.audited_account}:session" @@ -38,7 +41,24 @@ class Macie(AWSService): f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" ) + def _get_automated_discovery_configuration(self, session): + logger.info("Macie - Get Automated Discovery Configuration...") + try: + if session.status == "ENABLED": + regional_client = self.regional_clients[session.region] + session.automated_discovery_status = ( + regional_client.get_automated_discovery_configuration().get( + "status", "DISABLED" + ) + ) + + except Exception as error: + logger.error( + f"{regional_client.region} -- {error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + class Session(BaseModel): status: str + automated_discovery_status: str = "DISABLED" region: str diff --git a/tests/providers/aws/services/macie/macie_automated_sensitive_data_discovery_enabled/macie_automated_sensitive_data_discovery_enabled_test.py b/tests/providers/aws/services/macie/macie_automated_sensitive_data_discovery_enabled/macie_automated_sensitive_data_discovery_enabled_test.py new file mode 100644 index 0000000000..6b779bfd81 --- /dev/null +++ b/tests/providers/aws/services/macie/macie_automated_sensitive_data_discovery_enabled/macie_automated_sensitive_data_discovery_enabled_test.py @@ -0,0 +1,149 @@ +from unittest import mock + +from moto import mock_aws + +from prowler.providers.aws.services.macie.macie_service import Session +from tests.providers.aws.utils import ( + AWS_ACCOUNT_NUMBER, + AWS_REGION_EU_WEST_1, + set_mocked_aws_provider, +) + + +class Test_macie_automated_sensitive_data_discovery_enabled: + @mock_aws + def test_macie_disabled(self): + + macie_client = mock.MagicMock + macie_client.provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) + macie_client.audited_account = AWS_ACCOUNT_NUMBER + macie_client.audited_account_arn = f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:root" + macie_client.audited_partition = "aws" + macie_client.region = AWS_REGION_EU_WEST_1 + macie_client.sessions = [ + Session( + status="DISABLED", + region="eu-west-1", + automated_discovery_status="DISABLED", + ) + ] + macie_client.session_arn_template = f"arn:{macie_client.audited_partition}:macie:{macie_client.region}:{macie_client.audited_account}:session" + macie_client._get_session_arn_template = mock.MagicMock( + return_value=macie_client.session_arn_template + ) + aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.macie.macie_automated_sensitive_data_discovery_enabled.macie_automated_sensitive_data_discovery_enabled.macie_client", + new=macie_client, + ): + # Test Check + from prowler.providers.aws.services.macie.macie_automated_sensitive_data_discovery_enabled.macie_automated_sensitive_data_discovery_enabled import ( + macie_automated_sensitive_data_discovery_enabled, + ) + + check = macie_automated_sensitive_data_discovery_enabled() + result = check.execute() + + assert len(result) == 0 + + @mock_aws + def test_macie_enabled_automated_discovery_disabled(self): + + macie_client = mock.MagicMock + macie_client.provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) + macie_client.audited_account = AWS_ACCOUNT_NUMBER + macie_client.audited_account_arn = f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:root" + macie_client.audited_partition = "aws" + macie_client.region = AWS_REGION_EU_WEST_1 + macie_client.sessions = [ + Session( + status="ENABLED", + region="eu-west-1", + automated_discovery_status="DISABLED", + ) + ] + macie_client.session_arn_template = f"arn:{macie_client.audited_partition}:macie:{macie_client.region}:{macie_client.audited_account}:session" + macie_client._get_session_arn_template = mock.MagicMock( + return_value=macie_client.session_arn_template + ) + aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.macie.macie_automated_sensitive_data_discovery_enabled.macie_automated_sensitive_data_discovery_enabled.macie_client", + new=macie_client, + ): + # Test Check + from prowler.providers.aws.services.macie.macie_automated_sensitive_data_discovery_enabled.macie_automated_sensitive_data_discovery_enabled import ( + macie_automated_sensitive_data_discovery_enabled, + ) + + check = macie_automated_sensitive_data_discovery_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "FAIL" + assert ( + result[0].status_extended + == "Macie is enabled but it does not have automated sensitive data discovery." + ) + assert result[0].resource_id == AWS_ACCOUNT_NUMBER + assert ( + result[0].resource_arn + == f"arn:aws:macie:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:session" + ) + + @mock_aws + def test_macie_enabled_automated_discovery_enabled(self): + + macie_client = mock.MagicMock + macie_client.provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) + macie_client.audited_account = AWS_ACCOUNT_NUMBER + macie_client.audited_account_arn = f"arn:aws:iam::{AWS_ACCOUNT_NUMBER}:root" + macie_client.audited_partition = "aws" + macie_client.region = AWS_REGION_EU_WEST_1 + macie_client.sessions = [ + Session( + status="ENABLED", + region="eu-west-1", + automated_discovery_status="ENABLED", + ) + ] + macie_client.session_arn_template = f"arn:{macie_client.audited_partition}:macie:{macie_client.region}:{macie_client.audited_account}:session" + macie_client._get_session_arn_template = mock.MagicMock( + return_value=macie_client.session_arn_template + ) + aws_provider = set_mocked_aws_provider([AWS_REGION_EU_WEST_1]) + + with mock.patch( + "prowler.providers.common.provider.Provider.get_global_provider", + return_value=aws_provider, + ), mock.patch( + "prowler.providers.aws.services.macie.macie_automated_sensitive_data_discovery_enabled.macie_automated_sensitive_data_discovery_enabled.macie_client", + new=macie_client, + ): + # Test Check + from prowler.providers.aws.services.macie.macie_automated_sensitive_data_discovery_enabled.macie_automated_sensitive_data_discovery_enabled import ( + macie_automated_sensitive_data_discovery_enabled, + ) + + check = macie_automated_sensitive_data_discovery_enabled() + result = check.execute() + + assert len(result) == 1 + assert result[0].status == "PASS" + assert ( + result[0].status_extended + == "Macie has automated sensitive data discovery enabled." + ) + assert result[0].resource_id == AWS_ACCOUNT_NUMBER + assert ( + result[0].resource_arn + == f"arn:aws:macie:{AWS_REGION_EU_WEST_1}:{AWS_ACCOUNT_NUMBER}:session" + ) diff --git a/tests/providers/aws/services/macie/macie_service_test.py b/tests/providers/aws/services/macie/macie_service_test.py index ff3a7d67a1..d2385d01a4 100644 --- a/tests/providers/aws/services/macie/macie_service_test.py +++ b/tests/providers/aws/services/macie/macie_service_test.py @@ -73,3 +73,18 @@ class Test_Macie_Service: assert len(macie.sessions) == 1 assert macie.sessions[0].status == "ENABLED" assert macie.sessions[0].region == AWS_REGION_EU_WEST_1 + + def test_get_automated_discovery_configuration(self): + # Set partition for the service + macie = Macie(set_mocked_aws_provider([AWS_REGION_EU_WEST_1])) + macie.sessions = [ + Session( + status="ENABLED", + region="eu-west-1", + automated_discovery_status="ENABLED", + ) + ] + assert len(macie.sessions) == 1 + assert macie.sessions[0].status == "ENABLED" + assert macie.sessions[0].region == AWS_REGION_EU_WEST_1 + assert macie.sessions[0].automated_discovery_status == "ENABLED"