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,88 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SRA-S3-04: S3 block public policy is enabled.
|
|
3
|
+
"""
|
|
4
|
+
from typing import List, Dict, Any
|
|
5
|
+
from sraverify.services.s3.base import S3Check
|
|
6
|
+
from sraverify.core.logging import logger
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SRA_S3_04(S3Check):
|
|
10
|
+
"""Check if S3 block public policy is enabled for the account."""
|
|
11
|
+
|
|
12
|
+
def __init__(self):
|
|
13
|
+
"""Initialize the check."""
|
|
14
|
+
super().__init__()
|
|
15
|
+
self.check_id = "SRA-S3-04"
|
|
16
|
+
self.check_name = "S3 block public policy is enabled"
|
|
17
|
+
self.account_type = "application"
|
|
18
|
+
self.severity = "HIGH"
|
|
19
|
+
self.description = (
|
|
20
|
+
"This check verifies whether S3 should block public bucket policies for buckets. "
|
|
21
|
+
"Setting this causes Amazon S3 to reject calls that attaches a public access bucket policy to a S3 bucket."
|
|
22
|
+
)
|
|
23
|
+
self.check_logic = (
|
|
24
|
+
"Check if BlockPublicPolicy is set to true in the account's public access block configuration."
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
def execute(self) -> List[Dict[str, Any]]:
|
|
28
|
+
"""
|
|
29
|
+
Execute the check.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
List of findings
|
|
33
|
+
"""
|
|
34
|
+
findings = []
|
|
35
|
+
|
|
36
|
+
# Get public access block configuration using the base class method
|
|
37
|
+
# This will use the cache if available or make API calls if needed
|
|
38
|
+
public_access_config = self.get_public_access()
|
|
39
|
+
|
|
40
|
+
# Check if the configuration exists and BlockPublicPolicy is enabled
|
|
41
|
+
if not public_access_config:
|
|
42
|
+
findings.append(
|
|
43
|
+
self.create_finding(
|
|
44
|
+
status="FAIL",
|
|
45
|
+
region="global", # S3 public access block is a global setting
|
|
46
|
+
resource_id=self.account_id,
|
|
47
|
+
checked_value="BlockPublicPolicy: true",
|
|
48
|
+
actual_value="No public access block configuration found",
|
|
49
|
+
remediation=(
|
|
50
|
+
"Enable S3 Block Public Access at the account level using the AWS CLI command: "
|
|
51
|
+
f"aws s3control put-public-access-block --account-id {self.account_id} "
|
|
52
|
+
"--public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,"
|
|
53
|
+
"BlockPublicPolicy=true,RestrictPublicBuckets=true"
|
|
54
|
+
)
|
|
55
|
+
)
|
|
56
|
+
)
|
|
57
|
+
return findings
|
|
58
|
+
|
|
59
|
+
block_public_policy = public_access_config.get('BlockPublicPolicy', False)
|
|
60
|
+
|
|
61
|
+
if block_public_policy:
|
|
62
|
+
findings.append(
|
|
63
|
+
self.create_finding(
|
|
64
|
+
status="PASS",
|
|
65
|
+
region="global", # S3 public access block is a global setting
|
|
66
|
+
resource_id=self.account_id,
|
|
67
|
+
checked_value="BlockPublicPolicy: true",
|
|
68
|
+
actual_value="BlockPublicPolicy setting is true",
|
|
69
|
+
remediation="No remediation needed"
|
|
70
|
+
)
|
|
71
|
+
)
|
|
72
|
+
else:
|
|
73
|
+
findings.append(
|
|
74
|
+
self.create_finding(
|
|
75
|
+
status="FAIL",
|
|
76
|
+
region="global", # S3 public access block is a global setting
|
|
77
|
+
resource_id=self.account_id,
|
|
78
|
+
checked_value="BlockPublicPolicy: true",
|
|
79
|
+
actual_value="BlockPublicPolicy setting is false",
|
|
80
|
+
remediation=(
|
|
81
|
+
"Enable S3 Block Public Policy at the account level using the AWS CLI command: "
|
|
82
|
+
f"aws s3control put-public-access-block --account-id {self.account_id} "
|
|
83
|
+
"--public-access-block-configuration BlockPublicPolicy=true"
|
|
84
|
+
)
|
|
85
|
+
)
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
return findings
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""
|
|
2
|
+
S3 client for interacting with AWS S3 service.
|
|
3
|
+
"""
|
|
4
|
+
from typing import Dict, List, Optional, Any
|
|
5
|
+
import boto3
|
|
6
|
+
from botocore.exceptions import ClientError
|
|
7
|
+
from sraverify.core.logging import logger
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class S3Client:
|
|
11
|
+
"""Client for interacting with AWS S3 service."""
|
|
12
|
+
|
|
13
|
+
def __init__(self, region: str, session: Optional[boto3.Session] = None):
|
|
14
|
+
"""
|
|
15
|
+
Initialize S3 client for a specific region.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
region: AWS region name
|
|
19
|
+
session: AWS session to use (if None, a new session will be created)
|
|
20
|
+
"""
|
|
21
|
+
self.region = region
|
|
22
|
+
self.session = session or boto3.Session()
|
|
23
|
+
self.client = self.session.client('s3', region_name=region)
|
|
24
|
+
self.s3control_client = self.session.client('s3control', region_name=region)
|
|
25
|
+
|
|
26
|
+
def get_public_access_block(self, account_id: str) -> Dict[str, Any]:
|
|
27
|
+
"""
|
|
28
|
+
Get the public access block configuration for an account.
|
|
29
|
+
|
|
30
|
+
Args:
|
|
31
|
+
account_id: AWS account ID
|
|
32
|
+
|
|
33
|
+
Returns:
|
|
34
|
+
Public access block configuration
|
|
35
|
+
"""
|
|
36
|
+
try:
|
|
37
|
+
logger.debug(f"Getting public access block configuration for account {account_id} in {self.region}")
|
|
38
|
+
response = self.s3control_client.get_public_access_block(
|
|
39
|
+
AccountId=account_id
|
|
40
|
+
)
|
|
41
|
+
return response.get('PublicAccessBlockConfiguration', {})
|
|
42
|
+
except ClientError as e:
|
|
43
|
+
if 'NoSuchPublicAccessBlockConfiguration' in str(e):
|
|
44
|
+
# Silently handle the case where no configuration exists
|
|
45
|
+
# This is a common case and not an error condition
|
|
46
|
+
logger.debug(f"No public access block configuration found for account {account_id} in {self.region}")
|
|
47
|
+
return {}
|
|
48
|
+
logger.error(f"Error getting public access block configuration for account {account_id} in {self.region}: {e}")
|
|
49
|
+
return {}
|
|
50
|
+
except Exception as e:
|
|
51
|
+
logger.error(f"Unexpected error getting public access block configuration for account {account_id} in {self.region}: {e}")
|
|
52
|
+
return {}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""SecurityHub service checks."""
|
|
2
|
+
|
|
3
|
+
from sraverify.services.securityhub.checks.sra_securityhub_01 import SRA_SECURITYHUB_01
|
|
4
|
+
from sraverify.services.securityhub.checks.sra_securityhub_02 import SRA_SECURITYHUB_02
|
|
5
|
+
from sraverify.services.securityhub.checks.sra_securityhub_03 import SRA_SECURITYHUB_03
|
|
6
|
+
from sraverify.services.securityhub.checks.sra_securityhub_04 import SRA_SECURITYHUB_04
|
|
7
|
+
from sraverify.services.securityhub.checks.sra_securityhub_05 import SRA_SECURITYHUB_05
|
|
8
|
+
from sraverify.services.securityhub.checks.sra_securityhub_06 import SRA_SECURITYHUB_06
|
|
9
|
+
from sraverify.services.securityhub.checks.sra_securityhub_07 import SRA_SECURITYHUB_07
|
|
10
|
+
from sraverify.services.securityhub.checks.sra_securityhub_08 import SRA_SECURITYHUB_08
|
|
11
|
+
from sraverify.services.securityhub.checks.sra_securityhub_09 import SRA_SECURITYHUB_09
|
|
12
|
+
from sraverify.services.securityhub.checks.sra_securityhub_10 import SRA_SECURITYHUB_10
|
|
13
|
+
from sraverify.services.securityhub.checks.sra_securityhub_11 import SRA_SECURITYHUB_11
|
|
14
|
+
|
|
15
|
+
CHECKS = {
|
|
16
|
+
"SRA-SECURITYHUB-01": SRA_SECURITYHUB_01,
|
|
17
|
+
"SRA-SECURITYHUB-02": SRA_SECURITYHUB_02,
|
|
18
|
+
"SRA-SECURITYHUB-03": SRA_SECURITYHUB_03,
|
|
19
|
+
"SRA-SECURITYHUB-04": SRA_SECURITYHUB_04,
|
|
20
|
+
"SRA-SECURITYHUB-05": SRA_SECURITYHUB_05,
|
|
21
|
+
"SRA-SECURITYHUB-06": SRA_SECURITYHUB_06,
|
|
22
|
+
"SRA-SECURITYHUB-07": SRA_SECURITYHUB_07,
|
|
23
|
+
"SRA-SECURITYHUB-08": SRA_SECURITYHUB_08,
|
|
24
|
+
"SRA-SECURITYHUB-09": SRA_SECURITYHUB_09,
|
|
25
|
+
"SRA-SECURITYHUB-10": SRA_SECURITYHUB_10,
|
|
26
|
+
"SRA-SECURITYHUB-11": SRA_SECURITYHUB_11,
|
|
27
|
+
}
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Base class for SecurityHub security checks.
|
|
3
|
+
"""
|
|
4
|
+
from typing import List, Optional, Dict, Any
|
|
5
|
+
from sraverify.core.check import SecurityCheck
|
|
6
|
+
from sraverify.services.securityhub.client import SecurityHubClient
|
|
7
|
+
from sraverify.core.logging import logger
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class SecurityHubCheck(SecurityCheck):
|
|
11
|
+
"""Base class for all SecurityHub security checks."""
|
|
12
|
+
|
|
13
|
+
# Class-level caches shared across all instances
|
|
14
|
+
_enabled_standards_cache = {}
|
|
15
|
+
_admin_account_cache = {}
|
|
16
|
+
_organization_configuration_cache = {}
|
|
17
|
+
_product_integrations_cache = {}
|
|
18
|
+
_delegated_admin_cache = {}
|
|
19
|
+
_organization_accounts_cache = {}
|
|
20
|
+
_securityhub_members_cache = {}
|
|
21
|
+
|
|
22
|
+
def __init__(self):
|
|
23
|
+
"""Initialize SecurityHub base check."""
|
|
24
|
+
super().__init__(
|
|
25
|
+
account_type="audit", # Default to audit, can be overridden in child classes
|
|
26
|
+
service="SecurityHub",
|
|
27
|
+
resource_type="AWS::SecurityHub::Hub"
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
def _setup_clients(self):
|
|
31
|
+
"""Set up SecurityHub clients for each region."""
|
|
32
|
+
# Clear existing clients
|
|
33
|
+
self._clients.clear()
|
|
34
|
+
# Set up new clients only if regions are initialized
|
|
35
|
+
if hasattr(self, 'regions') and self.regions:
|
|
36
|
+
for region in self.regions:
|
|
37
|
+
self._clients[region] = SecurityHubClient(region, session=self.session)
|
|
38
|
+
|
|
39
|
+
def get_client(self, region: str) -> Optional[SecurityHubClient]:
|
|
40
|
+
"""
|
|
41
|
+
Get SecurityHub client for a specific region.
|
|
42
|
+
|
|
43
|
+
Args:
|
|
44
|
+
region: AWS region name
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
SecurityHubClient for the region or None if not available
|
|
48
|
+
"""
|
|
49
|
+
return self._clients.get(region)
|
|
50
|
+
|
|
51
|
+
def get_enabled_standards(self, region: str) -> List[Dict[str, Any]]:
|
|
52
|
+
"""
|
|
53
|
+
Get enabled Security Hub standards for a region with caching.
|
|
54
|
+
|
|
55
|
+
Args:
|
|
56
|
+
region: AWS region name
|
|
57
|
+
|
|
58
|
+
Returns:
|
|
59
|
+
List of enabled standards or None if Security Hub is not enabled
|
|
60
|
+
"""
|
|
61
|
+
account_id = self.account_id
|
|
62
|
+
if not account_id:
|
|
63
|
+
logger.warning("Could not determine account ID")
|
|
64
|
+
return []
|
|
65
|
+
|
|
66
|
+
# Check cache first
|
|
67
|
+
cache_key = f"{account_id}:{region}"
|
|
68
|
+
if cache_key in self.__class__._enabled_standards_cache:
|
|
69
|
+
logger.debug(f"Using cached enabled standards for {cache_key}")
|
|
70
|
+
return self.__class__._enabled_standards_cache[cache_key]
|
|
71
|
+
|
|
72
|
+
client = self.get_client(region)
|
|
73
|
+
if not client:
|
|
74
|
+
logger.warning(f"No SecurityHub client available for region {region}")
|
|
75
|
+
return []
|
|
76
|
+
|
|
77
|
+
try:
|
|
78
|
+
# Get enabled standards from client
|
|
79
|
+
standards = client.get_enabled_standards()
|
|
80
|
+
|
|
81
|
+
# If standards is None (Security Hub not enabled), don't try to cache it
|
|
82
|
+
if standards is None:
|
|
83
|
+
logger.debug(f"Security Hub is not enabled in region {region}")
|
|
84
|
+
return None
|
|
85
|
+
|
|
86
|
+
# Cache the results
|
|
87
|
+
self.__class__._enabled_standards_cache[cache_key] = standards
|
|
88
|
+
logger.debug(f"Cached {len(standards)} enabled standards for {cache_key}")
|
|
89
|
+
|
|
90
|
+
return standards
|
|
91
|
+
except Exception as e:
|
|
92
|
+
# Check if this is the "not subscribed to AWS Security Hub" error
|
|
93
|
+
if hasattr(e, 'response') and isinstance(e.response, dict):
|
|
94
|
+
error = e.response.get('Error', {})
|
|
95
|
+
if error.get('Code') == 'InvalidAccessException' and 'not subscribed to AWS Security Hub' in error.get('Message', ''):
|
|
96
|
+
# Return None specifically for this error to indicate Security Hub is not enabled
|
|
97
|
+
# Don't log this as an error since it's an expected condition we want to check for
|
|
98
|
+
logger.debug(f"Security Hub is not enabled in region {region}")
|
|
99
|
+
return None
|
|
100
|
+
|
|
101
|
+
# For other errors, log a warning instead of an error to avoid cluttering the build logs
|
|
102
|
+
logger.warning(f"Error getting enabled standards in {region}: {e}")
|
|
103
|
+
return []
|
|
104
|
+
|
|
105
|
+
def get_administrator_account(self, region: str) -> Dict[str, Any]:
|
|
106
|
+
"""
|
|
107
|
+
Get Security Hub administrator account with caching.
|
|
108
|
+
|
|
109
|
+
Args:
|
|
110
|
+
region: AWS region name
|
|
111
|
+
|
|
112
|
+
Returns:
|
|
113
|
+
Administrator account information
|
|
114
|
+
"""
|
|
115
|
+
account_id = self.account_id
|
|
116
|
+
if not account_id:
|
|
117
|
+
logger.warning("Could not determine account ID")
|
|
118
|
+
return {}
|
|
119
|
+
|
|
120
|
+
# Check cache first
|
|
121
|
+
cache_key = f"{account_id}:{region}"
|
|
122
|
+
if cache_key in self.__class__._admin_account_cache:
|
|
123
|
+
logger.debug(f"Using cached administrator account for {cache_key}")
|
|
124
|
+
return self.__class__._admin_account_cache[cache_key]
|
|
125
|
+
|
|
126
|
+
client = self.get_client(region)
|
|
127
|
+
if not client:
|
|
128
|
+
logger.warning(f"No SecurityHub client available for region {region}")
|
|
129
|
+
return {}
|
|
130
|
+
|
|
131
|
+
# Get administrator account from client
|
|
132
|
+
admin_account = client.get_administrator_account()
|
|
133
|
+
|
|
134
|
+
# Cache the results
|
|
135
|
+
self.__class__._admin_account_cache[cache_key] = admin_account
|
|
136
|
+
logger.debug(f"Cached administrator account for {cache_key}")
|
|
137
|
+
|
|
138
|
+
return admin_account
|
|
139
|
+
|
|
140
|
+
def get_organization_configuration(self, region: str) -> Dict[str, Any]:
|
|
141
|
+
"""
|
|
142
|
+
Get Security Hub organization configuration with caching.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
region: AWS region name
|
|
146
|
+
|
|
147
|
+
Returns:
|
|
148
|
+
Organization configuration
|
|
149
|
+
"""
|
|
150
|
+
account_id = self.account_id
|
|
151
|
+
if not account_id:
|
|
152
|
+
logger.warning("Could not determine account ID")
|
|
153
|
+
return {}
|
|
154
|
+
|
|
155
|
+
# Check cache first
|
|
156
|
+
cache_key = f"{account_id}:{region}"
|
|
157
|
+
if cache_key in self.__class__._organization_configuration_cache:
|
|
158
|
+
logger.debug(f"Using cached organization configuration for {cache_key}")
|
|
159
|
+
return self.__class__._organization_configuration_cache[cache_key]
|
|
160
|
+
|
|
161
|
+
client = self.get_client(region)
|
|
162
|
+
if not client:
|
|
163
|
+
logger.warning(f"No SecurityHub client available for region {region}")
|
|
164
|
+
return {}
|
|
165
|
+
|
|
166
|
+
# Get organization configuration from client
|
|
167
|
+
org_config = client.describe_organization_configuration()
|
|
168
|
+
|
|
169
|
+
# Cache the results
|
|
170
|
+
self.__class__._organization_configuration_cache[cache_key] = org_config
|
|
171
|
+
logger.debug(f"Cached organization configuration for {cache_key}")
|
|
172
|
+
|
|
173
|
+
return org_config
|
|
174
|
+
|
|
175
|
+
def get_enabled_products_for_import(self, region: str) -> Optional[List[str]]:
|
|
176
|
+
"""
|
|
177
|
+
Get enabled products for import with caching.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
region: AWS region name
|
|
181
|
+
|
|
182
|
+
Returns:
|
|
183
|
+
List of enabled product ARNs, or None if Security Hub is not enabled
|
|
184
|
+
"""
|
|
185
|
+
account_id = self.account_id
|
|
186
|
+
if not account_id:
|
|
187
|
+
logger.warning("Could not determine account ID")
|
|
188
|
+
return []
|
|
189
|
+
|
|
190
|
+
# Check cache first
|
|
191
|
+
cache_key = f"{account_id}:{region}"
|
|
192
|
+
if cache_key in self.__class__._product_integrations_cache:
|
|
193
|
+
logger.debug(f"Using cached product integrations for {cache_key}")
|
|
194
|
+
return self.__class__._product_integrations_cache[cache_key]
|
|
195
|
+
|
|
196
|
+
client = self.get_client(region)
|
|
197
|
+
if not client:
|
|
198
|
+
logger.warning(f"No SecurityHub client available for region {region}")
|
|
199
|
+
return []
|
|
200
|
+
|
|
201
|
+
# Get enabled products from client
|
|
202
|
+
products = client.list_enabled_products_for_import()
|
|
203
|
+
|
|
204
|
+
# Only cache if we got a valid response (not None)
|
|
205
|
+
if products is not None:
|
|
206
|
+
self.__class__._product_integrations_cache[cache_key] = products
|
|
207
|
+
logger.debug(f"Cached {len(products)} product integrations for {cache_key}")
|
|
208
|
+
|
|
209
|
+
return products
|
|
210
|
+
|
|
211
|
+
def get_delegated_administrators(self, region: str) -> List[Dict[str, Any]]:
|
|
212
|
+
"""
|
|
213
|
+
Get SecurityHub delegated administrators with caching.
|
|
214
|
+
|
|
215
|
+
Args:
|
|
216
|
+
region: AWS region name
|
|
217
|
+
|
|
218
|
+
Returns:
|
|
219
|
+
List of delegated administrators
|
|
220
|
+
"""
|
|
221
|
+
account_id = self.account_id
|
|
222
|
+
if not account_id:
|
|
223
|
+
logger.warning("Could not determine account ID")
|
|
224
|
+
return []
|
|
225
|
+
|
|
226
|
+
# Check cache first
|
|
227
|
+
cache_key = f"{account_id}:{region}"
|
|
228
|
+
if cache_key in self.__class__._delegated_admin_cache:
|
|
229
|
+
logger.debug(f"Using cached delegated administrators for {cache_key}")
|
|
230
|
+
return self.__class__._delegated_admin_cache[cache_key]
|
|
231
|
+
|
|
232
|
+
client = self.get_client(region)
|
|
233
|
+
if not client:
|
|
234
|
+
logger.warning(f"No SecurityHub client available for region {region}")
|
|
235
|
+
return []
|
|
236
|
+
|
|
237
|
+
# Get delegated administrators from client
|
|
238
|
+
delegated_admins = client.list_delegated_administrators()
|
|
239
|
+
|
|
240
|
+
# Cache the results
|
|
241
|
+
self.__class__._delegated_admin_cache[cache_key] = delegated_admins
|
|
242
|
+
logger.debug(f"Cached {len(delegated_admins)} delegated administrators for {cache_key}")
|
|
243
|
+
|
|
244
|
+
return delegated_admins
|
|
245
|
+
|
|
246
|
+
def get_organization_admin_accounts(self, region: str) -> List[Dict[str, Any]]:
|
|
247
|
+
"""
|
|
248
|
+
Get Security Hub organization admin accounts with caching.
|
|
249
|
+
|
|
250
|
+
Args:
|
|
251
|
+
region: AWS region name
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
List of organization admin accounts
|
|
255
|
+
"""
|
|
256
|
+
account_id = self.account_id
|
|
257
|
+
if not account_id:
|
|
258
|
+
logger.warning("Could not determine account ID")
|
|
259
|
+
return []
|
|
260
|
+
|
|
261
|
+
# Check cache first
|
|
262
|
+
cache_key = f"{account_id}:{region}"
|
|
263
|
+
if cache_key in self.__class__._admin_account_cache:
|
|
264
|
+
logger.debug(f"Using cached organization admin accounts for {cache_key}")
|
|
265
|
+
return self.__class__._admin_account_cache[cache_key]
|
|
266
|
+
|
|
267
|
+
client = self.get_client(region)
|
|
268
|
+
if not client:
|
|
269
|
+
logger.warning(f"No SecurityHub client available for region {region}")
|
|
270
|
+
return []
|
|
271
|
+
|
|
272
|
+
# Get organization admin accounts from client
|
|
273
|
+
admin_accounts = client.list_organization_admin_accounts()
|
|
274
|
+
|
|
275
|
+
# Cache the results
|
|
276
|
+
self.__class__._admin_account_cache[cache_key] = admin_accounts
|
|
277
|
+
logger.debug(f"Cached {len(admin_accounts)} organization admin accounts for {cache_key}")
|
|
278
|
+
|
|
279
|
+
return admin_accounts
|
|
280
|
+
|
|
281
|
+
def get_organization_accounts(self, region: str) -> List[Dict[str, Any]]:
|
|
282
|
+
"""
|
|
283
|
+
Get all organization accounts with caching.
|
|
284
|
+
|
|
285
|
+
Args:
|
|
286
|
+
region: AWS region name
|
|
287
|
+
|
|
288
|
+
Returns:
|
|
289
|
+
List of organization accounts
|
|
290
|
+
"""
|
|
291
|
+
account_id = self.account_id
|
|
292
|
+
if not account_id:
|
|
293
|
+
logger.warning("Could not determine account ID")
|
|
294
|
+
return []
|
|
295
|
+
|
|
296
|
+
# Check cache first
|
|
297
|
+
cache_key = f"{account_id}:{region}"
|
|
298
|
+
if cache_key in self.__class__._organization_accounts_cache:
|
|
299
|
+
logger.debug(f"Using cached organization accounts for {cache_key}")
|
|
300
|
+
return self.__class__._organization_accounts_cache[cache_key]
|
|
301
|
+
|
|
302
|
+
client = self.get_client(region)
|
|
303
|
+
if not client:
|
|
304
|
+
logger.warning(f"No SecurityHub client available for region {region}")
|
|
305
|
+
return []
|
|
306
|
+
|
|
307
|
+
# Get organization accounts from client
|
|
308
|
+
accounts = client.list_organization_accounts()
|
|
309
|
+
|
|
310
|
+
# Cache the results
|
|
311
|
+
self.__class__._organization_accounts_cache[cache_key] = accounts
|
|
312
|
+
logger.debug(f"Cached {len(accounts)} organization accounts for {cache_key}")
|
|
313
|
+
|
|
314
|
+
return accounts
|
|
315
|
+
|
|
316
|
+
def get_security_hub_members(self, region: str) -> List[Dict[str, Any]]:
|
|
317
|
+
"""
|
|
318
|
+
Get Security Hub member accounts with caching.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
region: AWS region name
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
List of Security Hub member accounts
|
|
325
|
+
"""
|
|
326
|
+
account_id = self.account_id
|
|
327
|
+
if not account_id:
|
|
328
|
+
logger.warning("Could not determine account ID")
|
|
329
|
+
return []
|
|
330
|
+
|
|
331
|
+
# Check cache first
|
|
332
|
+
cache_key = f"{account_id}:{region}"
|
|
333
|
+
if cache_key in self.__class__._securityhub_members_cache:
|
|
334
|
+
logger.debug(f"Using cached Security Hub members for {cache_key}")
|
|
335
|
+
return self.__class__._securityhub_members_cache[cache_key]
|
|
336
|
+
|
|
337
|
+
client = self.get_client(region)
|
|
338
|
+
if not client:
|
|
339
|
+
logger.warning(f"No SecurityHub client available for region {region}")
|
|
340
|
+
return []
|
|
341
|
+
|
|
342
|
+
# Get Security Hub members from client
|
|
343
|
+
members = client.list_members()
|
|
344
|
+
|
|
345
|
+
# Cache the results
|
|
346
|
+
self.__class__._securityhub_members_cache[cache_key] = members
|
|
347
|
+
logger.debug(f"Cached {len(members)} Security Hub members for {cache_key}")
|
|
348
|
+
|
|
349
|
+
return members
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""SecurityHub checks."""
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SRA-SECURITYHUB-01: Security Hub check.
|
|
3
|
+
"""
|
|
4
|
+
from typing import List, Dict, Any
|
|
5
|
+
from sraverify.services.securityhub.base import SecurityHubCheck
|
|
6
|
+
from sraverify.core.logging import logger
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class SRA_SECURITYHUB_01(SecurityHubCheck):
|
|
10
|
+
"""Check if Security Hub enabled account level standards exist."""
|
|
11
|
+
|
|
12
|
+
def __init__(self):
|
|
13
|
+
"""Initialize the check."""
|
|
14
|
+
super().__init__()
|
|
15
|
+
self.check_id = "SRA-SECURITYHUB-01"
|
|
16
|
+
self.check_name = "Security Hub enabled account level standards exist"
|
|
17
|
+
self.account_type = "application" # This check is for application accounts
|
|
18
|
+
self.severity = "HIGH"
|
|
19
|
+
self.description = (
|
|
20
|
+
"This check verifies whether a list of enabled Security Hub standards for the current AWS account exists."
|
|
21
|
+
)
|
|
22
|
+
self.check_logic = (
|
|
23
|
+
"Check evaluates if there are any standards enabled in the AWS account and AWS region. "
|
|
24
|
+
"Check PASS if there are any standards enabled."
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
def execute(self) -> List[Dict[str, Any]]:
|
|
28
|
+
"""
|
|
29
|
+
Execute the check.
|
|
30
|
+
|
|
31
|
+
Returns:
|
|
32
|
+
List of findings
|
|
33
|
+
"""
|
|
34
|
+
findings = []
|
|
35
|
+
|
|
36
|
+
# If no regions have Security Hub available, return a single failure
|
|
37
|
+
if not self._clients:
|
|
38
|
+
findings.append(
|
|
39
|
+
self.create_finding(
|
|
40
|
+
status="FAIL",
|
|
41
|
+
region="global",
|
|
42
|
+
resource_id="securityhub:global",
|
|
43
|
+
checked_value="Security Hub is enabled",
|
|
44
|
+
actual_value="Security Hub not available in any region",
|
|
45
|
+
remediation="Enable Security Hub in at least one region"
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
return findings
|
|
49
|
+
|
|
50
|
+
# Check each region where Security Hub is available
|
|
51
|
+
for region in self.regions:
|
|
52
|
+
# Get enabled standards for the current account in this region
|
|
53
|
+
enabled_standards = self.get_enabled_standards(region)
|
|
54
|
+
|
|
55
|
+
# If None is returned, Security Hub is not enabled
|
|
56
|
+
if enabled_standards is None:
|
|
57
|
+
findings.append(
|
|
58
|
+
self.create_finding(
|
|
59
|
+
status="FAIL",
|
|
60
|
+
region=region,
|
|
61
|
+
resource_id=f"securityhub:service/{self.account_id}",
|
|
62
|
+
checked_value="Security Hub is enabled",
|
|
63
|
+
actual_value=f"Security Hub is not enabled in region {region}",
|
|
64
|
+
remediation=(
|
|
65
|
+
"Enable Security Hub in this region. In the AWS console, navigate to Security Hub and enable the service. "
|
|
66
|
+
"Alternatively, use the AWS CLI command: "
|
|
67
|
+
f"aws securityhub enable-security-hub --region {region}"
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
)
|
|
71
|
+
continue
|
|
72
|
+
|
|
73
|
+
# Extract standard names for better reporting
|
|
74
|
+
standard_names = []
|
|
75
|
+
for standard in enabled_standards:
|
|
76
|
+
standard_arn = standard.get('StandardsArn', '')
|
|
77
|
+
# Extract the standard name from the ARN
|
|
78
|
+
if '/standards/' in standard_arn:
|
|
79
|
+
standard_name = standard_arn.split('/standards/')[1]
|
|
80
|
+
standard_names.append(standard_name)
|
|
81
|
+
else:
|
|
82
|
+
standard_names.append(standard_arn)
|
|
83
|
+
|
|
84
|
+
# Format the list of standards for reporting
|
|
85
|
+
standards_list = ', '.join(standard_names) if standard_names else "None"
|
|
86
|
+
|
|
87
|
+
if not enabled_standards:
|
|
88
|
+
findings.append(
|
|
89
|
+
self.create_finding(
|
|
90
|
+
status="FAIL",
|
|
91
|
+
region=region,
|
|
92
|
+
resource_id=f"securityhub:standards/{self.account_id}",
|
|
93
|
+
checked_value="Security Hub standards are enabled",
|
|
94
|
+
actual_value=f"Account {self.account_id} region {region} has no Security Hub standards enabled",
|
|
95
|
+
remediation=(
|
|
96
|
+
"Enable Security Hub standards for this account. In the Security Hub console, "
|
|
97
|
+
"navigate to Settings > Standards and enable the required standards. "
|
|
98
|
+
"Alternatively, use the AWS CLI command: "
|
|
99
|
+
f"aws securityhub batch-enable-standards --standards-subscription-requests 'StandardsArn=arn:aws:securityhub:{region}::standards/aws-foundational-security-best-practices/v/1.0.0' --region {region}"
|
|
100
|
+
)
|
|
101
|
+
)
|
|
102
|
+
)
|
|
103
|
+
else:
|
|
104
|
+
findings.append(
|
|
105
|
+
self.create_finding(
|
|
106
|
+
status="PASS",
|
|
107
|
+
region=region,
|
|
108
|
+
resource_id=f"securityhub:standards/{self.account_id}",
|
|
109
|
+
checked_value="Security Hub standards are enabled",
|
|
110
|
+
actual_value=f"Account {self.account_id} region {region} has the following standards enabled: {standards_list}",
|
|
111
|
+
remediation="No remediation needed"
|
|
112
|
+
)
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
return findings
|