From 6558aedee323634cb7bae39dd1d4fd2a09c0dfd5 Mon Sep 17 00:00:00 2001 From: Samuel Burgos <34037255+sbldevnet@users.noreply.github.com> Date: Mon, 2 Oct 2023 18:20:35 +0200 Subject: [PATCH] feat(json-asff): adds AWS resource tags in json-asff and SecurityHub findings (#2786) Co-authored-by: samuel.burgos Co-authored-by: Sergio Garcia --- prowler/lib/outputs/json.py | 22 +++++++++++++++++++ prowler/lib/outputs/models.py | 1 + prowler/lib/outputs/outputs.py | 2 +- .../aws/lib/security_hub/security_hub.py | 4 +++- tests/lib/outputs/outputs_test.py | 12 ++++++++++ 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/prowler/lib/outputs/json.py b/prowler/lib/outputs/json.py index 96b45a82..a7928393 100644 --- a/prowler/lib/outputs/json.py +++ b/prowler/lib/outputs/json.py @@ -63,12 +63,14 @@ def fill_json_asff(finding_output, audit_info, finding, output_options): if len(finding.status_extended) > 1000 else finding.status_extended ) + resource_tags = generate_json_asff_resource_tags(finding.resource_tags) finding_output.Resources = [ Resource( Id=finding.resource_arn, Type=finding.check_metadata.ResourceType, Partition=audit_info.audited_partition, Region=finding.region, + Tags=resource_tags, ) ] # Iterate for each compliance framework @@ -121,6 +123,26 @@ def generate_json_asff_status(status: str) -> str: return json_asff_status +def generate_json_asff_resource_tags(tags): + try: + resource_tags = {} + if tags and tags != [None]: + for tag in tags: + if "Key" in tag and "Value" in tag: + resource_tags[tag["Key"]] = tag["Value"] + else: + resource_tags.update(tag) + if len(resource_tags) == 0: + return None + else: + return None + return resource_tags + except Exception as error: + logger.error( + f"{error.__class__.__name__}[{error.__traceback__.tb_lineno}]: {error}" + ) + + def fill_json_ocsf(audit_info, finding, output_options) -> Check_Output_JSON_OCSF: try: resource_region = "" diff --git a/prowler/lib/outputs/models.py b/prowler/lib/outputs/models.py index 0b461413..47114ecb 100644 --- a/prowler/lib/outputs/models.py +++ b/prowler/lib/outputs/models.py @@ -683,6 +683,7 @@ class Resource(BaseModel): Id: str Partition: str Region: str + Tags: Optional[dict] class Compliance(BaseModel): diff --git a/prowler/lib/outputs/outputs.py b/prowler/lib/outputs/outputs.py index 2b8b23ca..6d4d8fc7 100644 --- a/prowler/lib/outputs/outputs.py +++ b/prowler/lib/outputs/outputs.py @@ -102,7 +102,7 @@ def report(check_findings, output_options, audit_info): ) json.dump( - finding_output.dict(), + finding_output.dict(exclude_none=True), file_descriptors["json-asff"], indent=4, ) diff --git a/prowler/providers/aws/lib/security_hub/security_hub.py b/prowler/providers/aws/lib/security_hub/security_hub.py index dffd6f9f..a5d3ede7 100644 --- a/prowler/providers/aws/lib/security_hub/security_hub.py +++ b/prowler/providers/aws/lib/security_hub/security_hub.py @@ -40,7 +40,9 @@ def prepare_security_hub_findings( ) # Include that finding within their region in the JSON format - security_hub_findings_per_region[region].append(finding_json_asff.dict()) + security_hub_findings_per_region[region].append( + finding_json_asff.dict(exclude_none=True) + ) return security_hub_findings_per_region diff --git a/tests/lib/outputs/outputs_test.py b/tests/lib/outputs/outputs_test.py index e03a782b..aa11f2be 100644 --- a/tests/lib/outputs/outputs_test.py +++ b/tests/lib/outputs/outputs_test.py @@ -28,6 +28,7 @@ from prowler.lib.outputs.json import ( fill_json_asff, fill_json_ocsf, generate_json_asff_status, + generate_json_asff_resource_tags, generate_json_ocsf_severity_id, generate_json_ocsf_status, generate_json_ocsf_status_id, @@ -1349,6 +1350,17 @@ class Test_Outputs: assert generate_json_asff_status("WARNING") == "WARNING" assert generate_json_asff_status("SOMETHING ELSE") == "NOT_AVAILABLE" + def test_generate_json_asff_resource_tags(self): + assert generate_json_asff_resource_tags(None) is None + assert generate_json_asff_resource_tags([]) is None + assert generate_json_asff_resource_tags([{}]) is None + assert generate_json_asff_resource_tags([{"key1": "value1"}]) == { + "key1": "value1" + } + assert generate_json_asff_resource_tags( + [{"Key": "key1", "Value": "value1"}] + ) == {"key1": "value1"} + def test_generate_json_ocsf_status(self): assert generate_json_ocsf_status("PASS") == "Success" assert generate_json_ocsf_status("FAIL") == "Failure"