diff --git a/docs/developer-guide/checks.md b/docs/developer-guide/checks.md index e0545781cd..a48545bb34 100644 --- a/docs/developer-guide/checks.md +++ b/docs/developer-guide/checks.md @@ -160,16 +160,20 @@ else: All the checks MUST fill the `report.resource_id` and `report.resource_arn` with the following criteria: - AWS - - Resource ID -- `report.resource_id` - - AWS Account --> Account Number `123456789012` - - AWS Resource --> Resource ID / Name - - Root resource --> `` - - Unknown resource --> `unknown` - - Resource ARN -- `report.resource_arn` - - AWS Account --> Root ARN `arn:aws:iam::123456789012:root` - - AWS Resource --> Resource ARN - - Root resource --> Resource Type ARN `f"arn:{service_client.audited_partition}::{service_client.region}:{service_client.audited_account}:"` - - Unknown Resource --> `arn:{service_client.audited_partition}:{service_name}:{service_client.region}:{service_client.audited_account}:unknown` + - Resouce ID and resource ARN: + - If the resource audited is the AWS account: + - `resource_id` -> AWS Account Number + - `resource_arn` -> AWS Account Root ARN + - If we can’t get the ARN from the resource audited, we create a valid ARN with the `resource_id` part as the resource audited. Examples: + - Bedrock -> `arn::bedrock:::model-invocation-logging` + - DirectConnect -> `arn::directconnect:::dxcon` + - If there is no real resource to audit we do the following: + - resource_id -> `resource_type/unknown` + - resource_arn -> `arn:::::/unknown` + - Examples: + - AWS Security Hub -> `arn::security-hub:::hub/unknown` + - Access Analyzer -> `arn::access-analyzer:::analyzer/unknown` + - GuardDuty -> `arn::guardduty:::detector/unknown` - GCP - Resource ID -- `report.resource_id` - GCP Resource --> Resource ID diff --git a/prowler/providers/aws/lib/service/service.py b/prowler/providers/aws/lib/service/service.py index e2cec05fd0..2444bf0b25 100644 --- a/prowler/providers/aws/lib/service/service.py +++ b/prowler/providers/aws/lib/service/service.py @@ -102,15 +102,16 @@ class AWSService: # Handle exceptions if necessary pass # Replace 'pass' with any additional exception handling logic. Currently handled within the called function - def get_unknown_arn(self, region: str = None) -> str: + def get_unknown_arn(self, resource_type: str = None, region: str = None) -> str: """ Generate an unknown ARN for the service Args: region (str): The region to get the unknown ARN for. + resource_type (str): The resource type to get the unknown ARN for Returns: str: The unknown ARN for the region. Examples: - >>> service.get_unknown_arn("us-east-1") - "arn:aws:service:us-east-1:0123456789012:unknown" + >>> service.get_unknown_arn(resource_type="bucket", region="us-east-1") + arn:aws:s3:us-east-1:123456789012:bucket/unknown """ - return f"arn:{self.audited_partition}:{self.service}:{f'{region}' if region else ''}:{self.audited_account}:unknown" + return f"arn:{self.audited_partition}:{self.service}:{f'{region}' if region else ''}:{self.audited_account}:{f'{resource_type}/' if resource_type else ''}unknown" diff --git a/prowler/providers/aws/services/accessanalyzer/accessanalyzer_enabled/accessanalyzer_enabled.py b/prowler/providers/aws/services/accessanalyzer/accessanalyzer_enabled/accessanalyzer_enabled.py index 3c5516aabe..52bb65184e 100644 --- a/prowler/providers/aws/services/accessanalyzer/accessanalyzer_enabled/accessanalyzer_enabled.py +++ b/prowler/providers/aws/services/accessanalyzer/accessanalyzer_enabled/accessanalyzer_enabled.py @@ -22,7 +22,7 @@ class accessanalyzer_enabled(Check): else: if analyzer.status == "NOT_AVAILABLE": report.status = "FAIL" - report.status_extended = f"IAM Access Analyzer in account {analyzer.name} is not enabled." + report.status_extended = f"IAM Access Analyzer in account {accessanalyzer_client.audited_account} is not enabled." else: report.status = "FAIL" diff --git a/prowler/providers/aws/services/accessanalyzer/accessanalyzer_service.py b/prowler/providers/aws/services/accessanalyzer/accessanalyzer_service.py index e33fb1838d..f3f2ac1d81 100644 --- a/prowler/providers/aws/services/accessanalyzer/accessanalyzer_service.py +++ b/prowler/providers/aws/services/accessanalyzer/accessanalyzer_service.py @@ -43,8 +43,10 @@ class AccessAnalyzer(AWSService): if analyzer_count == 0: self.analyzers.append( Analyzer( - arn=self.get_unknown_arn(regional_client.region), - name="unknown", + arn=self.get_unknown_arn( + region=regional_client.region, resource_type="analyzer" + ), + name="analyzer/unknown", status="NOT_AVAILABLE", tags=[], type="", diff --git a/prowler/providers/aws/services/bedrock/bedrock_model_invocation_logging_enabled/bedrock_model_invocation_logging_enabled.py b/prowler/providers/aws/services/bedrock/bedrock_model_invocation_logging_enabled/bedrock_model_invocation_logging_enabled.py index 4a48e8f66d..d28c392209 100644 --- a/prowler/providers/aws/services/bedrock/bedrock_model_invocation_logging_enabled/bedrock_model_invocation_logging_enabled.py +++ b/prowler/providers/aws/services/bedrock/bedrock_model_invocation_logging_enabled/bedrock_model_invocation_logging_enabled.py @@ -8,7 +8,7 @@ class bedrock_model_invocation_logging_enabled(Check): for region, logging in bedrock_client.logging_configurations.items(): report = Check_Report_AWS(self.metadata()) report.region = region - report.resource_id = "unknown" + report.resource_id = "model-invocation-logging" report.resource_arn = ( bedrock_client._get_model_invocation_logging_arn_template(region) ) diff --git a/prowler/providers/aws/services/bedrock/bedrock_model_invocation_logs_encryption_enabled/bedrock_model_invocation_logs_encryption_enabled.py b/prowler/providers/aws/services/bedrock/bedrock_model_invocation_logs_encryption_enabled/bedrock_model_invocation_logs_encryption_enabled.py index 6c85a68632..e3cbb28644 100644 --- a/prowler/providers/aws/services/bedrock/bedrock_model_invocation_logs_encryption_enabled/bedrock_model_invocation_logs_encryption_enabled.py +++ b/prowler/providers/aws/services/bedrock/bedrock_model_invocation_logs_encryption_enabled/bedrock_model_invocation_logs_encryption_enabled.py @@ -13,7 +13,7 @@ class bedrock_model_invocation_logs_encryption_enabled(Check): cloudwatch_encryption = True report = Check_Report_AWS(self.metadata()) report.region = region - report.resource_id = "unknown" + report.resource_id = "model-invocation-logging" report.resource_arn = ( bedrock_client._get_model_invocation_logging_arn_template(region) ) diff --git a/prowler/providers/aws/services/guardduty/guardduty_service.py b/prowler/providers/aws/services/guardduty/guardduty_service.py index c3569bc1bc..f67f0881e6 100644 --- a/prowler/providers/aws/services/guardduty/guardduty_service.py +++ b/prowler/providers/aws/services/guardduty/guardduty_service.py @@ -42,8 +42,10 @@ class GuardDuty(AWSService): if not detectors: self.detectors.append( Detector( - id="unknown", - arn=self.get_unknown_arn(regional_client.region), + id="detector/unknown", + arn=self.get_unknown_arn( + region=regional_client.region, resource_type="detector" + ), region=regional_client.region, enabled_in_account=False, ) diff --git a/prowler/providers/aws/services/securityhub/securityhub_service.py b/prowler/providers/aws/services/securityhub/securityhub_service.py index 6ff57e3363..3485113571 100644 --- a/prowler/providers/aws/services/securityhub/securityhub_service.py +++ b/prowler/providers/aws/services/securityhub/securityhub_service.py @@ -27,8 +27,10 @@ class SecurityHub(AWSService): if e.response["Error"]["Code"] == "InvalidAccessException": self.securityhubs.append( SecurityHubHub( - arn=self.audited_account_arn, - id="unknown", + arn=self.get_unknown_arn( + region=regional_client.region, resource_type="hub" + ), + id="hub/unknown", status="NOT_AVAILABLE", standards="", integrations="", @@ -73,8 +75,10 @@ class SecurityHub(AWSService): # SecurityHub is filtered self.securityhubs.append( SecurityHubHub( - arn=self.get_unknown_arn(regional_client.region), - id="unknown", + arn=self.get_unknown_arn( + region=regional_client.region, resource_type="hub" + ), + id="hub/unknown", status="NOT_AVAILABLE", standards="", integrations="", diff --git a/tests/providers/aws/lib/service/service_test.py b/tests/providers/aws/lib/service/service_test.py index e2eb29d631..8269c663f5 100644 --- a/tests/providers/aws/lib/service/service_test.py +++ b/tests/providers/aws/lib/service/service_test.py @@ -121,3 +121,34 @@ class TestAWSService: service.get_unknown_arn() == f"arn:aws:{service_name}::{AWS_ACCOUNT_NUMBER}:unknown" ) + + def test_AWSService_get_unknown_arn_resource_type_set(self): + service_name = "s3" + provider = set_mocked_aws_provider() + service = AWSService(service_name, provider) + + assert ( + service.get_unknown_arn(resource_type="bucket") + == f"arn:aws:{service_name}::{AWS_ACCOUNT_NUMBER}:bucket/unknown" + ) + + def test_AWSService_get_unknown_arn_resource_type_set_cn_partition(self): + service_name = "s3" + provider = set_mocked_aws_provider() + service = AWSService(service_name, provider) + service.audited_partition = "aws-cn" + + assert ( + service.get_unknown_arn(resource_type="bucket") + == f"arn:{service.audited_partition}:{service_name}::{AWS_ACCOUNT_NUMBER}:bucket/unknown" + ) + + def test_AWSService_get_unknown_arn_resource_type_set_region(self): + service_name = "s3" + provider = set_mocked_aws_provider() + service = AWSService(service_name, provider) + + assert ( + service.get_unknown_arn(region="eu-west-1", resource_type="bucket") + == f"arn:aws:{service_name}:eu-west-1:{AWS_ACCOUNT_NUMBER}:bucket/unknown" + ) diff --git a/tests/providers/aws/services/accessanalyzer/accessanalyzer_enabled/accessanalyzer_enabled_test.py b/tests/providers/aws/services/accessanalyzer/accessanalyzer_enabled/accessanalyzer_enabled_test.py index f8a6bf3fd3..c6c4d29656 100644 --- a/tests/providers/aws/services/accessanalyzer/accessanalyzer_enabled/accessanalyzer_enabled_test.py +++ b/tests/providers/aws/services/accessanalyzer/accessanalyzer_enabled/accessanalyzer_enabled_test.py @@ -126,12 +126,12 @@ class Test_accessanalyzer_enabled: accessanalyzer_client.audited_partition = "aws" accessanalyzer_client.audited_account = AWS_ACCOUNT_NUMBER accessanalyzer_client.get_unknown_arn = ( - lambda x: f"arn:aws:accessanalyzer:{x}:{AWS_ACCOUNT_NUMBER}:unknown" + lambda x: f"arn:aws:accessanalyzer:{x}:{AWS_ACCOUNT_NUMBER}:analyzer/unknown" ) accessanalyzer_client.analyzers = [ Analyzer( - arn=AWS_ACCOUNT_ARN, - name=AWS_ACCOUNT_NUMBER, + arn=f"arn:aws:accessanalyzer:{AWS_REGION_1}:{AWS_ACCOUNT_NUMBER}:analyzer/unknown", + name="analyzer/unknown", status="NOT_AVAILABLE", tags=[], type="", @@ -153,7 +153,7 @@ class Test_accessanalyzer_enabled: new=accessanalyzer_client, ), mock.patch( "prowler.providers.aws.services.accessanalyzer.accessanalyzer_service.AccessAnalyzer.get_unknown_arn", - return_value="arn:aws:accessanalyzer:eu-west-1:123456789012:unknown", + return_value="arn:aws:accessanalyzer:eu-west-1:123456789012:analyzer/unknown", ): # Test Check from prowler.providers.aws.services.accessanalyzer.accessanalyzer_enabled.accessanalyzer_enabled import ( @@ -170,8 +170,11 @@ class Test_accessanalyzer_enabled: result[0].status_extended == f"IAM Access Analyzer in account {AWS_ACCOUNT_NUMBER} is not enabled." ) - assert result[0].resource_id == "123456789012" - assert result[0].resource_arn == "arn:aws:iam::123456789012:root" + assert result[0].resource_id == "analyzer/unknown" + assert ( + result[0].resource_arn + == "arn:aws:accessanalyzer:eu-west-1:123456789012:analyzer/unknown" + ) assert result[0].resource_tags == [] assert result[0].region == AWS_REGION_1 diff --git a/tests/providers/aws/services/bedrock/bedrock_model_invocation_logging_enabled/bedrock_model_invocation_logging_enabled_test.py b/tests/providers/aws/services/bedrock/bedrock_model_invocation_logging_enabled/bedrock_model_invocation_logging_enabled_test.py index b41e741d0f..bcf819a7ec 100644 --- a/tests/providers/aws/services/bedrock/bedrock_model_invocation_logging_enabled/bedrock_model_invocation_logging_enabled_test.py +++ b/tests/providers/aws/services/bedrock/bedrock_model_invocation_logging_enabled/bedrock_model_invocation_logging_enabled_test.py @@ -39,7 +39,7 @@ class Test_bedrock_model_invocation_logging_enabled: result[0].status_extended == "Bedrock Model Invocation Logging is disabled." ) - assert result[0].resource_id == "unknown" + assert result[0].resource_id == "model-invocation-logging" assert ( result[0].resource_arn == f"arn:aws:bedrock:{result[0].region}:123456789012:model-invocation-logging" @@ -50,7 +50,7 @@ class Test_bedrock_model_invocation_logging_enabled: result[1].status_extended == "Bedrock Model Invocation Logging is disabled." ) - assert result[1].resource_id == "unknown" + assert result[1].resource_id == "model-invocation-logging" assert ( result[1].resource_arn == f"arn:aws:bedrock:{result[1].region}:123456789012:model-invocation-logging" @@ -99,7 +99,7 @@ class Test_bedrock_model_invocation_logging_enabled: result[0].status_extended == "Bedrock Model Invocation Logging is enabled in CloudWatch Log Group: Test and S3 Bucket: testconfigbucket." ) - assert result[0].resource_id == "unknown" + assert result[0].resource_id == "model-invocation-logging" assert ( result[0].resource_arn == "arn:aws:bedrock:us-east-1:123456789012:model-invocation-logging" @@ -142,7 +142,7 @@ class Test_bedrock_model_invocation_logging_enabled: result[0].status_extended == "Bedrock Model Invocation Logging is enabled in S3 Bucket: testconfigbucket." ) - assert result[0].resource_id == "unknown" + assert result[0].resource_id == "model-invocation-logging" assert ( result[0].resource_arn == "arn:aws:bedrock:us-east-1:123456789012:model-invocation-logging" @@ -186,7 +186,7 @@ class Test_bedrock_model_invocation_logging_enabled: result[0].status_extended == "Bedrock Model Invocation Logging is enabled in CloudWatch Log Group: Test." ) - assert result[0].resource_id == "unknown" + assert result[0].resource_id == "model-invocation-logging" assert ( result[0].resource_arn == "arn:aws:bedrock:us-east-1:123456789012:model-invocation-logging" diff --git a/tests/providers/aws/services/bedrock/bedrock_model_invocation_logs_encryption_enabled/bedrock_model_invocation_logs_encryption_enabled_test.py b/tests/providers/aws/services/bedrock/bedrock_model_invocation_logs_encryption_enabled/bedrock_model_invocation_logs_encryption_enabled_test.py index eb96b19701..74db1e4635 100644 --- a/tests/providers/aws/services/bedrock/bedrock_model_invocation_logs_encryption_enabled/bedrock_model_invocation_logs_encryption_enabled_test.py +++ b/tests/providers/aws/services/bedrock/bedrock_model_invocation_logs_encryption_enabled/bedrock_model_invocation_logs_encryption_enabled_test.py @@ -91,7 +91,7 @@ class Test_bedrock_model_invocation_logs_encryption_enabled: result[0].status_extended == "Bedrock Model Invocation logs are not encrypted in S3 bucket: testconfigbucket and CloudWatch Log Group: Test." ) - assert result[0].resource_id == "unknown" + assert result[0].resource_id == "model-invocation-logging" assert ( result[0].resource_arn == "arn:aws:bedrock:us-east-1:123456789012:model-invocation-logging" @@ -144,7 +144,7 @@ class Test_bedrock_model_invocation_logs_encryption_enabled: result[0].status_extended == "Bedrock Model Invocation logs are not encrypted in S3 bucket: testconfigbucket." ) - assert result[0].resource_id == "unknown" + assert result[0].resource_id == "model-invocation-logging" assert ( result[0].resource_arn == "arn:aws:bedrock:us-east-1:123456789012:model-invocation-logging" @@ -199,7 +199,7 @@ class Test_bedrock_model_invocation_logs_encryption_enabled: result[0].status_extended == "Bedrock Model Invocation logs are not encrypted in CloudWatch Log Group: Test." ) - assert result[0].resource_id == "unknown" + assert result[0].resource_id == "model-invocation-logging" assert ( result[0].resource_arn == "arn:aws:bedrock:us-east-1:123456789012:model-invocation-logging" @@ -274,7 +274,7 @@ class Test_bedrock_model_invocation_logs_encryption_enabled: result[0].status_extended == "Bedrock Model Invocation logs are encrypted." ) - assert result[0].resource_id == "unknown" + assert result[0].resource_id == "model-invocation-logging" assert ( result[0].resource_arn == "arn:aws:bedrock:us-east-1:123456789012:model-invocation-logging" @@ -340,7 +340,7 @@ class Test_bedrock_model_invocation_logs_encryption_enabled: result[0].status_extended == "Bedrock Model Invocation logs are encrypted." ) - assert result[0].resource_id == "unknown" + assert result[0].resource_id == "model-invocation-logging" assert ( result[0].resource_arn == "arn:aws:bedrock:us-east-1:123456789012:model-invocation-logging" @@ -395,7 +395,7 @@ class Test_bedrock_model_invocation_logs_encryption_enabled: result[0].status_extended == "Bedrock Model Invocation logs are encrypted." ) - assert result[0].resource_id == "unknown" + assert result[0].resource_id == "model-invocation-logging" assert ( result[0].resource_arn == "arn:aws:bedrock:us-east-1:123456789012:model-invocation-logging" diff --git a/tests/providers/aws/services/securityhub/securityhub_enabled/securityhub_enabled_test.py b/tests/providers/aws/services/securityhub/securityhub_enabled/securityhub_enabled_test.py index 6215bdb418..a34e784ac3 100644 --- a/tests/providers/aws/services/securityhub/securityhub_enabled/securityhub_enabled_test.py +++ b/tests/providers/aws/services/securityhub/securityhub_enabled/securityhub_enabled_test.py @@ -11,12 +11,12 @@ class Test_securityhub_enabled: securityhub_client = mock.MagicMock securityhub_client.region = AWS_REGION_EU_WEST_1 securityhub_client.get_unknown_arn = ( - lambda x: f"arn:aws:securityhub:{x}:0123456789012:unknown" + lambda x: f"arn:aws:securityhub:{x}:0123456789012:hub/unknown" ) securityhub_client.securityhubs = [ SecurityHubHub( - arn=f"arn:aws:securityhub:{AWS_REGION_EU_WEST_1}:0123456789012:unknown", - id="Security Hub", + arn=f"arn:aws:securityhub:{AWS_REGION_EU_WEST_1}:0123456789012:hub/unknown", + id="hub/unknown", status="NOT_AVAILABLE", standards="", integrations="", @@ -29,7 +29,7 @@ class Test_securityhub_enabled: new=securityhub_client, ), mock.patch( "prowler.providers.aws.services.securityhub.securityhub_service.SecurityHub.get_unknown_arn", - return_value="arn:aws:securityhub:eu-west-1:0123456789012:unknown", + return_value="arn:aws:securityhub:eu-west-1:0123456789012:hub/unknown", ): # Test Check from prowler.providers.aws.services.securityhub.securityhub_enabled.securityhub_enabled import ( @@ -41,10 +41,10 @@ class Test_securityhub_enabled: assert result[0].status == "FAIL" assert result[0].status_extended == "Security Hub is not enabled." - assert result[0].resource_id == "Security Hub" + assert result[0].resource_id == "hub/unknown" assert ( result[0].resource_arn - == "arn:aws:securityhub:eu-west-1:0123456789012:unknown" + == "arn:aws:securityhub:eu-west-1:0123456789012:hub/unknown" ) assert result[0].region == AWS_REGION_EU_WEST_1 assert result[0].resource_tags == [{"test_key": "test_value"}]