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,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 SRACT6(SecurityCheck):
|
|
7
|
+
"""SRA-CT-6: Organization Trail Global Service Events 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-6"
|
|
13
|
+
self.check_name = "Organization Trail Global Service Events Configuration"
|
|
14
|
+
self.description = ('This check verifies that your organization trail is configured to log global service events. '
|
|
15
|
+
'Global service events are activities that occur in global services like IAM, STS, and CloudFront. '
|
|
16
|
+
'Logging these events is crucial for maintaining a complete audit trail of activities in your AWS environment.')
|
|
17
|
+
self.service = "CloudTrail"
|
|
18
|
+
self.severity = "HIGH"
|
|
19
|
+
self.check_type = check_type
|
|
20
|
+
self.check_logic = ('1. Verify execution from Organization Management account | '
|
|
21
|
+
'2. List CloudTrail trails in current region and identify organization trails (IsOrganizationTrail=true) | '
|
|
22
|
+
'3. For each organization trail, verify IncludeGlobalServiceEvents=true | '
|
|
23
|
+
'4. Check passes if at least one organization trail is properly configured for global service events')
|
|
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 global service events enabled",
|
|
86
|
+
"Service": self.service,
|
|
87
|
+
"CheckLogic": self.check_logic,
|
|
88
|
+
"CheckType": self.check_type
|
|
89
|
+
})
|
|
90
|
+
return
|
|
91
|
+
|
|
92
|
+
# Check for global service events configuration
|
|
93
|
+
global_events_trail = None
|
|
94
|
+
for trail in org_trails:
|
|
95
|
+
if trail.get('IncludeGlobalServiceEvents'):
|
|
96
|
+
global_events_trail = trail
|
|
97
|
+
self.logger.debug(f"Found trail with global service events enabled: {trail['Name']}")
|
|
98
|
+
break
|
|
99
|
+
|
|
100
|
+
# Create finding based on global service events configuration
|
|
101
|
+
status = "PASS" if global_events_trail else "FAIL"
|
|
102
|
+
actual_value = (f"Organization trail {global_events_trail['Name'] if global_events_trail else org_trails[0]['Name']} "
|
|
103
|
+
f"{'has' if global_events_trail else 'does not have'} global service events enabled")
|
|
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": (global_events_trail or org_trails[0])['TrailARN'],
|
|
113
|
+
"ResourceType": "AWS::CloudTrail::Trail",
|
|
114
|
+
"AccountId": account_id,
|
|
115
|
+
"CheckedValue": "Global Service Events Configuration",
|
|
116
|
+
"ActualValue": actual_value,
|
|
117
|
+
"Remediation": "None required" if global_events_trail else "Enable global service events for the organization trail",
|
|
118
|
+
"Service": self.service,
|
|
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": self.service,
|
|
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": self.service,
|
|
159
|
+
"CheckLogic": self.check_logic,
|
|
160
|
+
"CheckType": self.check_type
|
|
161
|
+
})
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
from typing import Dict, List, Any, Optional
|
|
2
|
+
from sraverify.checks import SecurityCheck
|
|
3
|
+
from botocore.exceptions import ClientError
|
|
4
|
+
import logging
|
|
5
|
+
|
|
6
|
+
class SRACT7(SecurityCheck):
|
|
7
|
+
"""SRA-CT-7: Organization trail is actively publishing events"""
|
|
8
|
+
|
|
9
|
+
def __init__(self, check_type="account"):
|
|
10
|
+
"""Initialize the check with account type"""
|
|
11
|
+
super().__init__(check_type=check_type)
|
|
12
|
+
self.check_id = "SRA-CT-7"
|
|
13
|
+
self.check_name = "Organization trail is actively publishing events from accounts"
|
|
14
|
+
self.description = ('This check verifies that your organization trail is running and actively '
|
|
15
|
+
'logging events. If a trail is modified to stop logging, accidentally or by '
|
|
16
|
+
'malicious user, you will not have visibility into API activity.')
|
|
17
|
+
self.service = "CloudTrail"
|
|
18
|
+
self.severity = "HIGH"
|
|
19
|
+
self.check_type = check_type
|
|
20
|
+
self.check_logic = ('1. List CloudTrail trails in current region | '
|
|
21
|
+
'2. Check for organization trail with IsOrganizationTrail=true | '
|
|
22
|
+
'3. Verify trail is actively logging')
|
|
23
|
+
self.logger = logging.getLogger(self.__class__.__name__)
|
|
24
|
+
self.findings = []
|
|
25
|
+
self._regions = None
|
|
26
|
+
|
|
27
|
+
def initialize(self, regions: Optional[List[str]] = None):
|
|
28
|
+
"""Initialize check with optional regions"""
|
|
29
|
+
self._regions = regions
|
|
30
|
+
|
|
31
|
+
def get_findings(self) -> List[Dict[str, Any]]:
|
|
32
|
+
"""Return the findings"""
|
|
33
|
+
return self.findings
|
|
34
|
+
|
|
35
|
+
def check_trail_status(self, cloudtrail_client, trail_name: str) -> bool:
|
|
36
|
+
"""Check if trail is actively logging"""
|
|
37
|
+
try:
|
|
38
|
+
status = cloudtrail_client.get_trail_status(Name=trail_name)
|
|
39
|
+
return status.get('IsLogging', False)
|
|
40
|
+
except ClientError as e:
|
|
41
|
+
self.logger.error(f"Error getting trail status for {trail_name}: {str(e)}")
|
|
42
|
+
return False
|
|
43
|
+
|
|
44
|
+
def check_region(self, session, region: str, account_id: str):
|
|
45
|
+
"""Check CloudTrail configuration in a specific region"""
|
|
46
|
+
try:
|
|
47
|
+
# Initialize CloudTrail client for this region
|
|
48
|
+
cloudtrail_client = session.client('cloudtrail', region_name=region)
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
# List trails and find organization trails
|
|
52
|
+
trails = cloudtrail_client.describe_trails(includeShadowTrails=True)
|
|
53
|
+
org_trails = [t for t in trails['trailList'] if t.get('IsOrganizationTrail')]
|
|
54
|
+
self.logger.debug(f"Found {len(org_trails)} organization trails in {region}")
|
|
55
|
+
|
|
56
|
+
if not org_trails:
|
|
57
|
+
self.findings.append({
|
|
58
|
+
"CheckId": self.check_id,
|
|
59
|
+
"Status": "FAIL",
|
|
60
|
+
"Region": region,
|
|
61
|
+
"Severity": self.severity,
|
|
62
|
+
"Title": f"{self.check_id} {self.check_name}",
|
|
63
|
+
"Description": self.description,
|
|
64
|
+
"ResourceId": "organization-trail",
|
|
65
|
+
"ResourceType": "AWS::CloudTrail::Trail",
|
|
66
|
+
"AccountId": account_id,
|
|
67
|
+
"CheckedValue": "Organization Trail Configuration",
|
|
68
|
+
"ActualValue": "No organization trail found",
|
|
69
|
+
"Remediation": "Create an organization trail",
|
|
70
|
+
"Service": self.service,
|
|
71
|
+
"CheckLogic": self.check_logic,
|
|
72
|
+
"CheckType": self.check_type
|
|
73
|
+
})
|
|
74
|
+
return
|
|
75
|
+
|
|
76
|
+
# Check each organization trail for logging status
|
|
77
|
+
active_trail = None
|
|
78
|
+
for trail in org_trails:
|
|
79
|
+
trail_name = trail['Name']
|
|
80
|
+
if self.check_trail_status(cloudtrail_client, trail_name):
|
|
81
|
+
active_trail = trail
|
|
82
|
+
self.logger.debug(f"Found active trail: {trail_name} in {region}")
|
|
83
|
+
break
|
|
84
|
+
|
|
85
|
+
if active_trail:
|
|
86
|
+
self.findings.append({
|
|
87
|
+
"CheckId": self.check_id,
|
|
88
|
+
"Status": "PASS",
|
|
89
|
+
"Region": region,
|
|
90
|
+
"Severity": self.severity,
|
|
91
|
+
"Title": f"{self.check_id} {self.check_name}",
|
|
92
|
+
"Description": self.description,
|
|
93
|
+
"ResourceId": active_trail['TrailARN'],
|
|
94
|
+
"ResourceType": "AWS::CloudTrail::Trail",
|
|
95
|
+
"AccountId": account_id,
|
|
96
|
+
"CheckedValue": "Trail Logging Status",
|
|
97
|
+
"ActualValue": f"Organization trail {active_trail['Name']} is actively logging",
|
|
98
|
+
"Remediation": "None required",
|
|
99
|
+
"Service": self.service,
|
|
100
|
+
"CheckLogic": self.check_logic,
|
|
101
|
+
"CheckType": self.check_type
|
|
102
|
+
})
|
|
103
|
+
else:
|
|
104
|
+
trail = org_trails[0]
|
|
105
|
+
self.findings.append({
|
|
106
|
+
"CheckId": self.check_id,
|
|
107
|
+
"Status": "FAIL",
|
|
108
|
+
"Region": region,
|
|
109
|
+
"Severity": self.severity,
|
|
110
|
+
"Title": f"{self.check_id} {self.check_name}",
|
|
111
|
+
"Description": self.description,
|
|
112
|
+
"ResourceId": trail['TrailARN'],
|
|
113
|
+
"ResourceType": "AWS::CloudTrail::Trail",
|
|
114
|
+
"AccountId": account_id,
|
|
115
|
+
"CheckedValue": "Trail Logging Status",
|
|
116
|
+
"ActualValue": f"Organization trail {trail['Name']} is not actively logging",
|
|
117
|
+
"Remediation": "Start logging for the organization trail",
|
|
118
|
+
"Service": self.service,
|
|
119
|
+
"CheckLogic": self.check_logic,
|
|
120
|
+
"CheckType": self.check_type
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
except ClientError as e:
|
|
124
|
+
self.findings.append({
|
|
125
|
+
"CheckId": self.check_id,
|
|
126
|
+
"Status": "ERROR",
|
|
127
|
+
"Region": region,
|
|
128
|
+
"Severity": self.severity,
|
|
129
|
+
"Title": f"{self.check_id} {self.check_name}",
|
|
130
|
+
"Description": self.description,
|
|
131
|
+
"ResourceId": "cloudtrail",
|
|
132
|
+
"ResourceType": "AWS::CloudTrail::Trail",
|
|
133
|
+
"AccountId": account_id,
|
|
134
|
+
"CheckedValue": "CloudTrail API Access",
|
|
135
|
+
"ActualValue": f"Error accessing CloudTrail: {str(e)}",
|
|
136
|
+
"Remediation": "Verify CloudTrail permissions",
|
|
137
|
+
"Service": self.service,
|
|
138
|
+
"CheckLogic": self.check_logic,
|
|
139
|
+
"CheckType": self.check_type
|
|
140
|
+
})
|
|
141
|
+
|
|
142
|
+
except Exception as e:
|
|
143
|
+
self.findings.append({
|
|
144
|
+
"CheckId": self.check_id,
|
|
145
|
+
"Status": "ERROR",
|
|
146
|
+
"Region": region,
|
|
147
|
+
"Severity": self.severity,
|
|
148
|
+
"Title": f"{self.check_id} {self.check_name}",
|
|
149
|
+
"Description": self.description,
|
|
150
|
+
"ResourceId": "check-execution",
|
|
151
|
+
"ResourceType": "AWS::CloudTrail::Trail",
|
|
152
|
+
"AccountId": account_id,
|
|
153
|
+
"CheckedValue": "Check Execution",
|
|
154
|
+
"ActualValue": f"Error: {str(e)}",
|
|
155
|
+
"Remediation": "Check logs for more details",
|
|
156
|
+
"Service": self.service,
|
|
157
|
+
"CheckLogic": self.check_logic,
|
|
158
|
+
"CheckType": self.check_type
|
|
159
|
+
})
|
|
160
|
+
|
|
161
|
+
def run(self, session):
|
|
162
|
+
"""Run the security check"""
|
|
163
|
+
try:
|
|
164
|
+
# Get account information
|
|
165
|
+
sts_client = session.client('sts')
|
|
166
|
+
account_id = sts_client.get_caller_identity()['Account']
|
|
167
|
+
|
|
168
|
+
# Get regions to check
|
|
169
|
+
regions_to_check = self._regions if self._regions else [session.region_name]
|
|
170
|
+
self.logger.debug(f"Checking regions: {regions_to_check}")
|
|
171
|
+
|
|
172
|
+
# Check each region
|
|
173
|
+
for region in regions_to_check:
|
|
174
|
+
self.check_region(session, region, account_id)
|
|
175
|
+
|
|
176
|
+
except Exception as e:
|
|
177
|
+
self.logger.error(f"Unexpected error in check: {str(e)}")
|
|
178
|
+
self.findings.append({
|
|
179
|
+
"CheckId": self.check_id,
|
|
180
|
+
"Status": "ERROR",
|
|
181
|
+
"Region": session.region_name,
|
|
182
|
+
"Severity": self.severity,
|
|
183
|
+
"Title": f"{self.check_id} {self.check_name}",
|
|
184
|
+
"Description": self.description,
|
|
185
|
+
"ResourceId": "check-execution",
|
|
186
|
+
"ResourceType": "AWS::CloudTrail::Trail",
|
|
187
|
+
"AccountId": account_id if 'account_id' in locals() else "unknown",
|
|
188
|
+
"CheckedValue": "Check Execution",
|
|
189
|
+
"ActualValue": f"Unexpected error: {str(e)}",
|
|
190
|
+
"Remediation": "Contact support team",
|
|
191
|
+
"Service": self.service,
|
|
192
|
+
"CheckLogic": self.check_logic,
|
|
193
|
+
"CheckType": self.check_type
|
|
194
|
+
})
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
from typing import Dict, List, Any
|
|
2
|
+
from sraverify.checks import SecurityCheck
|
|
3
|
+
from botocore.exceptions import ClientError
|
|
4
|
+
import logging
|
|
5
|
+
from datetime import datetime, timezone
|
|
6
|
+
|
|
7
|
+
class SRACT8(SecurityCheck):
|
|
8
|
+
"""SRA-CT-8: Organization Trail S3 Delivery Status"""
|
|
9
|
+
|
|
10
|
+
def __init__(self, check_type="organization"):
|
|
11
|
+
"""Initialize the check with organization type"""
|
|
12
|
+
super().__init__(check_type=check_type)
|
|
13
|
+
self.check_id = "SRA-CT-8"
|
|
14
|
+
self.check_name = "Organization trail is publishing logs to destination S3 bucket"
|
|
15
|
+
self.description = ('This check verifies that last attempt to send CloudTrail logs to S3 bucket was successful. '
|
|
16
|
+
'CloudTrail log files are an audit log of actions taken by an IAM identity or an AWS service. '
|
|
17
|
+
'The integrity, completeness and availability of these logs is crucial for forensic and auditing purposes. '
|
|
18
|
+
'By logging to a dedicated and centralized Amazon S3 bucket, you can enforce strict security controls, '
|
|
19
|
+
'access, and segregation of duties.')
|
|
20
|
+
self.service = "CloudTrail"
|
|
21
|
+
self.severity = "HIGH"
|
|
22
|
+
self.check_type = check_type
|
|
23
|
+
self.check_logic = ('1. Verify execution from Organization Management Account | '
|
|
24
|
+
'2. List CloudTrail trails in current region | '
|
|
25
|
+
'3. Check for organization trail with IsOrganizationTrail=true | '
|
|
26
|
+
'4. Verify S3 bucket configuration and successful log delivery by checking: '
|
|
27
|
+
'a) S3 bucket is configured, b) No delivery errors exist, '
|
|
28
|
+
'c) Latest delivery was successful within 24 hours')
|
|
29
|
+
self.logger = logging.getLogger(self.__class__.__name__)
|
|
30
|
+
self.findings = []
|
|
31
|
+
|
|
32
|
+
def get_findings(self) -> List[Dict[str, Any]]:
|
|
33
|
+
"""Return the findings"""
|
|
34
|
+
return self.findings
|
|
35
|
+
|
|
36
|
+
def check_trail_delivery_status(self, cloudtrail_client, trail_name: str) -> tuple:
|
|
37
|
+
"""Check trail delivery status and return status details"""
|
|
38
|
+
try:
|
|
39
|
+
status = cloudtrail_client.get_trail_status(Name=trail_name)
|
|
40
|
+
latest_delivery_time = status.get('LatestDeliveryTime')
|
|
41
|
+
latest_delivery_error = status.get('LatestDeliveryError', '')
|
|
42
|
+
is_logging = status.get('IsLogging', False)
|
|
43
|
+
|
|
44
|
+
# Step 1: Verify we're in management account using org_mgmt_checker
|
|
45
|
+
is_management, error_message = self.org_checker.verify_org_management()
|
|
46
|
+
if not is_management:
|
|
47
|
+
finding = {
|
|
48
|
+
'CheckId': self.check_id,
|
|
49
|
+
'Status': 'ERROR',
|
|
50
|
+
'Region': region,
|
|
51
|
+
"Severity": self.severity,
|
|
52
|
+
'Title': f"{self.check_id} {self.check_name}",
|
|
53
|
+
'Description': self.description,
|
|
54
|
+
'ResourceId': account_id,
|
|
55
|
+
'ResourceType': 'AWS::Organizations::Account',
|
|
56
|
+
'AccountId': account_id,
|
|
57
|
+
'CheckedValue': 'Management Account Access',
|
|
58
|
+
'ActualValue': error_message if error_message else 'Not running from management account',
|
|
59
|
+
'Remediation': 'Run this check from the Organization Management Account',
|
|
60
|
+
'Service': self.service,
|
|
61
|
+
'CheckLogic': self.check_logic,
|
|
62
|
+
'CheckType': self.check_type
|
|
63
|
+
}
|
|
64
|
+
self.findings.append(finding)
|
|
65
|
+
return self.findings
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# Check if delivery is recent (within 24 hours)
|
|
70
|
+
current_time = datetime.now(timezone.utc)
|
|
71
|
+
is_recent = False
|
|
72
|
+
if latest_delivery_time:
|
|
73
|
+
time_difference = current_time - latest_delivery_time
|
|
74
|
+
is_recent = time_difference.total_seconds() < 86400 # 24 hours
|
|
75
|
+
|
|
76
|
+
return is_logging, is_recent, latest_delivery_error
|
|
77
|
+
|
|
78
|
+
except ClientError as e:
|
|
79
|
+
self.logger.error(f"Error getting trail status for {trail_name}: {str(e)}")
|
|
80
|
+
return False, False, str(e)
|
|
81
|
+
|
|
82
|
+
def run(self, session) -> None:
|
|
83
|
+
"""Run the security check"""
|
|
84
|
+
try:
|
|
85
|
+
# Get account information
|
|
86
|
+
sts_client = session.client('sts')
|
|
87
|
+
account_id = sts_client.get_caller_identity()['Account']
|
|
88
|
+
region = session.region_name
|
|
89
|
+
self.logger.debug(f"Running check for account: {account_id} in region: {region}")
|
|
90
|
+
|
|
91
|
+
# Initialize CloudTrail client
|
|
92
|
+
cloudtrail_client = session.client('cloudtrail')
|
|
93
|
+
|
|
94
|
+
try:
|
|
95
|
+
# List trails and find organization trails
|
|
96
|
+
trails = cloudtrail_client.describe_trails(includeShadowTrails=True)
|
|
97
|
+
org_trails = [t for t in trails['trailList'] if t.get('IsOrganizationTrail')]
|
|
98
|
+
self.logger.debug(f"Found {len(org_trails)} organization trails")
|
|
99
|
+
|
|
100
|
+
if not org_trails:
|
|
101
|
+
self.findings.append({
|
|
102
|
+
"CheckId": self.check_id,
|
|
103
|
+
"Status": "FAIL",
|
|
104
|
+
"Region": region,
|
|
105
|
+
"Severity": self.severity,
|
|
106
|
+
"Title": f"{self.check_id} {self.check_name}",
|
|
107
|
+
"Description": self.description,
|
|
108
|
+
"ResourceId": "organization-trail",
|
|
109
|
+
"ResourceType": "AWS::CloudTrail::Trail",
|
|
110
|
+
"AccountId": account_id,
|
|
111
|
+
"CheckedValue": "Organization Trail Configuration",
|
|
112
|
+
"ActualValue": "No organization trail found",
|
|
113
|
+
"Remediation": "Create an organization trail with S3 bucket configuration",
|
|
114
|
+
"Service": self.service,
|
|
115
|
+
"CheckLogic": self.check_logic,
|
|
116
|
+
"CheckType": self.check_type
|
|
117
|
+
})
|
|
118
|
+
return
|
|
119
|
+
|
|
120
|
+
# Check each organization trail for S3 delivery status
|
|
121
|
+
valid_trail = None
|
|
122
|
+
for trail in org_trails:
|
|
123
|
+
trail_name = trail['Name']
|
|
124
|
+
s3_bucket = trail.get('S3BucketName')
|
|
125
|
+
|
|
126
|
+
if not s3_bucket:
|
|
127
|
+
continue
|
|
128
|
+
|
|
129
|
+
is_logging, is_recent, delivery_error = self.check_trail_delivery_status(cloudtrail_client, trail_name)
|
|
130
|
+
|
|
131
|
+
if is_logging and is_recent and not delivery_error:
|
|
132
|
+
valid_trail = trail
|
|
133
|
+
self.logger.debug(f"Found valid trail with successful S3 delivery: {trail_name}")
|
|
134
|
+
break
|
|
135
|
+
|
|
136
|
+
# Create finding based on S3 delivery status
|
|
137
|
+
if valid_trail:
|
|
138
|
+
self.findings.append({
|
|
139
|
+
"CheckId": self.check_id,
|
|
140
|
+
"Status": "PASS",
|
|
141
|
+
"Region": region,
|
|
142
|
+
"Severity": self.severity,
|
|
143
|
+
"Title": f"{self.check_id} {self.check_name}",
|
|
144
|
+
"Description": self.description,
|
|
145
|
+
"ResourceId": valid_trail['TrailARN'],
|
|
146
|
+
"ResourceType": "AWS::CloudTrail::Trail",
|
|
147
|
+
"AccountId": account_id,
|
|
148
|
+
"CheckedValue": "S3 Delivery Status",
|
|
149
|
+
"ActualValue": f"Organization trail {valid_trail['Name']} is successfully delivering logs to S3 bucket {valid_trail['S3BucketName']}",
|
|
150
|
+
"Remediation": "None required",
|
|
151
|
+
"Service": self.service,
|
|
152
|
+
"CheckLogic": self.check_logic,
|
|
153
|
+
"CheckType": self.check_type
|
|
154
|
+
})
|
|
155
|
+
else:
|
|
156
|
+
actual_value = "No organization trail found with successful recent S3 delivery"
|
|
157
|
+
remediation = "Verify S3 bucket configuration and CloudTrail permissions"
|
|
158
|
+
if org_trails:
|
|
159
|
+
trail = org_trails[0]
|
|
160
|
+
if not trail.get('S3BucketName'):
|
|
161
|
+
actual_value = f"Trail {trail['Name']} has no S3 bucket configured"
|
|
162
|
+
remediation = "Configure S3 bucket for the organization trail"
|
|
163
|
+
elif delivery_error:
|
|
164
|
+
actual_value = f"Trail {trail['Name']} has delivery error: {delivery_error}"
|
|
165
|
+
remediation = "Resolve S3 delivery errors (check S3 bucket permissions)"
|
|
166
|
+
elif not is_recent:
|
|
167
|
+
actual_value = f"Trail {trail['Name']} has no recent log delivery"
|
|
168
|
+
remediation = "Verify trail logging is enabled and check CloudWatch logs for errors"
|
|
169
|
+
|
|
170
|
+
self.findings.append({
|
|
171
|
+
"CheckId": self.check_id,
|
|
172
|
+
"Status": "FAIL",
|
|
173
|
+
"Region": region,
|
|
174
|
+
"Severity": self.severity,
|
|
175
|
+
"Title": f"{self.check_id} {self.check_name}",
|
|
176
|
+
"Description": self.description,
|
|
177
|
+
"ResourceId": (valid_trail or org_trails[0])['TrailARN'],
|
|
178
|
+
"ResourceType": "AWS::CloudTrail::Trail",
|
|
179
|
+
"AccountId": account_id,
|
|
180
|
+
"CheckedValue": "S3 Delivery Status",
|
|
181
|
+
"ActualValue": actual_value,
|
|
182
|
+
"Remediation": remediation,
|
|
183
|
+
"Service": self.service,
|
|
184
|
+
"CheckLogic": self.check_logic,
|
|
185
|
+
"CheckType": self.check_type
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
except ClientError as e:
|
|
189
|
+
self.logger.error(f"Error accessing CloudTrail: {str(e)}")
|
|
190
|
+
self.findings.append({
|
|
191
|
+
"CheckId": self.check_id,
|
|
192
|
+
"Status": "ERROR",
|
|
193
|
+
"Region": region,
|
|
194
|
+
"Severity": self.severity,
|
|
195
|
+
"Title": f"{self.check_id} {self.check_name}",
|
|
196
|
+
"Description": self.description,
|
|
197
|
+
"ResourceId": "cloudtrail",
|
|
198
|
+
"ResourceType": "AWS::CloudTrail::Trail",
|
|
199
|
+
"AccountId": account_id,
|
|
200
|
+
"CheckedValue": "CloudTrail API Access",
|
|
201
|
+
"ActualValue": f"Error accessing CloudTrail: {str(e)}",
|
|
202
|
+
"Remediation": "Verify CloudTrail permissions",
|
|
203
|
+
"Service": self.service,
|
|
204
|
+
"CheckLogic": self.check_logic,
|
|
205
|
+
"CheckType": self.check_type
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
except Exception as e:
|
|
209
|
+
self.logger.error(f"Unexpected error in check: {str(e)}")
|
|
210
|
+
self.findings.append({
|
|
211
|
+
"CheckId": self.check_id,
|
|
212
|
+
"Status": "ERROR",
|
|
213
|
+
"Region": region if 'region' in locals() else session.region_name,
|
|
214
|
+
"Severity": self.severity,
|
|
215
|
+
"Title": f"{self.check_id} {self.check_name}",
|
|
216
|
+
"Description": self.description,
|
|
217
|
+
"ResourceId": "check-execution",
|
|
218
|
+
"ResourceType": "AWS::CloudTrail::Trail",
|
|
219
|
+
"AccountId": account_id if 'account_id' in locals() else "unknown",
|
|
220
|
+
"CheckedValue": "Check Execution",
|
|
221
|
+
"ActualValue": f"Unexpected error: {str(e)}",
|
|
222
|
+
"Remediation": "Contact support team",
|
|
223
|
+
"Service": self.service,
|
|
224
|
+
"CheckLogic": self.check_logic,
|
|
225
|
+
"CheckType": self.check_type
|
|
226
|
+
})
|