sraverify 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- sraverify/__init__.py +36 -0
- sraverify/checks/__init__.py +56 -0
- sraverify/checks/accessanalyzer/SRA_IAA_1.py +188 -0
- sraverify/checks/accessanalyzer/SRA_IAA_2.py +162 -0
- sraverify/checks/accessanalyzer/SRA_IAA_3.py +260 -0
- sraverify/checks/accessanalyzer/SRA_IAA_4.py +207 -0
- sraverify/checks/accessanalyzer/__init__.py +3 -0
- sraverify/checks/cloudtrail/SRA-CT-1.py +220 -0
- sraverify/checks/cloudtrail/SRA-CT-10.py +229 -0
- sraverify/checks/cloudtrail/SRA-CT-11.py +242 -0
- sraverify/checks/cloudtrail/SRA-CT-12.py +163 -0
- sraverify/checks/cloudtrail/SRA-CT-13.py +279 -0
- sraverify/checks/cloudtrail/SRA-CT-2.py +218 -0
- sraverify/checks/cloudtrail/SRA-CT-3.py +196 -0
- sraverify/checks/cloudtrail/SRA-CT-4.py +161 -0
- sraverify/checks/cloudtrail/SRA-CT-5.py +200 -0
- sraverify/checks/cloudtrail/SRA-CT-6.py +161 -0
- sraverify/checks/cloudtrail/SRA-CT-7.py +194 -0
- sraverify/checks/cloudtrail/SRA-CT-8.py +226 -0
- sraverify/checks/cloudtrail/SRA-CT-9.py +226 -0
- sraverify/checks/cloudtrail/__init__.py +3 -0
- sraverify/checks/config/SRA-CONFIG-1.py +197 -0
- sraverify/checks/config/__init__.py +3 -0
- sraverify/core/__init__.py +3 -0
- sraverify/core/check.py +227 -0
- sraverify/core/logging.py +37 -0
- sraverify/core/session.py +47 -0
- sraverify/lib/__init__.py +4 -0
- sraverify/lib/audit_info.py +37 -0
- sraverify/lib/banner.py +42 -0
- sraverify/lib/check_loader.py +80 -0
- sraverify/lib/org_mgmt_checker.py +86 -0
- sraverify/lib/outputs.py +46 -0
- sraverify/lib/progress.py +75 -0
- sraverify/lib/regions.py +27 -0
- sraverify/lib/session.py +23 -0
- sraverify/main.py +350 -0
- sraverify/services/__init__.py +3 -0
- sraverify/services/accessanalyzer/__init__.py +15 -0
- sraverify/services/accessanalyzer/base.py +123 -0
- sraverify/services/accessanalyzer/checks/__init__.py +3 -0
- sraverify/services/accessanalyzer/checks/sra_accessanalyzer_01.py +82 -0
- sraverify/services/accessanalyzer/checks/sra_accessanalyzer_02.py +82 -0
- sraverify/services/accessanalyzer/checks/sra_accessanalyzer_03.py +103 -0
- sraverify/services/accessanalyzer/checks/sra_accessanalyzer_04.py +139 -0
- sraverify/services/accessanalyzer/client.py +123 -0
- sraverify/services/account/__init__.py +9 -0
- sraverify/services/account/base.py +56 -0
- sraverify/services/account/checks/__init__.py +1 -0
- sraverify/services/account/checks/sra_account_01.py +65 -0
- sraverify/services/account/checks/sra_account_02.py +63 -0
- sraverify/services/account/checks/sra_account_03.py +63 -0
- sraverify/services/account/client.py +51 -0
- sraverify/services/auditmanager/__init__.py +10 -0
- sraverify/services/auditmanager/base.py +72 -0
- sraverify/services/auditmanager/checks/__init__.py +1 -0
- sraverify/services/auditmanager/checks/sra_auditmanager_01.py +58 -0
- sraverify/services/auditmanager/checks/sra_auditmanager_02.py +80 -0
- sraverify/services/auditmanager/client.py +58 -0
- sraverify/services/cloudtrail/__init__.py +33 -0
- sraverify/services/cloudtrail/base.py +167 -0
- sraverify/services/cloudtrail/checks/__init__.py +1 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_01.py +83 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_02.py +99 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_03.py +94 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_04.py +92 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_05.py +106 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_06.py +93 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_07.py +96 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_08.py +145 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_09.py +167 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_10.py +162 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_11.py +178 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_12.py +77 -0
- sraverify/services/cloudtrail/checks/sra_cloudtrail_13.py +120 -0
- sraverify/services/cloudtrail/client.py +118 -0
- sraverify/services/config/__init__.py +25 -0
- sraverify/services/config/base.py +249 -0
- sraverify/services/config/checks/__init__.py +1 -0
- sraverify/services/config/checks/sra_config_01.py +123 -0
- sraverify/services/config/checks/sra_config_02.py +156 -0
- sraverify/services/config/checks/sra_config_03.py +149 -0
- sraverify/services/config/checks/sra_config_04.py +104 -0
- sraverify/services/config/checks/sra_config_05.py +104 -0
- sraverify/services/config/checks/sra_config_06.py +194 -0
- sraverify/services/config/checks/sra_config_07.py +162 -0
- sraverify/services/config/checks/sra_config_08.py +185 -0
- sraverify/services/config/checks/sra_config_09.py +177 -0
- sraverify/services/config/client.py +264 -0
- sraverify/services/ec2/__init__.py +8 -0
- sraverify/services/ec2/base.py +75 -0
- sraverify/services/ec2/checks/__init__.py +1 -0
- sraverify/services/ec2/checks/sra_ec2_01.py +83 -0
- sraverify/services/ec2/client.py +63 -0
- sraverify/services/firewallmanager/__init__.py +23 -0
- sraverify/services/firewallmanager/base.py +48 -0
- sraverify/services/firewallmanager/checks/__init__.py +1 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_01.py +75 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_02.py +57 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_03.py +51 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_04.py +51 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_05.py +51 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_06.py +51 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_07.py +51 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_08.py +61 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_09.py +61 -0
- sraverify/services/firewallmanager/checks/sra_firewallmanager_10.py +71 -0
- sraverify/services/firewallmanager/client.py +40 -0
- sraverify/services/guardduty/__init__.py +58 -0
- sraverify/services/guardduty/base.py +207 -0
- sraverify/services/guardduty/checks/__init__.py +3 -0
- sraverify/services/guardduty/checks/sra_guardduty_01.py +51 -0
- sraverify/services/guardduty/checks/sra_guardduty_02.py +80 -0
- sraverify/services/guardduty/checks/sra_guardduty_03.py +77 -0
- sraverify/services/guardduty/checks/sra_guardduty_04.py +84 -0
- sraverify/services/guardduty/checks/sra_guardduty_05.py +84 -0
- sraverify/services/guardduty/checks/sra_guardduty_06.py +84 -0
- sraverify/services/guardduty/checks/sra_guardduty_07.py +85 -0
- sraverify/services/guardduty/checks/sra_guardduty_08.py +83 -0
- sraverify/services/guardduty/checks/sra_guardduty_09.py +84 -0
- sraverify/services/guardduty/checks/sra_guardduty_10.py +83 -0
- sraverify/services/guardduty/checks/sra_guardduty_11.py +93 -0
- sraverify/services/guardduty/checks/sra_guardduty_12.py +83 -0
- sraverify/services/guardduty/checks/sra_guardduty_13.py +90 -0
- sraverify/services/guardduty/checks/sra_guardduty_14.py +136 -0
- sraverify/services/guardduty/checks/sra_guardduty_15.py +94 -0
- sraverify/services/guardduty/checks/sra_guardduty_16.py +94 -0
- sraverify/services/guardduty/checks/sra_guardduty_17.py +91 -0
- sraverify/services/guardduty/checks/sra_guardduty_18.py +91 -0
- sraverify/services/guardduty/checks/sra_guardduty_19.py +91 -0
- sraverify/services/guardduty/checks/sra_guardduty_20.py +111 -0
- sraverify/services/guardduty/checks/sra_guardduty_21.py +112 -0
- sraverify/services/guardduty/checks/sra_guardduty_22.py +111 -0
- sraverify/services/guardduty/checks/sra_guardduty_23.py +154 -0
- sraverify/services/guardduty/checks/sra_guardduty_24.py +111 -0
- sraverify/services/guardduty/checks/sra_guardduty_25.py +111 -0
- sraverify/services/guardduty/client.py +107 -0
- sraverify/services/inspector/__init__.py +29 -0
- sraverify/services/inspector/base.py +233 -0
- sraverify/services/inspector/checks/__init__.py +3 -0
- sraverify/services/inspector/checks/sra_inspector_01.py +69 -0
- sraverify/services/inspector/checks/sra_inspector_02.py +68 -0
- sraverify/services/inspector/checks/sra_inspector_03.py +68 -0
- sraverify/services/inspector/checks/sra_inspector_04.py +70 -0
- sraverify/services/inspector/checks/sra_inspector_05.py +69 -0
- sraverify/services/inspector/checks/sra_inspector_06.py +115 -0
- sraverify/services/inspector/checks/sra_inspector_07.py +109 -0
- sraverify/services/inspector/checks/sra_inspector_08.py +69 -0
- sraverify/services/inspector/checks/sra_inspector_09.py +69 -0
- sraverify/services/inspector/checks/sra_inspector_10.py +69 -0
- sraverify/services/inspector/checks/sra_inspector_11.py +69 -0
- sraverify/services/inspector/client.py +99 -0
- sraverify/services/macie/__init__.py +27 -0
- sraverify/services/macie/base.py +271 -0
- sraverify/services/macie/checks/__init__.py +1 -0
- sraverify/services/macie/checks/sra_macie_01.py +100 -0
- sraverify/services/macie/checks/sra_macie_02.py +102 -0
- sraverify/services/macie/checks/sra_macie_03.py +152 -0
- sraverify/services/macie/checks/sra_macie_04.py +120 -0
- sraverify/services/macie/checks/sra_macie_05.py +85 -0
- sraverify/services/macie/checks/sra_macie_06.py +124 -0
- sraverify/services/macie/checks/sra_macie_07.py +138 -0
- sraverify/services/macie/checks/sra_macie_08.py +82 -0
- sraverify/services/macie/checks/sra_macie_09.py +103 -0
- sraverify/services/macie/checks/sra_macie_10.py +81 -0
- sraverify/services/macie/client.py +220 -0
- sraverify/services/s3/__init__.py +16 -0
- sraverify/services/s3/base.py +69 -0
- sraverify/services/s3/checks/__init__.py +1 -0
- sraverify/services/s3/checks/sra_s3_01.py +89 -0
- sraverify/services/s3/checks/sra_s3_02.py +89 -0
- sraverify/services/s3/checks/sra_s3_03.py +88 -0
- sraverify/services/s3/checks/sra_s3_04.py +88 -0
- sraverify/services/s3/client.py +52 -0
- sraverify/services/securityhub/__init__.py +27 -0
- sraverify/services/securityhub/base.py +349 -0
- sraverify/services/securityhub/checks/__init__.py +1 -0
- sraverify/services/securityhub/checks/sra_securityhub_01.py +115 -0
- sraverify/services/securityhub/checks/sra_securityhub_02.py +114 -0
- sraverify/services/securityhub/checks/sra_securityhub_03.py +136 -0
- sraverify/services/securityhub/checks/sra_securityhub_04.py +75 -0
- sraverify/services/securityhub/checks/sra_securityhub_05.py +102 -0
- sraverify/services/securityhub/checks/sra_securityhub_06.py +113 -0
- sraverify/services/securityhub/checks/sra_securityhub_07.py +121 -0
- sraverify/services/securityhub/checks/sra_securityhub_08.py +113 -0
- sraverify/services/securityhub/checks/sra_securityhub_09.py +100 -0
- sraverify/services/securityhub/checks/sra_securityhub_10.py +94 -0
- sraverify/services/securityhub/checks/sra_securityhub_11.py +73 -0
- sraverify/services/securityhub/client.py +249 -0
- sraverify/services/securityincidentresponse/__init__.py +13 -0
- sraverify/services/securityincidentresponse/base.py +95 -0
- sraverify/services/securityincidentresponse/checks/__init__.py +1 -0
- sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_01.py +77 -0
- sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_02.py +72 -0
- sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_03.py +86 -0
- sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_04.py +117 -0
- sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_05.py +55 -0
- sraverify/services/securityincidentresponse/client.py +71 -0
- sraverify/services/securitylake/__init__.py +39 -0
- sraverify/services/securitylake/base.py +461 -0
- sraverify/services/securitylake/checks/__init__.py +1 -0
- sraverify/services/securitylake/checks/sra_securitylake_01.py +98 -0
- sraverify/services/securitylake/checks/sra_securitylake_02.py +133 -0
- sraverify/services/securitylake/checks/sra_securitylake_03.py +116 -0
- sraverify/services/securitylake/checks/sra_securitylake_04.py +72 -0
- sraverify/services/securitylake/checks/sra_securitylake_05.py +116 -0
- sraverify/services/securitylake/checks/sra_securitylake_06.py +104 -0
- sraverify/services/securitylake/checks/sra_securitylake_07.py +108 -0
- sraverify/services/securitylake/checks/sra_securitylake_08.py +107 -0
- sraverify/services/securitylake/checks/sra_securitylake_09.py +107 -0
- sraverify/services/securitylake/checks/sra_securitylake_10.py +106 -0
- sraverify/services/securitylake/checks/sra_securitylake_11.py +109 -0
- sraverify/services/securitylake/checks/sra_securitylake_12.py +108 -0
- sraverify/services/securitylake/checks/sra_securitylake_13.py +108 -0
- sraverify/services/securitylake/checks/sra_securitylake_14.py +72 -0
- sraverify/services/securitylake/checks/sra_securitylake_15.py +120 -0
- sraverify/services/securitylake/checks/sra_securitylake_16.py +104 -0
- sraverify/services/securitylake/checks/sra_securitylake_17.py +103 -0
- sraverify/services/securitylake/client.py +247 -0
- sraverify/services/shield/__init__.py +33 -0
- sraverify/services/shield/base.py +199 -0
- sraverify/services/shield/checks/__init__.py +1 -0
- sraverify/services/shield/checks/sra_shield_01.py +68 -0
- sraverify/services/shield/checks/sra_shield_02.py +77 -0
- sraverify/services/shield/checks/sra_shield_03.py +84 -0
- sraverify/services/shield/checks/sra_shield_04.py +84 -0
- sraverify/services/shield/checks/sra_shield_05.py +84 -0
- sraverify/services/shield/checks/sra_shield_06.py +84 -0
- sraverify/services/shield/checks/sra_shield_07.py +84 -0
- sraverify/services/shield/checks/sra_shield_08.py +69 -0
- sraverify/services/shield/checks/sra_shield_09.py +86 -0
- sraverify/services/shield/checks/sra_shield_10.py +100 -0
- sraverify/services/shield/checks/sra_shield_11.py +71 -0
- sraverify/services/shield/checks/sra_shield_12.py +130 -0
- sraverify/services/shield/checks/sra_shield_13.py +112 -0
- sraverify/services/shield/checks/sra_shield_14.py +111 -0
- sraverify/services/shield/client.py +214 -0
- sraverify/services/waf/__init__.py +21 -0
- sraverify/services/waf/base.py +100 -0
- sraverify/services/waf/checks/__init__.py +1 -0
- sraverify/services/waf/checks/sra_waf_01.py +63 -0
- sraverify/services/waf/checks/sra_waf_02.py +82 -0
- sraverify/services/waf/checks/sra_waf_03.py +123 -0
- sraverify/services/waf/checks/sra_waf_04.py +94 -0
- sraverify/services/waf/checks/sra_waf_05.py +94 -0
- sraverify/services/waf/checks/sra_waf_06.py +91 -0
- sraverify/services/waf/checks/sra_waf_07.py +94 -0
- sraverify/services/waf/checks/sra_waf_08.py +66 -0
- sraverify/services/waf/checks/sra_waf_09.py +95 -0
- sraverify/services/waf/client.py +109 -0
- sraverify/utils/__init__.py +3 -0
- sraverify/utils/banner.py +65 -0
- sraverify/utils/outputs.py +57 -0
- sraverify/utils/progress.py +97 -0
- sraverify-0.1.0.dist-info/LICENSE +175 -0
- sraverify-0.1.0.dist-info/METADATA +516 -0
- sraverify-0.1.0.dist-info/NOTICE +1 -0
- sraverify-0.1.0.dist-info/RECORD +261 -0
- sraverify-0.1.0.dist-info/WHEEL +5 -0
- sraverify-0.1.0.dist-info/entry_points.txt +2 -0
- sraverify-0.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
from typing import Dict, List, Any
|
|
2
|
+
from sraverify.services.firewallmanager.base import FirewallManagerCheck
|
|
3
|
+
|
|
4
|
+
class SRA_FIREWALLMANAGER_10(FirewallManagerCheck):
|
|
5
|
+
def __init__(self):
|
|
6
|
+
super().__init__()
|
|
7
|
+
self.check_id = "SRA-FIREWALLMANAGER-10"
|
|
8
|
+
self.check_name = "Firewall Manager policy cleanup is enabled"
|
|
9
|
+
self.description = "Verifies that AWS Firewall Manager policies have cleanup enabled to remove protections from resources that leave policy scope"
|
|
10
|
+
self.severity = "MEDIUM"
|
|
11
|
+
self.check_logic = "Calls list_policies() per region and checks that policies have DeleteUnusedFMManagedResources set to true"
|
|
12
|
+
|
|
13
|
+
def execute(self) -> List[Dict[str, Any]]:
|
|
14
|
+
for region in self.regions:
|
|
15
|
+
policies_response = self.list_policies(region)
|
|
16
|
+
|
|
17
|
+
if "Error" in policies_response:
|
|
18
|
+
self.findings.append(self.create_finding(
|
|
19
|
+
status="ERROR",
|
|
20
|
+
region=region,
|
|
21
|
+
resource_id=None,
|
|
22
|
+
actual_value=policies_response["Error"].get("Message", "Unknown error"),
|
|
23
|
+
remediation="Check IAM permissions for Firewall Manager API access"
|
|
24
|
+
))
|
|
25
|
+
continue
|
|
26
|
+
|
|
27
|
+
policies = policies_response.get("PolicyList", [])
|
|
28
|
+
|
|
29
|
+
if not policies:
|
|
30
|
+
self.findings.append(self.create_finding(
|
|
31
|
+
status="PASS",
|
|
32
|
+
region=region,
|
|
33
|
+
resource_id=None,
|
|
34
|
+
actual_value="No Firewall Manager policies configured in region",
|
|
35
|
+
remediation="No remediation needed"
|
|
36
|
+
))
|
|
37
|
+
continue
|
|
38
|
+
|
|
39
|
+
for policy in policies:
|
|
40
|
+
policy_id = policy.get("PolicyId", "")
|
|
41
|
+
policy_name = policy.get("PolicyName", "Unknown")
|
|
42
|
+
security_service_type = policy.get("SecurityServiceType", "")
|
|
43
|
+
cleanup_enabled = policy.get("DeleteUnusedFMManagedResources", False)
|
|
44
|
+
|
|
45
|
+
# Shield Advanced and WAF Classic don't support cleanup
|
|
46
|
+
if security_service_type in ["SHIELD_ADVANCED", "WAF"]:
|
|
47
|
+
self.findings.append(self.create_finding(
|
|
48
|
+
status="PASS",
|
|
49
|
+
region=region,
|
|
50
|
+
resource_id=policy_id,
|
|
51
|
+
actual_value=f"Policy '{policy_name}' ({security_service_type}) does not support cleanup",
|
|
52
|
+
remediation="No remediation needed - cleanup not available for this policy type"
|
|
53
|
+
))
|
|
54
|
+
elif not cleanup_enabled:
|
|
55
|
+
self.findings.append(self.create_finding(
|
|
56
|
+
status="FAIL",
|
|
57
|
+
region=region,
|
|
58
|
+
resource_id=policy_id,
|
|
59
|
+
actual_value=f"Policy '{policy_name}' has cleanup disabled",
|
|
60
|
+
remediation=f"Enable cleanup on policy '{policy_name}' to automatically remove protections from out-of-scope resources"
|
|
61
|
+
))
|
|
62
|
+
else:
|
|
63
|
+
self.findings.append(self.create_finding(
|
|
64
|
+
status="PASS",
|
|
65
|
+
region=region,
|
|
66
|
+
resource_id=policy_id,
|
|
67
|
+
actual_value=f"Policy '{policy_name}' has cleanup enabled",
|
|
68
|
+
remediation="No remediation needed"
|
|
69
|
+
))
|
|
70
|
+
|
|
71
|
+
return self.findings
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
from typing import Dict, Any, Optional
|
|
2
|
+
import boto3
|
|
3
|
+
from botocore.exceptions import ClientError
|
|
4
|
+
from sraverify.core.logging import logger
|
|
5
|
+
|
|
6
|
+
class FirewallManagerClient:
|
|
7
|
+
def __init__(self, region: str, session: Optional[boto3.Session] = None):
|
|
8
|
+
self.region = region
|
|
9
|
+
self.session = session or boto3.Session()
|
|
10
|
+
self.client = self.session.client('fms', region_name=region)
|
|
11
|
+
|
|
12
|
+
def get_admin_account(self) -> Dict[str, Any]:
|
|
13
|
+
try:
|
|
14
|
+
return self.client.get_admin_account()
|
|
15
|
+
except ClientError as e:
|
|
16
|
+
error_code = e.response.get('Error', {}).get('Code', '')
|
|
17
|
+
if error_code == 'ResourceNotFoundException':
|
|
18
|
+
return {"Error": {"Message": "No Firewall Manager administrator account configured"}}
|
|
19
|
+
logger.error(f"Error getting Firewall Manager admin account: {e}")
|
|
20
|
+
return {"Error": {"Message": str(e)}}
|
|
21
|
+
|
|
22
|
+
def list_policies(self) -> Dict[str, Any]:
|
|
23
|
+
try:
|
|
24
|
+
policies = []
|
|
25
|
+
next_token = None
|
|
26
|
+
while True:
|
|
27
|
+
if next_token:
|
|
28
|
+
response = self.client.list_policies(NextToken=next_token, MaxResults=100)
|
|
29
|
+
else:
|
|
30
|
+
response = self.client.list_policies(MaxResults=100)
|
|
31
|
+
|
|
32
|
+
policies.extend(response.get('PolicyList', []))
|
|
33
|
+
next_token = response.get('NextToken')
|
|
34
|
+
if not next_token:
|
|
35
|
+
break
|
|
36
|
+
|
|
37
|
+
return {"PolicyList": policies}
|
|
38
|
+
except ClientError as e:
|
|
39
|
+
logger.error(f"Error listing Firewall Manager policies in {self.region}: {e}")
|
|
40
|
+
return {"Error": {"Message": str(e)}}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""
|
|
2
|
+
GuardDuty security checks.
|
|
3
|
+
"""
|
|
4
|
+
from sraverify.services.guardduty.checks.sra_guardduty_01 import SRA_GUARDDUTY_01
|
|
5
|
+
from sraverify.services.guardduty.checks.sra_guardduty_02 import SRA_GUARDDUTY_02
|
|
6
|
+
from sraverify.services.guardduty.checks.sra_guardduty_03 import SRA_GUARDDUTY_03
|
|
7
|
+
from sraverify.services.guardduty.checks.sra_guardduty_04 import SRA_GUARDDUTY_04
|
|
8
|
+
from sraverify.services.guardduty.checks.sra_guardduty_05 import SRA_GUARDDUTY_05
|
|
9
|
+
from sraverify.services.guardduty.checks.sra_guardduty_06 import SRA_GUARDDUTY_06
|
|
10
|
+
from sraverify.services.guardduty.checks.sra_guardduty_07 import SRA_GUARDDUTY_07
|
|
11
|
+
from sraverify.services.guardduty.checks.sra_guardduty_08 import SRA_GUARDDUTY_08
|
|
12
|
+
from sraverify.services.guardduty.checks.sra_guardduty_09 import SRA_GUARDDUTY_09
|
|
13
|
+
from sraverify.services.guardduty.checks.sra_guardduty_10 import SRA_GUARDDUTY_10
|
|
14
|
+
from sraverify.services.guardduty.checks.sra_guardduty_11 import SRA_GUARDDUTY_11
|
|
15
|
+
from sraverify.services.guardduty.checks.sra_guardduty_12 import SRA_GUARDDUTY_12
|
|
16
|
+
from sraverify.services.guardduty.checks.sra_guardduty_13 import SRA_GUARDDUTY_13
|
|
17
|
+
from sraverify.services.guardduty.checks.sra_guardduty_14 import SRA_GUARDDUTY_14
|
|
18
|
+
from sraverify.services.guardduty.checks.sra_guardduty_15 import SRA_GUARDDUTY_15
|
|
19
|
+
from sraverify.services.guardduty.checks.sra_guardduty_16 import SRA_GUARDDUTY_16
|
|
20
|
+
from sraverify.services.guardduty.checks.sra_guardduty_17 import SRA_GUARDDUTY_17
|
|
21
|
+
from sraverify.services.guardduty.checks.sra_guardduty_18 import SRA_GUARDDUTY_18
|
|
22
|
+
from sraverify.services.guardduty.checks.sra_guardduty_19 import SRA_GUARDDUTY_19
|
|
23
|
+
from sraverify.services.guardduty.checks.sra_guardduty_20 import SRA_GUARDDUTY_20
|
|
24
|
+
from sraverify.services.guardduty.checks.sra_guardduty_21 import SRA_GUARDDUTY_21
|
|
25
|
+
from sraverify.services.guardduty.checks.sra_guardduty_22 import SRA_GUARDDUTY_22
|
|
26
|
+
from sraverify.services.guardduty.checks.sra_guardduty_23 import SRA_GUARDDUTY_23
|
|
27
|
+
from sraverify.services.guardduty.checks.sra_guardduty_24 import SRA_GUARDDUTY_24
|
|
28
|
+
from sraverify.services.guardduty.checks.sra_guardduty_25 import SRA_GUARDDUTY_25
|
|
29
|
+
|
|
30
|
+
# Map check IDs to check classes for easy lookup
|
|
31
|
+
CHECKS = {
|
|
32
|
+
"SRA-GUARDDUTY-01": SRA_GUARDDUTY_01,
|
|
33
|
+
"SRA-GUARDDUTY-02": SRA_GUARDDUTY_02,
|
|
34
|
+
"SRA-GUARDDUTY-03": SRA_GUARDDUTY_03,
|
|
35
|
+
"SRA-GUARDDUTY-04": SRA_GUARDDUTY_04,
|
|
36
|
+
"SRA-GUARDDUTY-05": SRA_GUARDDUTY_05,
|
|
37
|
+
"SRA-GUARDDUTY-06": SRA_GUARDDUTY_06,
|
|
38
|
+
"SRA-GUARDDUTY-07": SRA_GUARDDUTY_07,
|
|
39
|
+
"SRA-GUARDDUTY-08": SRA_GUARDDUTY_08,
|
|
40
|
+
"SRA-GUARDDUTY-09": SRA_GUARDDUTY_09,
|
|
41
|
+
"SRA-GUARDDUTY-10": SRA_GUARDDUTY_10,
|
|
42
|
+
"SRA-GUARDDUTY-11": SRA_GUARDDUTY_11,
|
|
43
|
+
"SRA-GUARDDUTY-12": SRA_GUARDDUTY_12,
|
|
44
|
+
"SRA-GUARDDUTY-13": SRA_GUARDDUTY_13,
|
|
45
|
+
"SRA-GUARDDUTY-14": SRA_GUARDDUTY_14,
|
|
46
|
+
"SRA-GUARDDUTY-15": SRA_GUARDDUTY_15,
|
|
47
|
+
"SRA-GUARDDUTY-16": SRA_GUARDDUTY_16,
|
|
48
|
+
"SRA-GUARDDUTY-17": SRA_GUARDDUTY_17,
|
|
49
|
+
"SRA-GUARDDUTY-18": SRA_GUARDDUTY_18,
|
|
50
|
+
"SRA-GUARDDUTY-19": SRA_GUARDDUTY_19,
|
|
51
|
+
"SRA-GUARDDUTY-20": SRA_GUARDDUTY_20,
|
|
52
|
+
"SRA-GUARDDUTY-21": SRA_GUARDDUTY_21,
|
|
53
|
+
"SRA-GUARDDUTY-22": SRA_GUARDDUTY_22,
|
|
54
|
+
"SRA-GUARDDUTY-23": SRA_GUARDDUTY_23,
|
|
55
|
+
"SRA-GUARDDUTY-24": SRA_GUARDDUTY_24,
|
|
56
|
+
"SRA-GUARDDUTY-25": SRA_GUARDDUTY_25
|
|
57
|
+
# Add more checks here as they are implemented
|
|
58
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base class for GuardDuty security checks.
|
|
3
|
+
"""
|
|
4
|
+
from typing import List, Optional, Dict, Any
|
|
5
|
+
from sraverify.core.check import SecurityCheck
|
|
6
|
+
from sraverify.services.guardduty.client import GuardDutyClient
|
|
7
|
+
from sraverify.core.logging import logger
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class GuardDutyCheck(SecurityCheck):
|
|
11
|
+
"""Base class for all GuardDuty security checks."""
|
|
12
|
+
|
|
13
|
+
# Class-level caches shared across all instances
|
|
14
|
+
_detector_details_cache = {}
|
|
15
|
+
_detector_ids_cache = {}
|
|
16
|
+
_org_config_cache = {}
|
|
17
|
+
_admin_accounts_cache = {}
|
|
18
|
+
|
|
19
|
+
def __init__(self):
|
|
20
|
+
"""Initialize GuardDuty base check."""
|
|
21
|
+
super().__init__(
|
|
22
|
+
account_type="application",
|
|
23
|
+
service="GuardDuty",
|
|
24
|
+
resource_type="AWS::GuardDuty::Detector"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
def _setup_clients(self):
|
|
28
|
+
"""Set up GuardDuty clients for each region."""
|
|
29
|
+
# Clear existing clients
|
|
30
|
+
self._clients.clear()
|
|
31
|
+
# Set up new clients only if regions are initialized
|
|
32
|
+
if hasattr(self, 'regions') and self.regions:
|
|
33
|
+
for region in self.regions:
|
|
34
|
+
self._clients[region] = GuardDutyClient(region, session=self.session)
|
|
35
|
+
|
|
36
|
+
def get_detector_id(self, region: str) -> Optional[str]:
|
|
37
|
+
"""
|
|
38
|
+
Get detector ID for a specific region with caching.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
region: AWS region name
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
Detector ID if available, None otherwise
|
|
45
|
+
"""
|
|
46
|
+
# Check class-level cache
|
|
47
|
+
cache_key = f"{self.session.region_name}:{region}"
|
|
48
|
+
if cache_key in GuardDutyCheck._detector_ids_cache:
|
|
49
|
+
logger.debug(f"GuardDuty: Using cached detector ID for {region}")
|
|
50
|
+
return GuardDutyCheck._detector_ids_cache[cache_key]
|
|
51
|
+
|
|
52
|
+
# Get client
|
|
53
|
+
client = self.get_client(region)
|
|
54
|
+
if not client:
|
|
55
|
+
logger.warning(f"GuardDuty: No GuardDuty client available for region {region}")
|
|
56
|
+
return None
|
|
57
|
+
|
|
58
|
+
# Get detector ID
|
|
59
|
+
logger.debug(f"GuardDuty: Fetching detector ID for {region}")
|
|
60
|
+
detector_id = client.get_detector_id()
|
|
61
|
+
|
|
62
|
+
# Check if detector_id contains an error
|
|
63
|
+
if detector_id and isinstance(detector_id, str) and detector_id.startswith("ERROR:"):
|
|
64
|
+
_, error_code, error_message = detector_id.split(":", 2)
|
|
65
|
+
logger.warning(f"GuardDuty: Error accessing GuardDuty in {region}: {error_code}")
|
|
66
|
+
GuardDutyCheck._detector_ids_cache[cache_key] = None
|
|
67
|
+
return None
|
|
68
|
+
|
|
69
|
+
# Cache the detector ID
|
|
70
|
+
if detector_id:
|
|
71
|
+
logger.debug(f"GuardDuty: Found detector ID {detector_id} for {region}")
|
|
72
|
+
GuardDutyCheck._detector_ids_cache[cache_key] = detector_id
|
|
73
|
+
else:
|
|
74
|
+
logger.debug(f"GuardDuty: No detector ID found for {region}")
|
|
75
|
+
|
|
76
|
+
return detector_id
|
|
77
|
+
|
|
78
|
+
def get_detector_details(self, region: str) -> Dict[str, Any]:
|
|
79
|
+
"""
|
|
80
|
+
Get detector details for a specific region.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
83
|
+
region: AWS region name
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
Dictionary containing detector details or empty dict if not available
|
|
87
|
+
"""
|
|
88
|
+
# Check if we already have cached details in the class-level cache
|
|
89
|
+
cache_key = f"{self.session.region_name}:{region}" # Include session region to avoid conflicts
|
|
90
|
+
if cache_key in GuardDutyCheck._detector_details_cache:
|
|
91
|
+
logger.debug(f"GuardDuty: Using cached detector details for {region}")
|
|
92
|
+
return GuardDutyCheck._detector_details_cache[cache_key]
|
|
93
|
+
|
|
94
|
+
# Get detector ID
|
|
95
|
+
detector_id = self.get_detector_id(region)
|
|
96
|
+
if not detector_id:
|
|
97
|
+
logger.debug(f"GuardDuty: No detector ID found for region {region}")
|
|
98
|
+
return {}
|
|
99
|
+
|
|
100
|
+
# Get client
|
|
101
|
+
client = self.get_client(region)
|
|
102
|
+
if not client:
|
|
103
|
+
logger.warning(f"GuardDuty: No GuardDuty client available for region {region}")
|
|
104
|
+
return {}
|
|
105
|
+
|
|
106
|
+
# Get detector details
|
|
107
|
+
logger.debug(f"GuardDuty: Getting detector details for {detector_id} in {region}")
|
|
108
|
+
details = client.get_detector_details(detector_id)
|
|
109
|
+
|
|
110
|
+
# Cache the details in the class-level cache
|
|
111
|
+
GuardDutyCheck._detector_details_cache[cache_key] = details
|
|
112
|
+
logger.debug(f"GuardDuty: Cached detector details for {region}")
|
|
113
|
+
|
|
114
|
+
return details
|
|
115
|
+
|
|
116
|
+
def get_organization_configuration(self, region: str) -> Dict[str, Any]:
|
|
117
|
+
"""
|
|
118
|
+
Get organization configuration for a specific region.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
region: AWS region name
|
|
122
|
+
|
|
123
|
+
Returns:
|
|
124
|
+
Dictionary containing organization configuration details or empty dict if not available
|
|
125
|
+
"""
|
|
126
|
+
# Check if we already have cached org config in the class-level cache
|
|
127
|
+
cache_key = f"{self.session.region_name}:{region}"
|
|
128
|
+
if cache_key in GuardDutyCheck._org_config_cache:
|
|
129
|
+
logger.debug(f"GuardDuty: Using cached organization configuration for {region}")
|
|
130
|
+
return GuardDutyCheck._org_config_cache[cache_key]
|
|
131
|
+
|
|
132
|
+
# Get detector ID
|
|
133
|
+
detector_id = self.get_detector_id(region)
|
|
134
|
+
if not detector_id:
|
|
135
|
+
logger.debug(f"GuardDuty: No detector ID found for region {region}")
|
|
136
|
+
return {}
|
|
137
|
+
|
|
138
|
+
# Get client
|
|
139
|
+
client = self.get_client(region)
|
|
140
|
+
if not client:
|
|
141
|
+
logger.warning(f"GuardDuty: No GuardDuty client available for region {region}")
|
|
142
|
+
return {}
|
|
143
|
+
|
|
144
|
+
# Get organization configuration
|
|
145
|
+
logger.debug(f"GuardDuty: Getting organization configuration for {detector_id} in {region}")
|
|
146
|
+
org_config = client.describe_organization_configuration(detector_id)
|
|
147
|
+
|
|
148
|
+
# Cache the org config in the class-level cache
|
|
149
|
+
GuardDutyCheck._org_config_cache[cache_key] = org_config
|
|
150
|
+
logger.debug(f"GuardDuty: Cached organization configuration for {region}")
|
|
151
|
+
|
|
152
|
+
return org_config
|
|
153
|
+
|
|
154
|
+
def list_organization_admin_accounts(self, region: str) -> Dict[str, Any]:
|
|
155
|
+
"""
|
|
156
|
+
List organization admin accounts for GuardDuty.
|
|
157
|
+
|
|
158
|
+
Args:
|
|
159
|
+
region: AWS region name
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
Dictionary containing organization admin accounts details or empty dict if not available
|
|
163
|
+
"""
|
|
164
|
+
# Check if we already have cached admin accounts in the class-level cache
|
|
165
|
+
cache_key = f"{self.session.region_name}:{region}"
|
|
166
|
+
if cache_key in GuardDutyCheck._admin_accounts_cache:
|
|
167
|
+
logger.debug(f"GuardDuty: Using cached organization admin accounts for {region}")
|
|
168
|
+
return GuardDutyCheck._admin_accounts_cache[cache_key]
|
|
169
|
+
|
|
170
|
+
# Get client
|
|
171
|
+
client = self.get_client(region)
|
|
172
|
+
if not client:
|
|
173
|
+
logger.warning(f"GuardDuty: No GuardDuty client available for region {region}")
|
|
174
|
+
return {}
|
|
175
|
+
|
|
176
|
+
# List organization admin accounts
|
|
177
|
+
logger.debug(f"GuardDuty: Listing organization admin accounts in {region}")
|
|
178
|
+
admin_accounts = client.list_organization_admin_accounts()
|
|
179
|
+
|
|
180
|
+
# Cache the admin accounts in the class-level cache
|
|
181
|
+
GuardDutyCheck._admin_accounts_cache[cache_key] = admin_accounts
|
|
182
|
+
logger.debug(f"GuardDuty: Cached organization admin accounts for {region}")
|
|
183
|
+
|
|
184
|
+
return admin_accounts
|
|
185
|
+
|
|
186
|
+
def get_enabled_regions(self) -> List[str]:
|
|
187
|
+
"""
|
|
188
|
+
Get list of regions where GuardDuty is enabled.
|
|
189
|
+
|
|
190
|
+
Returns:
|
|
191
|
+
List of region names where GuardDuty is enabled
|
|
192
|
+
"""
|
|
193
|
+
# If no detector IDs have been discovered yet, try to discover them
|
|
194
|
+
if not any(k.endswith(f":{region}") for k in GuardDutyCheck._detector_ids_cache.keys()
|
|
195
|
+
for region in self.regions):
|
|
196
|
+
logger.debug("GuardDuty: No detector IDs cached, discovering them now")
|
|
197
|
+
for region in self.regions:
|
|
198
|
+
self.get_detector_id(region)
|
|
199
|
+
|
|
200
|
+
# Get regions from the class-level cache that match the current session
|
|
201
|
+
prefix = f"{self.session.region_name}:"
|
|
202
|
+
enabled_regions = [
|
|
203
|
+
key.split(":")[-1] for key in GuardDutyCheck._detector_ids_cache.keys()
|
|
204
|
+
if key.startswith(prefix) and GuardDutyCheck._detector_ids_cache[key] is not None
|
|
205
|
+
]
|
|
206
|
+
|
|
207
|
+
return enabled_regions
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Check if GuardDuty detector exists.
|
|
3
|
+
"""
|
|
4
|
+
from typing import Dict, List, Any
|
|
5
|
+
from sraverify.services.guardduty.base import GuardDutyCheck
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SRA_GUARDDUTY_01(GuardDutyCheck):
|
|
9
|
+
"""Check if GuardDuty detector exists."""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
"""Initialize GuardDuty enabled check."""
|
|
13
|
+
super().__init__()
|
|
14
|
+
self.check_id = "SRA-GUARDDUTY-01"
|
|
15
|
+
self.check_name = "GuardDuty detector exists"
|
|
16
|
+
self.description = "This check verifies that an GuardDuty detector exists in the AWS Region.\
|
|
17
|
+
A detector is a resource that represents the GuardDuty service and should be present \
|
|
18
|
+
in all AWS member account and AWS Region so that GuardDuty can generate findings \
|
|
19
|
+
about unauthorized or unusual activity even in those Regions that you may not \
|
|
20
|
+
be using actively."
|
|
21
|
+
self.severity = "HIGH"
|
|
22
|
+
self.check_logic = "Get detector_id in each Region. Check fails if there is no detector_id"
|
|
23
|
+
|
|
24
|
+
def execute(self) -> List[Dict[str, Any]]:
|
|
25
|
+
"""
|
|
26
|
+
Execute the check.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
List of findings
|
|
30
|
+
"""
|
|
31
|
+
for region in self.regions:
|
|
32
|
+
detector_id = self.get_detector_id(region)
|
|
33
|
+
|
|
34
|
+
if not detector_id:
|
|
35
|
+
self.findings.append(self.create_finding(
|
|
36
|
+
status="FAIL",
|
|
37
|
+
region=region,
|
|
38
|
+
resource_id=None,
|
|
39
|
+
actual_value=None,
|
|
40
|
+
remediation=f"Enable GuardDuty in {region}"
|
|
41
|
+
))
|
|
42
|
+
else:
|
|
43
|
+
self.findings.append(self.create_finding(
|
|
44
|
+
status="PASS",
|
|
45
|
+
region=region,
|
|
46
|
+
resource_id=f"guardduty:{region}:{detector_id}",
|
|
47
|
+
actual_value=None,
|
|
48
|
+
remediation=""
|
|
49
|
+
))
|
|
50
|
+
|
|
51
|
+
return self.findings
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Check if GuardDuty finding frequency is set.
|
|
3
|
+
"""
|
|
4
|
+
from typing import Dict, List, Any
|
|
5
|
+
from sraverify.services.guardduty.base import GuardDutyCheck
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SRA_GUARDDUTY_02(GuardDutyCheck):
|
|
9
|
+
"""Check if GuardDuty finding frequency is set."""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
"""Initialize GuardDuty enabled check."""
|
|
13
|
+
super().__init__()
|
|
14
|
+
self.check_id = "SRA-GUARDDUTY-02"
|
|
15
|
+
self.check_name = "GuardDuty finding frequency is set"
|
|
16
|
+
self.description = ("This check verifies that the GuardDuty finding frequency is set "
|
|
17
|
+
"as per your organization requirement. This determines how often updates to active "
|
|
18
|
+
"findings are exported to EventBridge, S3 (optional) and Detective (optional). "
|
|
19
|
+
"By default, updated findings are exported every 6 hours but you can set to "
|
|
20
|
+
"every 15 minutes or 1 hour.")
|
|
21
|
+
self.severity = "LOW"
|
|
22
|
+
self.check_logic = "Get detector details in each Region. Check value of FindingPublishingFrequency."
|
|
23
|
+
|
|
24
|
+
def execute(self) -> List[Dict[str, Any]]:
|
|
25
|
+
"""
|
|
26
|
+
Execute the check.
|
|
27
|
+
|
|
28
|
+
Returns:
|
|
29
|
+
List of findings
|
|
30
|
+
"""
|
|
31
|
+
findings = []
|
|
32
|
+
# Check all regions
|
|
33
|
+
for region in self.regions:
|
|
34
|
+
detector_id = self.get_detector_id(region)
|
|
35
|
+
|
|
36
|
+
# Handle regions where we can't access GuardDuty
|
|
37
|
+
if not detector_id:
|
|
38
|
+
findings.append(self.create_finding(
|
|
39
|
+
status="ERROR",
|
|
40
|
+
region=region,
|
|
41
|
+
resource_id=f"guardduty:{region}",
|
|
42
|
+
actual_value="Unable to access GuardDuty in this region",
|
|
43
|
+
remediation="Check permissions or if GuardDuty is supported in this region"
|
|
44
|
+
))
|
|
45
|
+
continue
|
|
46
|
+
|
|
47
|
+
# Use helper method from the base class
|
|
48
|
+
detector_details = self.get_detector_details(region)
|
|
49
|
+
|
|
50
|
+
if detector_details:
|
|
51
|
+
finding_frequency = detector_details.get('FindingPublishingFrequency', 'Not set')
|
|
52
|
+
|
|
53
|
+
# Determine if the frequency is set to a valid value
|
|
54
|
+
valid_frequencies = ['FIFTEEN_MINUTES', 'ONE_HOUR', 'SIX_HOURS']
|
|
55
|
+
if finding_frequency in valid_frequencies:
|
|
56
|
+
findings.append(self.create_finding(
|
|
57
|
+
status="PASS",
|
|
58
|
+
region=region,
|
|
59
|
+
resource_id=f"guardduty:{region}:{detector_id}",
|
|
60
|
+
actual_value=f"Finding frequency is set to {finding_frequency}",
|
|
61
|
+
remediation="No remediation needed"
|
|
62
|
+
))
|
|
63
|
+
else:
|
|
64
|
+
findings.append(self.create_finding(
|
|
65
|
+
status="FAIL",
|
|
66
|
+
region=region,
|
|
67
|
+
resource_id=f"guardduty:{region}:{detector_id}",
|
|
68
|
+
actual_value=f"Finding frequency is not properly set: {finding_frequency}",
|
|
69
|
+
remediation="Set GuardDuty finding frequency to FIFTEEN_MINUTES, ONE_HOUR, or SIX_HOURS"
|
|
70
|
+
))
|
|
71
|
+
else:
|
|
72
|
+
findings.append(self.create_finding(
|
|
73
|
+
status="FAIL",
|
|
74
|
+
region=region,
|
|
75
|
+
resource_id=f"guardduty:{region}:{detector_id}",
|
|
76
|
+
actual_value="Unable to retrieve detector details",
|
|
77
|
+
remediation="Check GuardDuty permissions and configuration"
|
|
78
|
+
))
|
|
79
|
+
|
|
80
|
+
return findings
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Check if GuardDuty detector is enabled.
|
|
3
|
+
"""
|
|
4
|
+
from typing import Dict, List, Any
|
|
5
|
+
from sraverify.services.guardduty.base import GuardDutyCheck
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SRA_GUARDDUTY_03(GuardDutyCheck):
|
|
9
|
+
"""Check if GuardDuty detector is enabled."""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
"""Initialize GuardDuty enabled check."""
|
|
13
|
+
super().__init__()
|
|
14
|
+
self.check_id = "SRA-GUARDDUTY-03"
|
|
15
|
+
self.check_name = "GuardDuty detector is enabled"
|
|
16
|
+
self.description = ("This check verifies that the GuardDuty detector in the "
|
|
17
|
+
"AWS account and AWS region is enabled. Detector represents "
|
|
18
|
+
"GuardDuty service in the AWS account and specific region, "
|
|
19
|
+
"if disabled will not provided threat intelligence service.")
|
|
20
|
+
self.severity = "HIGH"
|
|
21
|
+
self.check_logic = "Get detector details in each Region. Check value of FindingPublishingFrequency."
|
|
22
|
+
|
|
23
|
+
def execute(self) -> List[Dict[str, Any]]:
|
|
24
|
+
"""
|
|
25
|
+
Execute the check.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
List of findings
|
|
29
|
+
"""
|
|
30
|
+
findings = []
|
|
31
|
+
# Check all regions
|
|
32
|
+
for region in self.regions:
|
|
33
|
+
detector_id = self.get_detector_id(region)
|
|
34
|
+
|
|
35
|
+
# Handle regions where we can't access GuardDuty
|
|
36
|
+
if not detector_id:
|
|
37
|
+
findings.append(self.create_finding(
|
|
38
|
+
status="ERROR",
|
|
39
|
+
region=region,
|
|
40
|
+
resource_id=f"guardduty:{region}",
|
|
41
|
+
actual_value="Unable to access GuardDuty in this region",
|
|
42
|
+
remediation="Check permissions or if GuardDuty is supported in this region"
|
|
43
|
+
))
|
|
44
|
+
continue
|
|
45
|
+
|
|
46
|
+
# Use helper method from the base class
|
|
47
|
+
detector_details = self.get_detector_details(region)
|
|
48
|
+
|
|
49
|
+
if detector_details:
|
|
50
|
+
detector_status = detector_details.get('Status', 'Not set')
|
|
51
|
+
|
|
52
|
+
if detector_status == 'ENABLED':
|
|
53
|
+
findings.append(self.create_finding(
|
|
54
|
+
status="PASS",
|
|
55
|
+
region=region,
|
|
56
|
+
resource_id=f"guardduty:{region}:{detector_id}",
|
|
57
|
+
actual_value=f"Detector status is {detector_status}",
|
|
58
|
+
remediation="No remediation needed"
|
|
59
|
+
))
|
|
60
|
+
else:
|
|
61
|
+
findings.append(self.create_finding(
|
|
62
|
+
status="FAIL",
|
|
63
|
+
region=region,
|
|
64
|
+
resource_id=f"guardduty:{region}:{detector_id}",
|
|
65
|
+
actual_value=f"Detector status is {detector_status}",
|
|
66
|
+
remediation="Enabled GuardDuty"
|
|
67
|
+
))
|
|
68
|
+
else:
|
|
69
|
+
findings.append(self.create_finding(
|
|
70
|
+
status="FAIL",
|
|
71
|
+
region=region,
|
|
72
|
+
resource_id=f"guardduty:{region}:{detector_id}",
|
|
73
|
+
actual_value="Unable to retrieve detector details",
|
|
74
|
+
remediation="Check GuardDuty permissions and configuration"
|
|
75
|
+
))
|
|
76
|
+
|
|
77
|
+
return findings
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Check if GuardDuty has DNS logs enabled as a log source.
|
|
3
|
+
"""
|
|
4
|
+
from typing import Dict, List, Any
|
|
5
|
+
from sraverify.services.guardduty.base import GuardDutyCheck
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class SRA_GUARDDUTY_04(GuardDutyCheck):
|
|
9
|
+
"""Check if GuardDuty has DNS logs enabled as a log source."""
|
|
10
|
+
|
|
11
|
+
def __init__(self):
|
|
12
|
+
"""Initialize GuardDuty DNS logs check."""
|
|
13
|
+
super().__init__()
|
|
14
|
+
self.check_id = "SRA-GUARDDUTY-04"
|
|
15
|
+
self.check_name = "GuardDuty DNS logs enabled"
|
|
16
|
+
self.description = ("This check verifies that GuardDuty has DNS logs as one of the log sources, enabled. "
|
|
17
|
+
"If you use AWS DNS resolvers for your Amazon EC2 instances (the default setting), "
|
|
18
|
+
"then GuardDuty can access and process your request and response DNS logs through the "
|
|
19
|
+
"internal AWS DNS resolvers.")
|
|
20
|
+
self.severity = "MEDIUM"
|
|
21
|
+
self.check_logic = "Get detector details in each Region. Check if DNS logs are enabled in the Features array."
|
|
22
|
+
|
|
23
|
+
def execute(self) -> List[Dict[str, Any]]:
|
|
24
|
+
"""
|
|
25
|
+
Execute the check.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
List of findings
|
|
29
|
+
"""
|
|
30
|
+
findings = []
|
|
31
|
+
# Check all regions
|
|
32
|
+
for region in self.regions:
|
|
33
|
+
detector_id = self.get_detector_id(region)
|
|
34
|
+
|
|
35
|
+
# Handle regions where we can't access GuardDuty
|
|
36
|
+
if not detector_id:
|
|
37
|
+
findings.append(self.create_finding(
|
|
38
|
+
status="ERROR",
|
|
39
|
+
region=region,
|
|
40
|
+
resource_id=f"guardduty:{region}",
|
|
41
|
+
actual_value="Unable to access GuardDuty in this region",
|
|
42
|
+
remediation="Check permissions or if GuardDuty is supported in this region"
|
|
43
|
+
))
|
|
44
|
+
continue
|
|
45
|
+
|
|
46
|
+
# Get detector details
|
|
47
|
+
detector_details = self.get_detector_details(region)
|
|
48
|
+
|
|
49
|
+
if detector_details:
|
|
50
|
+
# Check if DNS logs are enabled in the Features array
|
|
51
|
+
dns_logs_enabled = False
|
|
52
|
+
features = detector_details.get('Features', [])
|
|
53
|
+
|
|
54
|
+
for feature in features:
|
|
55
|
+
if feature.get('Name') == 'DNS_LOGS' and feature.get('Status') == 'ENABLED':
|
|
56
|
+
dns_logs_enabled = True
|
|
57
|
+
break
|
|
58
|
+
|
|
59
|
+
if dns_logs_enabled:
|
|
60
|
+
findings.append(self.create_finding(
|
|
61
|
+
status="PASS",
|
|
62
|
+
region=region,
|
|
63
|
+
resource_id=f"guardduty:{region}:{detector_id}",
|
|
64
|
+
actual_value="DNS logs are enabled as a data source",
|
|
65
|
+
remediation=""
|
|
66
|
+
))
|
|
67
|
+
else:
|
|
68
|
+
findings.append(self.create_finding(
|
|
69
|
+
status="FAIL",
|
|
70
|
+
region=region,
|
|
71
|
+
resource_id=f"guardduty:{region}:{detector_id}",
|
|
72
|
+
actual_value="DNS logs are not enabled as a data source",
|
|
73
|
+
remediation=f"Enable DNS logs as a data source for GuardDuty in {region}"
|
|
74
|
+
))
|
|
75
|
+
else:
|
|
76
|
+
findings.append(self.create_finding(
|
|
77
|
+
status="FAIL",
|
|
78
|
+
region=region,
|
|
79
|
+
resource_id=f"guardduty:{region}:{detector_id}",
|
|
80
|
+
actual_value="Unable to retrieve detector details",
|
|
81
|
+
remediation="Check GuardDuty permissions and configuration"
|
|
82
|
+
))
|
|
83
|
+
|
|
84
|
+
return findings
|