Skip to content

Commit a83096d

Browse files
committed
awssecurityhub: introduce support for 'Security Hub', 'IAM Access Analyzer', 'Health', 'Config' products. fail if unsupported one is imported
1 parent 2206535 commit a83096d

File tree

5 files changed

+233
-1
lines changed

5 files changed

+233
-1
lines changed
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from dojo.models import Finding
2+
3+
4+
class Config:
5+
def get_item(self, finding: dict, test):
6+
finding_id = finding.get("Id", "")
7+
title = finding.get("Title", "")
8+
severity = finding.get("Severity", {}).get("Label", "INFORMATIONAL").title()
9+
resource_arns = [arn for resource in finding.get("Resources", [])
10+
if (arn := resource.get("Id"))]
11+
impact = []
12+
unsaved_vulnerability_ids = []
13+
epss_score = None
14+
description = "This is a Config Finding \n" + finding.get("Description", "") + "\n"
15+
description += f"**AWS Finding ARN:** {finding_id}\n"
16+
description += f"**Resource IDs:** {', '.join(set(resource_arns))}\n"
17+
description += f"**AwsAccountId:** {finding.get('AwsAccountId', '')}\n"
18+
if finding.get("Region"):
19+
description += f"**Region:** {finding.get('Region', '')}\n"
20+
description += f"**Generator ID:** {finding.get('GeneratorId', '')}\n"
21+
title_suffix = ""
22+
for resource in finding.get("Resources", []):
23+
component_name = resource.get("Type")
24+
resource_id = resource["Id"].split(":")[-1]
25+
impact.append(f"Resource: {resource_id}")
26+
title_suffix = f" - Resource: {resource_id}"
27+
false_p = False
28+
result = Finding(
29+
title=f"{title}{title_suffix}",
30+
test=test,
31+
description=description,
32+
severity=severity,
33+
impact="\n".join(impact),
34+
verified=False,
35+
false_p=false_p,
36+
unique_id_from_tool=finding_id,
37+
static_finding=True,
38+
dynamic_finding=False,
39+
component_name=component_name,
40+
)
41+
if epss_score is not None:
42+
result.epss_score = epss_score
43+
# Add the unsaved vulnerability ids
44+
result.unsaved_vulnerability_ids = unsaved_vulnerability_ids
45+
return result
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import datetime
2+
3+
from dojo.models import Finding
4+
5+
6+
class Health:
7+
def get_item(self, finding: dict, test):
8+
finding_id = finding.get("Id", "")
9+
title = finding.get("Title", "")
10+
severity = finding.get("Severity", {}).get("Label", "INFORMATIONAL").title()
11+
resource_arns = [arn for resource in finding.get("Resources", [])
12+
if (arn := resource.get("Id"))]
13+
impact = []
14+
references = []
15+
unsaved_vulnerability_ids = []
16+
epss_score = None
17+
description = "This is a Health Finding \n" + finding.get("Description", "") + "\n"
18+
description += f"**AWS Finding ARN:** {finding_id}\n"
19+
description += f"**Resource IDs:** {', '.join(set(resource_arns))}\n"
20+
description += f"**AwsAccountId:** {finding.get('AwsAccountId', '')}\n"
21+
if finding.get("Region"):
22+
description += f"**Region:** {finding.get('Region', '')}\n"
23+
description += f"**Generator ID:** {finding.get('GeneratorId', '')}\n"
24+
title_suffix = ""
25+
for resource in finding.get("Resources", []):
26+
component_name = resource.get("Type")
27+
resource_id = resource["Id"].split(":")[-1]
28+
impact.append(f"Resource: {resource_id}")
29+
title_suffix = f" - Resource: {resource_id}"
30+
references.append((finding.get("SourceUrl", "") or ""))
31+
false_p = False
32+
result = Finding(
33+
title=f"{title}{title_suffix}",
34+
test=test,
35+
description=description,
36+
references="\n".join(references),
37+
severity=severity,
38+
impact="\n".join(impact),
39+
verified=False,
40+
false_p=false_p,
41+
unique_id_from_tool=finding_id,
42+
static_finding=True,
43+
dynamic_finding=False,
44+
component_name=component_name,
45+
)
46+
if epss_score is not None:
47+
result.epss_score = epss_score
48+
# Add the unsaved vulnerability ids
49+
result.unsaved_vulnerability_ids = unsaved_vulnerability_ids
50+
return result
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from dojo.models import Finding
2+
3+
4+
class IamAccessAnalyzer:
5+
def get_item(self, finding: dict, test):
6+
finding_id = finding.get("Id", "")
7+
title = finding.get("Title", "")
8+
severity = finding.get("Severity", {}).get("Label", "INFORMATIONAL").title()
9+
resource_arns = [arn for resource in finding.get("Resources", [])
10+
if (arn := resource.get("Id"))]
11+
impact = []
12+
references = []
13+
unsaved_vulnerability_ids = []
14+
epss_score = None
15+
mitigation = finding.get("Remediation", {}).get("Recommendation", {}).get("Text", "")
16+
mitigation += "\n" + (finding.get("Remediation", {}).get("Recommendation", {}).get("Url", "") or "")
17+
description = "This is an IAM Access Analyzer Finding \n" + finding.get("Description", "") + "\n"
18+
description += f"**AWS Finding ARN:** {finding_id}\n"
19+
description += f"**Resource IDs:** {', '.join(set(resource_arns))}\n"
20+
description += f"**AwsAccountId:** {finding.get('AwsAccountId', '')}\n"
21+
if finding.get("Region"):
22+
description += f"**Region:** {finding.get('Region', '')}\n"
23+
description += f"**Generator ID:** {finding.get('GeneratorId', '')}\n"
24+
title_suffix = ""
25+
for resource in finding.get("Resources", []):
26+
resource_id = resource["Id"].split(":")[-1]
27+
impact.append(f"Resource: {resource_id}")
28+
title_suffix = f" - Resource: {resource_id}"
29+
if remediation_rec_url := finding.get("Remediation", {}).get("Recommendation", {}).get("Url"):
30+
references.append(remediation_rec_url)
31+
result = Finding(
32+
title=f"{title}{title_suffix}",
33+
test=test,
34+
description=description,
35+
mitigation=mitigation,
36+
references="\n".join(references),
37+
severity=severity,
38+
impact="\n".join(impact),
39+
active=True,
40+
verified=False,
41+
false_p=False,
42+
unique_id_from_tool=finding_id,
43+
is_mitigated=False,
44+
static_finding=True,
45+
dynamic_finding=False,
46+
)
47+
if epss_score is not None:
48+
result.epss_score = epss_score
49+
# Add the unsaved vulnerability ids
50+
result.unsaved_vulnerability_ids = unsaved_vulnerability_ids
51+
return result

dojo/tools/awssecurityhub/parser.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import json
22

33
from dojo.tools.awssecurityhub.compliance import Compliance
4+
from dojo.tools.awssecurityhub.config import Config
45
from dojo.tools.awssecurityhub.guardduty import GuardDuty
6+
from dojo.tools.awssecurityhub.iam_access_analyzer import IamAccessAnalyzer
57
from dojo.tools.awssecurityhub.inspector import Inspector
8+
from dojo.tools.awssecurityhub.health import Health
9+
from dojo.tools.awssecurityhub.securityhub import SecurityHub
610
from dojo.tools.parser_test import ParserTest
711

812

@@ -57,8 +61,19 @@ def get_items(self, tree: dict, test):
5761
item = Inspector().get_item(node, test)
5862
elif aws_scanner_type == "GuardDuty":
5963
item = GuardDuty().get_item(node, test)
60-
else:
64+
elif aws_scanner_type == "Compliance":
6165
item = Compliance().get_item(node, test)
66+
elif aws_scanner_type == "IAM Access Analyzer":
67+
item = IamAccessAnalyzer().get_item(node, test)
68+
elif aws_scanner_type == "Health":
69+
item = Health().get_item(node, test)
70+
elif aws_scanner_type == "Config":
71+
item = Config().get_item(node, test)
72+
elif aws_scanner_type == "Security Hub":
73+
item = SecurityHub().get_item(node, test)
74+
else:
75+
msg = "Unsupported Security Hub report format"
76+
raise TypeError(msg)
6277
key = node["Id"]
6378
if not isinstance(key, str):
6479
msg = "Incorrect Security Hub report format"
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import datetime
2+
3+
from dojo.models import Finding
4+
5+
6+
class SecurityHub:
7+
def get_item(self, finding: dict, test):
8+
finding_id = finding.get("Id", "")
9+
title = finding.get("Title", "")
10+
severity = finding.get("Severity", {}).get("Label", "INFORMATIONAL").title()
11+
mitigation = ""
12+
impact = []
13+
references = []
14+
unsaved_vulnerability_ids = []
15+
epss_score = None
16+
mitigations = finding.get("FindingProviderFields", {}).get("Types")
17+
for mitigate in mitigations:
18+
mitigation += mitigate + "\n"
19+
active = True
20+
if finding.get("RecordState") == "ACTIVE":
21+
is_Mitigated = False
22+
mitigated = None
23+
else:
24+
is_Mitigated = True
25+
if finding.get("LastObservedAt"):
26+
try:
27+
mitigated = datetime.datetime.strptime(finding.get("LastObservedAt"), "%Y-%m-%dT%H:%M:%S.%fZ")
28+
except Exception:
29+
mitigated = datetime.datetime.strptime(finding.get("LastObservedAt"), "%Y-%m-%dT%H:%M:%fZ")
30+
else:
31+
mitigated = datetime.datetime.now(datetime.UTC)
32+
description = f"This is a Security Hub Finding\n{finding.get('Description', '')}" + "\n"
33+
description += f"**AWS Finding ARN:** {finding_id}\n"
34+
description += f"**AwsAccountId:** {finding.get('AwsAccountId', '')}\n"
35+
description += f"**Region:** {finding.get('Region', '')}\n"
36+
description += f"**Generator ID:** {finding.get('GeneratorId', '')}\n"
37+
title_suffix = ""
38+
hosts = []
39+
for resource in finding.get("Resources", []):
40+
component_name = resource.get("Type")
41+
resource_id = resource["Id"].split(":")[-1]
42+
impact.append(f"Resource: {resource_id}")
43+
title_suffix = f" - Resource: {resource_id}"
44+
if remediation_rec_url := finding.get("Remediation", {}).get("Recommendation", {}).get("Url"):
45+
references.append(remediation_rec_url)
46+
false_p = False
47+
result = Finding(
48+
title=f"{title}{title_suffix}",
49+
test=test,
50+
description=description,
51+
mitigation=mitigation,
52+
references="\n".join(references),
53+
severity=severity,
54+
impact="\n".join(impact),
55+
active=active,
56+
verified=False,
57+
false_p=false_p,
58+
unique_id_from_tool=finding_id,
59+
mitigated=mitigated,
60+
is_mitigated=is_Mitigated,
61+
static_finding=True,
62+
dynamic_finding=False,
63+
component_name=component_name,
64+
)
65+
result.unsaved_endpoints = []
66+
result.unsaved_endpoints.extend(hosts)
67+
if epss_score is not None:
68+
result.epss_score = epss_score
69+
# Add the unsaved vulnerability ids
70+
result.unsaved_vulnerability_ids = unsaved_vulnerability_ids
71+
return result

0 commit comments

Comments
 (0)