refactor(arn): fine tune arn and resources id for unknown values (#5841)

This commit is contained in:
Pedro Martín
2024-11-20 12:56:51 +01:00
committed by GitHub
parent b06e549d81
commit 096749a455
13 changed files with 95 additions and 48 deletions
+14 -10
View File
@@ -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 --> `<root_account>`
- 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_name>:{service_client.region}:{service_client.audited_account}:<resource_type>"`
- 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 cant get the ARN from the resource audited, we create a valid ARN with the `resource_id` part as the resource audited. Examples:
- Bedrock -> `arn:<partition>:bedrock:<region>:<account-id>:model-invocation-logging`
- DirectConnect -> `arn:<partition>:directconnect:<region>:<account-id>:dxcon`
- If there is no real resource to audit we do the following:
- resource_id -> `resource_type/unknown`
- resource_arn -> `arn:<partition>:<service>:<region>:<account-id>:<resource_type>/unknown`
- Examples:
- AWS Security Hub -> `arn:<partition>:security-hub:<region>:<account-id>:hub/unknown`
- Access Analyzer -> `arn:<partition>:access-analyzer:<region>:<account-id>:analyzer/unknown`
- GuardDuty -> `arn:<partition>:guardduty:<region>:<account-id>:detector/unknown`
- GCP
- Resource ID -- `report.resource_id`
- GCP Resource --> Resource ID
+5 -4
View File
@@ -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"
@@ -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"
@@ -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="",
@@ -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)
)
@@ -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)
)
@@ -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,
)
@@ -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="",
@@ -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"
)
@@ -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
@@ -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"
@@ -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"
@@ -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"}]