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,196 @@
|
|
|
1
|
+
from typing import Dict, List, Any
|
|
2
|
+
from sraverify.checks import SecurityCheck
|
|
3
|
+
from botocore.exceptions import ClientError
|
|
4
|
+
|
|
5
|
+
class SRACT3(SecurityCheck):
|
|
6
|
+
"""SRA-CT-3: Organization Trail Log File Validation"""
|
|
7
|
+
|
|
8
|
+
def __init__(self, check_type="organization"):
|
|
9
|
+
super().__init__(check_type=check_type)
|
|
10
|
+
self.check_id = "SRA-CT-3"
|
|
11
|
+
self.check_name = "Organization Trail Log File Validation"
|
|
12
|
+
self.severity = 'HIGH'
|
|
13
|
+
self.description = ('This check verifies that your organization trail has log file validation enabled. '
|
|
14
|
+
'Validated log files are especially valuable in security and forensic investigations. '
|
|
15
|
+
'CloudTrail log file integrity validation uses industry standard algorithms: SHA-256 '
|
|
16
|
+
'for hashing and SHA-256 with RSA for digital signing. This makes it computationally '
|
|
17
|
+
'unfeasible to modify, delete or forge CloudTrail log files without detection.')
|
|
18
|
+
self.check_logic = ('1. Verify execution from Organization Management Account | '
|
|
19
|
+
'2. List CloudTrail trails in current region | '
|
|
20
|
+
'3. Check for organization trail with IsOrganizationTrail=true | '
|
|
21
|
+
'4. Verify trail configuration has EnableLogFileValidation=true | '
|
|
22
|
+
'5. Validate digest files are being delivered | '
|
|
23
|
+
'6. Check passes if organization trail has log file validation enabled and working')
|
|
24
|
+
self.service = 'CloudTrail'
|
|
25
|
+
|
|
26
|
+
def get_findings(self) -> List[Dict[str, Any]]:
|
|
27
|
+
"""Return the findings"""
|
|
28
|
+
return self.findings
|
|
29
|
+
|
|
30
|
+
def run(self, session):
|
|
31
|
+
"""Run the security check"""
|
|
32
|
+
try:
|
|
33
|
+
region = session.region_name
|
|
34
|
+
account_id = session.client('sts').get_caller_identity()['Account']
|
|
35
|
+
|
|
36
|
+
# Initialize clients
|
|
37
|
+
org_client = session.client('organizations')
|
|
38
|
+
cloudtrail_client = session.client('cloudtrail')
|
|
39
|
+
|
|
40
|
+
# Step 1: Verify we're in management account using org_mgmt_checker
|
|
41
|
+
is_management, error_message = self.org_checker.verify_org_management()
|
|
42
|
+
if not is_management:
|
|
43
|
+
finding = {
|
|
44
|
+
'CheckId': self.check_id,
|
|
45
|
+
'Status': 'ERROR',
|
|
46
|
+
'Region': region,
|
|
47
|
+
"Severity": self.severity,
|
|
48
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
49
|
+
'Description': self.description,
|
|
50
|
+
'ResourceId': account_id,
|
|
51
|
+
'ResourceType': 'AWS::Organizations::Account',
|
|
52
|
+
'AccountId': account_id,
|
|
53
|
+
'CheckedValue': 'Management Account Access',
|
|
54
|
+
'ActualValue': error_message if error_message else 'Not running from management account',
|
|
55
|
+
'Remediation': 'Run this check from the Organization Management Account',
|
|
56
|
+
'Service': self.service,
|
|
57
|
+
'CheckLogic': self.check_logic,
|
|
58
|
+
'CheckType': self.check_type
|
|
59
|
+
}
|
|
60
|
+
self.findings.append(finding)
|
|
61
|
+
return self.findings
|
|
62
|
+
|
|
63
|
+
# Steps 2-6: List trails and check validation
|
|
64
|
+
trails = cloudtrail_client.list_trails()['Trails']
|
|
65
|
+
org_trails = []
|
|
66
|
+
|
|
67
|
+
for trail in trails:
|
|
68
|
+
trail_info = cloudtrail_client.get_trail(Name=trail['Name'])['Trail']
|
|
69
|
+
|
|
70
|
+
if trail_info.get('IsOrganizationTrail', False):
|
|
71
|
+
org_trails.append(trail_info)
|
|
72
|
+
|
|
73
|
+
if not org_trails:
|
|
74
|
+
self.findings.append({
|
|
75
|
+
'CheckId': self.check_id,
|
|
76
|
+
'Status': 'FAIL',
|
|
77
|
+
'Region': region,
|
|
78
|
+
"Severity": self.severity,
|
|
79
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
80
|
+
'Description': self.description,
|
|
81
|
+
'ResourceId': account_id,
|
|
82
|
+
'ResourceType': 'AWS::CloudTrail::Trail',
|
|
83
|
+
'AccountId': account_id,
|
|
84
|
+
'CheckedValue': 'Organization Trail',
|
|
85
|
+
'ActualValue': 'No organization trail found',
|
|
86
|
+
'Remediation': 'Create an organization-wide CloudTrail trail with log file validation enabled',
|
|
87
|
+
'Service': self.service,
|
|
88
|
+
'CheckLogic': self.check_logic,
|
|
89
|
+
'CheckType': self.check_type
|
|
90
|
+
})
|
|
91
|
+
return self.findings
|
|
92
|
+
|
|
93
|
+
for trail in org_trails:
|
|
94
|
+
trail_name = trail['Name']
|
|
95
|
+
trail_arn = trail['TrailARN']
|
|
96
|
+
|
|
97
|
+
# Check if logging is enabled
|
|
98
|
+
trail_status = cloudtrail_client.get_trail_status(Name=trail_name)
|
|
99
|
+
if not trail_status.get('IsLogging', False):
|
|
100
|
+
self.findings.append({
|
|
101
|
+
'CheckId': self.check_id,
|
|
102
|
+
'Status': 'FAIL',
|
|
103
|
+
'Region': region,
|
|
104
|
+
"Severity": self.severity,
|
|
105
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
106
|
+
'Description': self.description,
|
|
107
|
+
'ResourceId': trail_arn,
|
|
108
|
+
'ResourceType': 'AWS::CloudTrail::Trail',
|
|
109
|
+
'AccountId': account_id,
|
|
110
|
+
'CheckedValue': 'Trail Logging Status',
|
|
111
|
+
'ActualValue': 'Organization trail is not logging',
|
|
112
|
+
'Remediation': 'Enable logging for the organization trail',
|
|
113
|
+
'Service': self.service,
|
|
114
|
+
'CheckLogic': self.check_logic,
|
|
115
|
+
'CheckType': self.check_type
|
|
116
|
+
})
|
|
117
|
+
continue
|
|
118
|
+
|
|
119
|
+
# Check log file validation
|
|
120
|
+
if not trail.get('LogFileValidationEnabled', False):
|
|
121
|
+
self.findings.append({
|
|
122
|
+
'CheckId': self.check_id,
|
|
123
|
+
'Status': 'FAIL',
|
|
124
|
+
'Region': region,
|
|
125
|
+
"Severity": self.severity,
|
|
126
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
127
|
+
'Description': self.description,
|
|
128
|
+
'ResourceId': trail_arn,
|
|
129
|
+
'ResourceType': 'AWS::CloudTrail::Trail',
|
|
130
|
+
'AccountId': account_id,
|
|
131
|
+
'CheckedValue': 'Log File Validation',
|
|
132
|
+
'ActualValue': 'Log file validation is not enabled',
|
|
133
|
+
'Remediation': 'Enable log file validation on the organization CloudTrail trail',
|
|
134
|
+
'Service': self.service,
|
|
135
|
+
'CheckLogic': self.check_logic,
|
|
136
|
+
'CheckType': self.check_type
|
|
137
|
+
})
|
|
138
|
+
else:
|
|
139
|
+
# Check if digest files are being delivered
|
|
140
|
+
if not trail_status.get('LatestDigestDeliveryTime'):
|
|
141
|
+
self.findings.append({
|
|
142
|
+
'CheckId': self.check_id,
|
|
143
|
+
'Status': 'FAIL',
|
|
144
|
+
'Region': region,
|
|
145
|
+
"Severity": self.severity,
|
|
146
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
147
|
+
'Description': self.description,
|
|
148
|
+
'ResourceId': trail_arn,
|
|
149
|
+
'ResourceType': 'AWS::CloudTrail::Trail',
|
|
150
|
+
'AccountId': account_id,
|
|
151
|
+
'CheckedValue': 'Digest File Delivery',
|
|
152
|
+
'ActualValue': 'No digest files have been delivered',
|
|
153
|
+
'Remediation': 'Verify S3 bucket permissions and trail configuration',
|
|
154
|
+
'Service': self.service,
|
|
155
|
+
'CheckLogic': self.check_logic,
|
|
156
|
+
'CheckType': self.check_type
|
|
157
|
+
})
|
|
158
|
+
else:
|
|
159
|
+
self.findings.append({
|
|
160
|
+
'CheckId': self.check_id,
|
|
161
|
+
'Status': 'PASS',
|
|
162
|
+
'Region': region,
|
|
163
|
+
"Severity": self.severity,
|
|
164
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
165
|
+
'Description': self.description,
|
|
166
|
+
'ResourceId': trail_arn,
|
|
167
|
+
'ResourceType': 'AWS::CloudTrail::Trail',
|
|
168
|
+
'AccountId': account_id,
|
|
169
|
+
'CheckedValue': 'Log File Validation',
|
|
170
|
+
'ActualValue': 'Log file validation is enabled and digest files are being delivered',
|
|
171
|
+
'Remediation': None,
|
|
172
|
+
'Service': self.service,
|
|
173
|
+
'CheckLogic': self.check_logic,
|
|
174
|
+
'CheckType': self.check_type
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
except Exception as e:
|
|
178
|
+
self.findings.append({
|
|
179
|
+
'CheckId': self.check_id,
|
|
180
|
+
'Status': 'ERROR',
|
|
181
|
+
'Region': region,
|
|
182
|
+
"Severity": self.severity,
|
|
183
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
184
|
+
'Description': self.description,
|
|
185
|
+
'ResourceId': account_id,
|
|
186
|
+
'ResourceType': 'AWS::CloudTrail::Trail',
|
|
187
|
+
'AccountId': account_id,
|
|
188
|
+
'CheckedValue': 'Check Execution',
|
|
189
|
+
'ActualValue': f'Error running check: {str(e)}',
|
|
190
|
+
'Remediation': 'Review the error message and try again',
|
|
191
|
+
'Service': self.service,
|
|
192
|
+
'CheckLogic': self.check_logic,
|
|
193
|
+
'CheckType': self.check_type
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
return self.findings
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
from typing import Dict, List, Any
|
|
2
|
+
from sraverify.checks import SecurityCheck
|
|
3
|
+
from botocore.exceptions import ClientError
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
class SRACT4(SecurityCheck):
|
|
7
|
+
"""SRA-CT-4: Organization Trail Multi-Region Configuration"""
|
|
8
|
+
|
|
9
|
+
def __init__(self, check_type="organization"):
|
|
10
|
+
"""Initialize the check with organization type"""
|
|
11
|
+
super().__init__(check_type=check_type)
|
|
12
|
+
self.check_id = "SRA-CT-4"
|
|
13
|
+
self.check_name = "Organization Trail Multi-Region Configuration"
|
|
14
|
+
self.severity = "HIGH"
|
|
15
|
+
self.description = ('This check verifies that your organization trail is configured as a multi-region trail. '
|
|
16
|
+
'This helps ensure you have visibility across your entire AWS environment.')
|
|
17
|
+
self.check_logic = ('1. Verify execution from Organization Management account | '
|
|
18
|
+
'2. List CloudTrail trails in current region | '
|
|
19
|
+
'3. Check for organization trail with IsOrganizationTrail=true | '
|
|
20
|
+
'4. Verify trail configuration has IsMultiRegionTrail=true | '
|
|
21
|
+
'5. Verify trail is recording in all regions | '
|
|
22
|
+
'6. Check passes if organization trail is properly configured for multi-region logging')
|
|
23
|
+
self.service = 'CloudTrail'
|
|
24
|
+
self.logger = logging.getLogger(self.__class__.__name__)
|
|
25
|
+
self.findings = []
|
|
26
|
+
|
|
27
|
+
def get_findings(self) -> List[Dict[str, Any]]:
|
|
28
|
+
"""Return the findings"""
|
|
29
|
+
return self.findings
|
|
30
|
+
|
|
31
|
+
def run(self, session) -> None:
|
|
32
|
+
"""Run the security check"""
|
|
33
|
+
try:
|
|
34
|
+
# Get account information
|
|
35
|
+
sts_client = session.client('sts')
|
|
36
|
+
account_id = sts_client.get_caller_identity()['Account']
|
|
37
|
+
region = session.region_name
|
|
38
|
+
self.logger.debug(f"Running check for account: {account_id} in region: {region}")
|
|
39
|
+
|
|
40
|
+
# Initialize CloudTrail client
|
|
41
|
+
cloudtrail_client = session.client('cloudtrail')
|
|
42
|
+
|
|
43
|
+
# Step 1: Verify we're in management account using org_mgmt_checker
|
|
44
|
+
is_management, error_message = self.org_checker.verify_org_management()
|
|
45
|
+
if not is_management:
|
|
46
|
+
finding = {
|
|
47
|
+
'CheckId': self.check_id,
|
|
48
|
+
'Status': 'ERROR',
|
|
49
|
+
'Region': region,
|
|
50
|
+
"Severity": self.severity,
|
|
51
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
52
|
+
'Description': self.description,
|
|
53
|
+
'ResourceId': account_id,
|
|
54
|
+
'ResourceType': 'AWS::Organizations::Account',
|
|
55
|
+
'AccountId': account_id,
|
|
56
|
+
'CheckedValue': 'Management Account Access',
|
|
57
|
+
'ActualValue': error_message if error_message else 'Not running from management account',
|
|
58
|
+
'Remediation': 'Run this check from the Organization Management Account',
|
|
59
|
+
'Service': self.service,
|
|
60
|
+
'CheckLogic': self.check_logic,
|
|
61
|
+
'CheckType': self.check_type
|
|
62
|
+
}
|
|
63
|
+
self.findings.append(finding)
|
|
64
|
+
return self.findings
|
|
65
|
+
|
|
66
|
+
try:
|
|
67
|
+
# List trails and find organization trails
|
|
68
|
+
trails = cloudtrail_client.describe_trails(includeShadowTrails=True)
|
|
69
|
+
org_trails = [t for t in trails['trailList'] if t.get('IsOrganizationTrail')]
|
|
70
|
+
self.logger.debug(f"Found {len(org_trails)} organization trails")
|
|
71
|
+
|
|
72
|
+
if not org_trails:
|
|
73
|
+
self.findings.append({
|
|
74
|
+
"CheckId": self.check_id,
|
|
75
|
+
"Status": "FAIL",
|
|
76
|
+
"Region": region,
|
|
77
|
+
"Severity": self.severity,
|
|
78
|
+
"Title": f"{self.check_id} {self.check_name}",
|
|
79
|
+
"Description": self.description,
|
|
80
|
+
"ResourceId": "organization-trail",
|
|
81
|
+
"ResourceType": "AWS::CloudTrail::Trail",
|
|
82
|
+
"AccountId": account_id,
|
|
83
|
+
"CheckedValue": "Organization Trail Configuration",
|
|
84
|
+
"ActualValue": "No organization trail found",
|
|
85
|
+
"Remediation": "Create an organization trail with multi-region logging enabled",
|
|
86
|
+
"Service": "CloudTrail",
|
|
87
|
+
"CheckLogic": self.check_logic,
|
|
88
|
+
"CheckType": self.check_type
|
|
89
|
+
})
|
|
90
|
+
return
|
|
91
|
+
|
|
92
|
+
# Check multi-region configuration for organization trails
|
|
93
|
+
multi_region_trail = None
|
|
94
|
+
for trail in org_trails:
|
|
95
|
+
if trail.get('IsMultiRegionTrail'):
|
|
96
|
+
multi_region_trail = trail
|
|
97
|
+
self.logger.debug(f"Found multi-region organization trail: {trail['Name']}")
|
|
98
|
+
break
|
|
99
|
+
|
|
100
|
+
# Create finding based on multi-region configuration
|
|
101
|
+
status = "PASS" if multi_region_trail else "FAIL"
|
|
102
|
+
actual_value = (f"Organization trail {multi_region_trail['Name'] if multi_region_trail else org_trails[0]['Name']} "
|
|
103
|
+
f"{'is' if multi_region_trail else 'is not'} configured for multi-region logging")
|
|
104
|
+
|
|
105
|
+
self.findings.append({
|
|
106
|
+
"CheckId": self.check_id,
|
|
107
|
+
"Status": status,
|
|
108
|
+
"Region": region,
|
|
109
|
+
"Severity": self.severity,
|
|
110
|
+
"Title": f"{self.check_id} {self.check_name}",
|
|
111
|
+
"Description": self.description,
|
|
112
|
+
"ResourceId": (multi_region_trail or org_trails[0])['TrailARN'],
|
|
113
|
+
"ResourceType": "AWS::CloudTrail::Trail",
|
|
114
|
+
"AccountId": account_id,
|
|
115
|
+
"CheckedValue": "Multi-Region Configuration",
|
|
116
|
+
"ActualValue": actual_value,
|
|
117
|
+
"Remediation": "None required" if multi_region_trail else "Enable multi-region logging for the organization trail",
|
|
118
|
+
"Service": "CloudTrail",
|
|
119
|
+
"CheckLogic": self.check_logic,
|
|
120
|
+
"CheckType": self.check_type
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
except ClientError as e:
|
|
124
|
+
self.logger.error(f"Error accessing CloudTrail: {str(e)}")
|
|
125
|
+
self.findings.append({
|
|
126
|
+
"CheckId": self.check_id,
|
|
127
|
+
"Status": "ERROR",
|
|
128
|
+
"Region": region,
|
|
129
|
+
"Severity": self.severity,
|
|
130
|
+
"Title": f"{self.check_id} {self.check_name}",
|
|
131
|
+
"Description": self.description,
|
|
132
|
+
"ResourceId": "cloudtrail",
|
|
133
|
+
"ResourceType": "AWS::CloudTrail::Trail",
|
|
134
|
+
"AccountId": account_id,
|
|
135
|
+
"CheckedValue": "CloudTrail API Access",
|
|
136
|
+
"ActualValue": f"Error accessing CloudTrail: {str(e)}",
|
|
137
|
+
"Remediation": "Verify CloudTrail permissions",
|
|
138
|
+
"Service": "CloudTrail",
|
|
139
|
+
"CheckLogic": self.check_logic,
|
|
140
|
+
"CheckType": self.check_type
|
|
141
|
+
})
|
|
142
|
+
|
|
143
|
+
except Exception as e:
|
|
144
|
+
self.logger.error(f"Unexpected error in check: {str(e)}")
|
|
145
|
+
self.findings.append({
|
|
146
|
+
"CheckId": self.check_id,
|
|
147
|
+
"Status": "ERROR",
|
|
148
|
+
"Region": region if 'region' in locals() else session.region_name,
|
|
149
|
+
"Severity": self.severity,
|
|
150
|
+
"Title": f"{self.check_id} {self.check_name}",
|
|
151
|
+
"Description": self.description,
|
|
152
|
+
"ResourceId": "check-execution",
|
|
153
|
+
"ResourceType": "AWS::CloudTrail::Trail",
|
|
154
|
+
"AccountId": account_id if 'account_id' in locals() else "unknown",
|
|
155
|
+
"CheckedValue": "Check Execution",
|
|
156
|
+
"ActualValue": f"Unexpected error: {str(e)}",
|
|
157
|
+
"Remediation": "Contact support team",
|
|
158
|
+
"Service": "CloudTrail",
|
|
159
|
+
"CheckLogic": self.check_logic,
|
|
160
|
+
"CheckType": self.check_type
|
|
161
|
+
})
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
from typing import Dict, List, Any
|
|
2
|
+
from sraverify.checks import SecurityCheck
|
|
3
|
+
from botocore.exceptions import ClientError
|
|
4
|
+
from datetime import datetime, timezone
|
|
5
|
+
|
|
6
|
+
class SRACT5(SecurityCheck):
|
|
7
|
+
"""SRA-CT-5: Organization Trail CloudWatch Logs Delivery"""
|
|
8
|
+
|
|
9
|
+
def __init__(self, check_type="organization"):
|
|
10
|
+
super().__init__(check_type=check_type)
|
|
11
|
+
self.check_id = "SRA-CT-5"
|
|
12
|
+
self.check_name = "Organization Trail CloudWatch Logs Delivery"
|
|
13
|
+
self.severity = "HIGH"
|
|
14
|
+
self.description = ('This check verifies that last delivery of cloudtrail logs to CloudWatch Logs was successful. '
|
|
15
|
+
'CloudWatch Logs enables you to centralize the cloudtrail logs from all your AWS accounts and '
|
|
16
|
+
'regions in the AWS Organization, to a single, highly scalable service. You can then easily view '
|
|
17
|
+
'them, search them for specific error codes or patterns, filter them based on specific fields, '
|
|
18
|
+
'or archive them securely for future analysis.')
|
|
19
|
+
self.check_logic = ('1. Verify execution from Organization Management account | '
|
|
20
|
+
'2. List CloudTrail trails in current region and identify organization trails (IsOrganizationTrail=true) | '
|
|
21
|
+
'3. For each organization trail, verify CloudWatch Logs integration is configured (CloudWatchLogsLogGroupArn and CloudWatchLogsRoleArn exist) | '
|
|
22
|
+
'4. Get trail status and verify no CloudWatch Logs delivery errors (LatestCloudWatchLogsDeliveryError is empty) | '
|
|
23
|
+
'5. Verify latest CloudWatch Logs delivery time exists and occurred within last 24 hours | '
|
|
24
|
+
'6. Check passes if all above conditions are met for at least one organization trail')
|
|
25
|
+
self.service = 'CloudTrail'
|
|
26
|
+
|
|
27
|
+
def get_findings(self) -> List[Dict[str, Any]]:
|
|
28
|
+
"""Return the findings"""
|
|
29
|
+
return self.findings
|
|
30
|
+
|
|
31
|
+
def run(self, session):
|
|
32
|
+
"""Run the security check"""
|
|
33
|
+
try:
|
|
34
|
+
region = session.region_name
|
|
35
|
+
account_id = session.client('sts').get_caller_identity()['Account']
|
|
36
|
+
|
|
37
|
+
organizations = session.client('organizations')
|
|
38
|
+
cloudtrail_client = session.client('cloudtrail')
|
|
39
|
+
|
|
40
|
+
# Step 1: Verify we're in management account using org_mgmt_checker
|
|
41
|
+
is_management, error_message = self.org_checker.verify_org_management()
|
|
42
|
+
if not is_management:
|
|
43
|
+
finding = {
|
|
44
|
+
'CheckId': self.check_id,
|
|
45
|
+
'Status': 'ERROR',
|
|
46
|
+
'Region': region,
|
|
47
|
+
"Severity": self.severity,
|
|
48
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
49
|
+
'Description': self.description,
|
|
50
|
+
'ResourceId': account_id,
|
|
51
|
+
'ResourceType': 'AWS::Organizations::Account',
|
|
52
|
+
'AccountId': account_id,
|
|
53
|
+
'CheckedValue': 'Management Account Access',
|
|
54
|
+
'ActualValue': error_message if error_message else 'Not running from management account',
|
|
55
|
+
'Remediation': 'Run this check from the Organization Management Account',
|
|
56
|
+
'Service': self.service,
|
|
57
|
+
'CheckLogic': self.check_logic,
|
|
58
|
+
'CheckType': self.check_type
|
|
59
|
+
}
|
|
60
|
+
self.findings.append(finding)
|
|
61
|
+
return self.findings
|
|
62
|
+
|
|
63
|
+
# Step 2: List trails and identify organization trails
|
|
64
|
+
try:
|
|
65
|
+
trails = cloudtrail_client.list_trails()['Trails']
|
|
66
|
+
org_trails = []
|
|
67
|
+
|
|
68
|
+
for trail in trails:
|
|
69
|
+
trail_info = cloudtrail_client.get_trail(Name=trail['Name'])['Trail']
|
|
70
|
+
if trail_info.get('IsOrganizationTrail', False):
|
|
71
|
+
org_trails.append(trail_info)
|
|
72
|
+
|
|
73
|
+
if not org_trails:
|
|
74
|
+
self.findings.append({
|
|
75
|
+
'CheckId': self.check_id,
|
|
76
|
+
'Status': 'FAIL',
|
|
77
|
+
'Region': region,
|
|
78
|
+
"Severity": self.severity,
|
|
79
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
80
|
+
'Description': self.description,
|
|
81
|
+
'ResourceId': account_id,
|
|
82
|
+
'ResourceType': 'AWS::CloudTrail::Trail',
|
|
83
|
+
'AccountId': account_id,
|
|
84
|
+
'CheckedValue': 'Organization Trail',
|
|
85
|
+
'ActualValue': 'No organization trails found in the current region',
|
|
86
|
+
'Remediation': 'Create an organization-wide CloudTrail trail with CloudWatch Logs integration enabled',
|
|
87
|
+
'Service': self.service,
|
|
88
|
+
'CheckLogic': self.check_logic,
|
|
89
|
+
'CheckType': self.check_type
|
|
90
|
+
})
|
|
91
|
+
return self.findings
|
|
92
|
+
|
|
93
|
+
for trail in org_trails:
|
|
94
|
+
trail_name = trail['Name']
|
|
95
|
+
trail_arn = trail['TrailARN']
|
|
96
|
+
failures = []
|
|
97
|
+
|
|
98
|
+
# Step 3: Verify CloudWatch Logs integration configuration
|
|
99
|
+
cloudwatch_logs_group_arn = trail.get('CloudWatchLogsLogGroupArn')
|
|
100
|
+
cloudwatch_logs_role_arn = trail.get('CloudWatchLogsRoleArn')
|
|
101
|
+
|
|
102
|
+
if not cloudwatch_logs_group_arn:
|
|
103
|
+
failures.append('CloudWatch Logs group ARN is not configured')
|
|
104
|
+
if not cloudwatch_logs_role_arn:
|
|
105
|
+
failures.append('CloudWatch Logs role ARN is not configured')
|
|
106
|
+
|
|
107
|
+
if cloudwatch_logs_group_arn and cloudwatch_logs_role_arn:
|
|
108
|
+
# Step 4: Check CloudWatch Logs delivery errors
|
|
109
|
+
trail_status = cloudtrail_client.get_trail_status(Name=trail_name)
|
|
110
|
+
delivery_error = trail_status.get('LatestCloudWatchLogsDeliveryError')
|
|
111
|
+
if delivery_error:
|
|
112
|
+
failures.append(f"CloudWatch Logs delivery error: {delivery_error}")
|
|
113
|
+
|
|
114
|
+
# Step 5: Verify latest delivery time
|
|
115
|
+
latest_delivery_time = trail_status.get('LatestCloudWatchLogsDeliveryTime')
|
|
116
|
+
if not latest_delivery_time:
|
|
117
|
+
failures.append('No CloudWatch Logs deliveries found')
|
|
118
|
+
else:
|
|
119
|
+
current_time = datetime.now(timezone.utc)
|
|
120
|
+
time_difference = current_time - latest_delivery_time
|
|
121
|
+
if time_difference.total_seconds() > 86400: # 24 hours in seconds
|
|
122
|
+
failures.append(f'Last CloudWatch Logs delivery was more than 24 hours ago: {latest_delivery_time.isoformat()}')
|
|
123
|
+
|
|
124
|
+
if failures:
|
|
125
|
+
self.findings.append({
|
|
126
|
+
'CheckId': self.check_id,
|
|
127
|
+
'Status': 'FAIL',
|
|
128
|
+
'Region': region,
|
|
129
|
+
"Severity": self.severity,
|
|
130
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
131
|
+
'Description': self.description,
|
|
132
|
+
'ResourceId': trail_arn,
|
|
133
|
+
'ResourceType': 'AWS::CloudTrail::Trail',
|
|
134
|
+
'AccountId': account_id,
|
|
135
|
+
'CheckedValue': 'CloudWatch Logs Integration Requirements',
|
|
136
|
+
'ActualValue': f'Trail "{trail_name}" has the following issues: {" | ".join(failures)}',
|
|
137
|
+
'Remediation': ('Ensure CloudWatch Logs integration is properly configured and delivering logs within 24 hours'),
|
|
138
|
+
'Service': self.service,
|
|
139
|
+
'CheckLogic': self.check_logic,
|
|
140
|
+
'CheckType': self.check_type
|
|
141
|
+
})
|
|
142
|
+
else:
|
|
143
|
+
self.findings.append({
|
|
144
|
+
'CheckId': self.check_id,
|
|
145
|
+
'Status': 'PASS',
|
|
146
|
+
'Region': region,
|
|
147
|
+
"Severity": self.severity,
|
|
148
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
149
|
+
'Description': self.description,
|
|
150
|
+
'ResourceId': trail_arn,
|
|
151
|
+
'ResourceType': 'AWS::CloudTrail::Trail',
|
|
152
|
+
'AccountId': account_id,
|
|
153
|
+
'CheckedValue': 'CloudWatch Logs Integration Requirements',
|
|
154
|
+
'ActualValue': f'Organization trail {trail_name} has properly configured CloudWatch Logs integration and successfully delivered logs within the last 24 hours',
|
|
155
|
+
'Remediation': 'None required',
|
|
156
|
+
'Service': self.service,
|
|
157
|
+
'CheckLogic': self.check_logic,
|
|
158
|
+
'CheckType': self.check_type
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
except ClientError as e:
|
|
163
|
+
self.findings.append({
|
|
164
|
+
'CheckId': self.check_id,
|
|
165
|
+
'Status': 'ERROR',
|
|
166
|
+
'Region': region,
|
|
167
|
+
"Severity": self.severity,
|
|
168
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
169
|
+
'Description': self.description,
|
|
170
|
+
'ResourceId': account_id,
|
|
171
|
+
'ResourceType': 'AWS::CloudTrail::Trail',
|
|
172
|
+
'AccountId': account_id,
|
|
173
|
+
'CheckedValue': 'API Access',
|
|
174
|
+
'ActualValue': f'Error accessing CloudTrail API: {str(e)}',
|
|
175
|
+
'Remediation': 'Verify CloudTrail API permissions and retry',
|
|
176
|
+
'Service': self.service,
|
|
177
|
+
'CheckLogic': self.check_logic,
|
|
178
|
+
'CheckType': self.check_type
|
|
179
|
+
})
|
|
180
|
+
|
|
181
|
+
except Exception as e:
|
|
182
|
+
self.findings.append({
|
|
183
|
+
'CheckId': self.check_id,
|
|
184
|
+
'Status': 'ERROR',
|
|
185
|
+
'Region': region,
|
|
186
|
+
"Severity": self.severity,
|
|
187
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
188
|
+
'Description': self.description,
|
|
189
|
+
'ResourceId': account_id,
|
|
190
|
+
'ResourceType': 'AWS::CloudTrail::Trail',
|
|
191
|
+
'AccountId': account_id,
|
|
192
|
+
'CheckedValue': 'Check Execution',
|
|
193
|
+
'ActualValue': f'Error running check: {str(e)}',
|
|
194
|
+
'Remediation': 'Review the error message and try again',
|
|
195
|
+
'Service': self.service,
|
|
196
|
+
'CheckLogic': self.check_logic,
|
|
197
|
+
'CheckType': self.check_type
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
return self.findings
|