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.
Files changed (261) hide show
  1. sraverify/__init__.py +36 -0
  2. sraverify/checks/__init__.py +56 -0
  3. sraverify/checks/accessanalyzer/SRA_IAA_1.py +188 -0
  4. sraverify/checks/accessanalyzer/SRA_IAA_2.py +162 -0
  5. sraverify/checks/accessanalyzer/SRA_IAA_3.py +260 -0
  6. sraverify/checks/accessanalyzer/SRA_IAA_4.py +207 -0
  7. sraverify/checks/accessanalyzer/__init__.py +3 -0
  8. sraverify/checks/cloudtrail/SRA-CT-1.py +220 -0
  9. sraverify/checks/cloudtrail/SRA-CT-10.py +229 -0
  10. sraverify/checks/cloudtrail/SRA-CT-11.py +242 -0
  11. sraverify/checks/cloudtrail/SRA-CT-12.py +163 -0
  12. sraverify/checks/cloudtrail/SRA-CT-13.py +279 -0
  13. sraverify/checks/cloudtrail/SRA-CT-2.py +218 -0
  14. sraverify/checks/cloudtrail/SRA-CT-3.py +196 -0
  15. sraverify/checks/cloudtrail/SRA-CT-4.py +161 -0
  16. sraverify/checks/cloudtrail/SRA-CT-5.py +200 -0
  17. sraverify/checks/cloudtrail/SRA-CT-6.py +161 -0
  18. sraverify/checks/cloudtrail/SRA-CT-7.py +194 -0
  19. sraverify/checks/cloudtrail/SRA-CT-8.py +226 -0
  20. sraverify/checks/cloudtrail/SRA-CT-9.py +226 -0
  21. sraverify/checks/cloudtrail/__init__.py +3 -0
  22. sraverify/checks/config/SRA-CONFIG-1.py +197 -0
  23. sraverify/checks/config/__init__.py +3 -0
  24. sraverify/core/__init__.py +3 -0
  25. sraverify/core/check.py +227 -0
  26. sraverify/core/logging.py +37 -0
  27. sraverify/core/session.py +47 -0
  28. sraverify/lib/__init__.py +4 -0
  29. sraverify/lib/audit_info.py +37 -0
  30. sraverify/lib/banner.py +42 -0
  31. sraverify/lib/check_loader.py +80 -0
  32. sraverify/lib/org_mgmt_checker.py +86 -0
  33. sraverify/lib/outputs.py +46 -0
  34. sraverify/lib/progress.py +75 -0
  35. sraverify/lib/regions.py +27 -0
  36. sraverify/lib/session.py +23 -0
  37. sraverify/main.py +350 -0
  38. sraverify/services/__init__.py +3 -0
  39. sraverify/services/accessanalyzer/__init__.py +15 -0
  40. sraverify/services/accessanalyzer/base.py +123 -0
  41. sraverify/services/accessanalyzer/checks/__init__.py +3 -0
  42. sraverify/services/accessanalyzer/checks/sra_accessanalyzer_01.py +82 -0
  43. sraverify/services/accessanalyzer/checks/sra_accessanalyzer_02.py +82 -0
  44. sraverify/services/accessanalyzer/checks/sra_accessanalyzer_03.py +103 -0
  45. sraverify/services/accessanalyzer/checks/sra_accessanalyzer_04.py +139 -0
  46. sraverify/services/accessanalyzer/client.py +123 -0
  47. sraverify/services/account/__init__.py +9 -0
  48. sraverify/services/account/base.py +56 -0
  49. sraverify/services/account/checks/__init__.py +1 -0
  50. sraverify/services/account/checks/sra_account_01.py +65 -0
  51. sraverify/services/account/checks/sra_account_02.py +63 -0
  52. sraverify/services/account/checks/sra_account_03.py +63 -0
  53. sraverify/services/account/client.py +51 -0
  54. sraverify/services/auditmanager/__init__.py +10 -0
  55. sraverify/services/auditmanager/base.py +72 -0
  56. sraverify/services/auditmanager/checks/__init__.py +1 -0
  57. sraverify/services/auditmanager/checks/sra_auditmanager_01.py +58 -0
  58. sraverify/services/auditmanager/checks/sra_auditmanager_02.py +80 -0
  59. sraverify/services/auditmanager/client.py +58 -0
  60. sraverify/services/cloudtrail/__init__.py +33 -0
  61. sraverify/services/cloudtrail/base.py +167 -0
  62. sraverify/services/cloudtrail/checks/__init__.py +1 -0
  63. sraverify/services/cloudtrail/checks/sra_cloudtrail_01.py +83 -0
  64. sraverify/services/cloudtrail/checks/sra_cloudtrail_02.py +99 -0
  65. sraverify/services/cloudtrail/checks/sra_cloudtrail_03.py +94 -0
  66. sraverify/services/cloudtrail/checks/sra_cloudtrail_04.py +92 -0
  67. sraverify/services/cloudtrail/checks/sra_cloudtrail_05.py +106 -0
  68. sraverify/services/cloudtrail/checks/sra_cloudtrail_06.py +93 -0
  69. sraverify/services/cloudtrail/checks/sra_cloudtrail_07.py +96 -0
  70. sraverify/services/cloudtrail/checks/sra_cloudtrail_08.py +145 -0
  71. sraverify/services/cloudtrail/checks/sra_cloudtrail_09.py +167 -0
  72. sraverify/services/cloudtrail/checks/sra_cloudtrail_10.py +162 -0
  73. sraverify/services/cloudtrail/checks/sra_cloudtrail_11.py +178 -0
  74. sraverify/services/cloudtrail/checks/sra_cloudtrail_12.py +77 -0
  75. sraverify/services/cloudtrail/checks/sra_cloudtrail_13.py +120 -0
  76. sraverify/services/cloudtrail/client.py +118 -0
  77. sraverify/services/config/__init__.py +25 -0
  78. sraverify/services/config/base.py +249 -0
  79. sraverify/services/config/checks/__init__.py +1 -0
  80. sraverify/services/config/checks/sra_config_01.py +123 -0
  81. sraverify/services/config/checks/sra_config_02.py +156 -0
  82. sraverify/services/config/checks/sra_config_03.py +149 -0
  83. sraverify/services/config/checks/sra_config_04.py +104 -0
  84. sraverify/services/config/checks/sra_config_05.py +104 -0
  85. sraverify/services/config/checks/sra_config_06.py +194 -0
  86. sraverify/services/config/checks/sra_config_07.py +162 -0
  87. sraverify/services/config/checks/sra_config_08.py +185 -0
  88. sraverify/services/config/checks/sra_config_09.py +177 -0
  89. sraverify/services/config/client.py +264 -0
  90. sraverify/services/ec2/__init__.py +8 -0
  91. sraverify/services/ec2/base.py +75 -0
  92. sraverify/services/ec2/checks/__init__.py +1 -0
  93. sraverify/services/ec2/checks/sra_ec2_01.py +83 -0
  94. sraverify/services/ec2/client.py +63 -0
  95. sraverify/services/firewallmanager/__init__.py +23 -0
  96. sraverify/services/firewallmanager/base.py +48 -0
  97. sraverify/services/firewallmanager/checks/__init__.py +1 -0
  98. sraverify/services/firewallmanager/checks/sra_firewallmanager_01.py +75 -0
  99. sraverify/services/firewallmanager/checks/sra_firewallmanager_02.py +57 -0
  100. sraverify/services/firewallmanager/checks/sra_firewallmanager_03.py +51 -0
  101. sraverify/services/firewallmanager/checks/sra_firewallmanager_04.py +51 -0
  102. sraverify/services/firewallmanager/checks/sra_firewallmanager_05.py +51 -0
  103. sraverify/services/firewallmanager/checks/sra_firewallmanager_06.py +51 -0
  104. sraverify/services/firewallmanager/checks/sra_firewallmanager_07.py +51 -0
  105. sraverify/services/firewallmanager/checks/sra_firewallmanager_08.py +61 -0
  106. sraverify/services/firewallmanager/checks/sra_firewallmanager_09.py +61 -0
  107. sraverify/services/firewallmanager/checks/sra_firewallmanager_10.py +71 -0
  108. sraverify/services/firewallmanager/client.py +40 -0
  109. sraverify/services/guardduty/__init__.py +58 -0
  110. sraverify/services/guardduty/base.py +207 -0
  111. sraverify/services/guardduty/checks/__init__.py +3 -0
  112. sraverify/services/guardduty/checks/sra_guardduty_01.py +51 -0
  113. sraverify/services/guardduty/checks/sra_guardduty_02.py +80 -0
  114. sraverify/services/guardduty/checks/sra_guardduty_03.py +77 -0
  115. sraverify/services/guardduty/checks/sra_guardduty_04.py +84 -0
  116. sraverify/services/guardduty/checks/sra_guardduty_05.py +84 -0
  117. sraverify/services/guardduty/checks/sra_guardduty_06.py +84 -0
  118. sraverify/services/guardduty/checks/sra_guardduty_07.py +85 -0
  119. sraverify/services/guardduty/checks/sra_guardduty_08.py +83 -0
  120. sraverify/services/guardduty/checks/sra_guardduty_09.py +84 -0
  121. sraverify/services/guardduty/checks/sra_guardduty_10.py +83 -0
  122. sraverify/services/guardduty/checks/sra_guardduty_11.py +93 -0
  123. sraverify/services/guardduty/checks/sra_guardduty_12.py +83 -0
  124. sraverify/services/guardduty/checks/sra_guardduty_13.py +90 -0
  125. sraverify/services/guardduty/checks/sra_guardduty_14.py +136 -0
  126. sraverify/services/guardduty/checks/sra_guardduty_15.py +94 -0
  127. sraverify/services/guardduty/checks/sra_guardduty_16.py +94 -0
  128. sraverify/services/guardduty/checks/sra_guardduty_17.py +91 -0
  129. sraverify/services/guardduty/checks/sra_guardduty_18.py +91 -0
  130. sraverify/services/guardduty/checks/sra_guardduty_19.py +91 -0
  131. sraverify/services/guardduty/checks/sra_guardduty_20.py +111 -0
  132. sraverify/services/guardduty/checks/sra_guardduty_21.py +112 -0
  133. sraverify/services/guardduty/checks/sra_guardduty_22.py +111 -0
  134. sraverify/services/guardduty/checks/sra_guardduty_23.py +154 -0
  135. sraverify/services/guardduty/checks/sra_guardduty_24.py +111 -0
  136. sraverify/services/guardduty/checks/sra_guardduty_25.py +111 -0
  137. sraverify/services/guardduty/client.py +107 -0
  138. sraverify/services/inspector/__init__.py +29 -0
  139. sraverify/services/inspector/base.py +233 -0
  140. sraverify/services/inspector/checks/__init__.py +3 -0
  141. sraverify/services/inspector/checks/sra_inspector_01.py +69 -0
  142. sraverify/services/inspector/checks/sra_inspector_02.py +68 -0
  143. sraverify/services/inspector/checks/sra_inspector_03.py +68 -0
  144. sraverify/services/inspector/checks/sra_inspector_04.py +70 -0
  145. sraverify/services/inspector/checks/sra_inspector_05.py +69 -0
  146. sraverify/services/inspector/checks/sra_inspector_06.py +115 -0
  147. sraverify/services/inspector/checks/sra_inspector_07.py +109 -0
  148. sraverify/services/inspector/checks/sra_inspector_08.py +69 -0
  149. sraverify/services/inspector/checks/sra_inspector_09.py +69 -0
  150. sraverify/services/inspector/checks/sra_inspector_10.py +69 -0
  151. sraverify/services/inspector/checks/sra_inspector_11.py +69 -0
  152. sraverify/services/inspector/client.py +99 -0
  153. sraverify/services/macie/__init__.py +27 -0
  154. sraverify/services/macie/base.py +271 -0
  155. sraverify/services/macie/checks/__init__.py +1 -0
  156. sraverify/services/macie/checks/sra_macie_01.py +100 -0
  157. sraverify/services/macie/checks/sra_macie_02.py +102 -0
  158. sraverify/services/macie/checks/sra_macie_03.py +152 -0
  159. sraverify/services/macie/checks/sra_macie_04.py +120 -0
  160. sraverify/services/macie/checks/sra_macie_05.py +85 -0
  161. sraverify/services/macie/checks/sra_macie_06.py +124 -0
  162. sraverify/services/macie/checks/sra_macie_07.py +138 -0
  163. sraverify/services/macie/checks/sra_macie_08.py +82 -0
  164. sraverify/services/macie/checks/sra_macie_09.py +103 -0
  165. sraverify/services/macie/checks/sra_macie_10.py +81 -0
  166. sraverify/services/macie/client.py +220 -0
  167. sraverify/services/s3/__init__.py +16 -0
  168. sraverify/services/s3/base.py +69 -0
  169. sraverify/services/s3/checks/__init__.py +1 -0
  170. sraverify/services/s3/checks/sra_s3_01.py +89 -0
  171. sraverify/services/s3/checks/sra_s3_02.py +89 -0
  172. sraverify/services/s3/checks/sra_s3_03.py +88 -0
  173. sraverify/services/s3/checks/sra_s3_04.py +88 -0
  174. sraverify/services/s3/client.py +52 -0
  175. sraverify/services/securityhub/__init__.py +27 -0
  176. sraverify/services/securityhub/base.py +349 -0
  177. sraverify/services/securityhub/checks/__init__.py +1 -0
  178. sraverify/services/securityhub/checks/sra_securityhub_01.py +115 -0
  179. sraverify/services/securityhub/checks/sra_securityhub_02.py +114 -0
  180. sraverify/services/securityhub/checks/sra_securityhub_03.py +136 -0
  181. sraverify/services/securityhub/checks/sra_securityhub_04.py +75 -0
  182. sraverify/services/securityhub/checks/sra_securityhub_05.py +102 -0
  183. sraverify/services/securityhub/checks/sra_securityhub_06.py +113 -0
  184. sraverify/services/securityhub/checks/sra_securityhub_07.py +121 -0
  185. sraverify/services/securityhub/checks/sra_securityhub_08.py +113 -0
  186. sraverify/services/securityhub/checks/sra_securityhub_09.py +100 -0
  187. sraverify/services/securityhub/checks/sra_securityhub_10.py +94 -0
  188. sraverify/services/securityhub/checks/sra_securityhub_11.py +73 -0
  189. sraverify/services/securityhub/client.py +249 -0
  190. sraverify/services/securityincidentresponse/__init__.py +13 -0
  191. sraverify/services/securityincidentresponse/base.py +95 -0
  192. sraverify/services/securityincidentresponse/checks/__init__.py +1 -0
  193. sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_01.py +77 -0
  194. sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_02.py +72 -0
  195. sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_03.py +86 -0
  196. sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_04.py +117 -0
  197. sraverify/services/securityincidentresponse/checks/sra_securityincidentresponse_05.py +55 -0
  198. sraverify/services/securityincidentresponse/client.py +71 -0
  199. sraverify/services/securitylake/__init__.py +39 -0
  200. sraverify/services/securitylake/base.py +461 -0
  201. sraverify/services/securitylake/checks/__init__.py +1 -0
  202. sraverify/services/securitylake/checks/sra_securitylake_01.py +98 -0
  203. sraverify/services/securitylake/checks/sra_securitylake_02.py +133 -0
  204. sraverify/services/securitylake/checks/sra_securitylake_03.py +116 -0
  205. sraverify/services/securitylake/checks/sra_securitylake_04.py +72 -0
  206. sraverify/services/securitylake/checks/sra_securitylake_05.py +116 -0
  207. sraverify/services/securitylake/checks/sra_securitylake_06.py +104 -0
  208. sraverify/services/securitylake/checks/sra_securitylake_07.py +108 -0
  209. sraverify/services/securitylake/checks/sra_securitylake_08.py +107 -0
  210. sraverify/services/securitylake/checks/sra_securitylake_09.py +107 -0
  211. sraverify/services/securitylake/checks/sra_securitylake_10.py +106 -0
  212. sraverify/services/securitylake/checks/sra_securitylake_11.py +109 -0
  213. sraverify/services/securitylake/checks/sra_securitylake_12.py +108 -0
  214. sraverify/services/securitylake/checks/sra_securitylake_13.py +108 -0
  215. sraverify/services/securitylake/checks/sra_securitylake_14.py +72 -0
  216. sraverify/services/securitylake/checks/sra_securitylake_15.py +120 -0
  217. sraverify/services/securitylake/checks/sra_securitylake_16.py +104 -0
  218. sraverify/services/securitylake/checks/sra_securitylake_17.py +103 -0
  219. sraverify/services/securitylake/client.py +247 -0
  220. sraverify/services/shield/__init__.py +33 -0
  221. sraverify/services/shield/base.py +199 -0
  222. sraverify/services/shield/checks/__init__.py +1 -0
  223. sraverify/services/shield/checks/sra_shield_01.py +68 -0
  224. sraverify/services/shield/checks/sra_shield_02.py +77 -0
  225. sraverify/services/shield/checks/sra_shield_03.py +84 -0
  226. sraverify/services/shield/checks/sra_shield_04.py +84 -0
  227. sraverify/services/shield/checks/sra_shield_05.py +84 -0
  228. sraverify/services/shield/checks/sra_shield_06.py +84 -0
  229. sraverify/services/shield/checks/sra_shield_07.py +84 -0
  230. sraverify/services/shield/checks/sra_shield_08.py +69 -0
  231. sraverify/services/shield/checks/sra_shield_09.py +86 -0
  232. sraverify/services/shield/checks/sra_shield_10.py +100 -0
  233. sraverify/services/shield/checks/sra_shield_11.py +71 -0
  234. sraverify/services/shield/checks/sra_shield_12.py +130 -0
  235. sraverify/services/shield/checks/sra_shield_13.py +112 -0
  236. sraverify/services/shield/checks/sra_shield_14.py +111 -0
  237. sraverify/services/shield/client.py +214 -0
  238. sraverify/services/waf/__init__.py +21 -0
  239. sraverify/services/waf/base.py +100 -0
  240. sraverify/services/waf/checks/__init__.py +1 -0
  241. sraverify/services/waf/checks/sra_waf_01.py +63 -0
  242. sraverify/services/waf/checks/sra_waf_02.py +82 -0
  243. sraverify/services/waf/checks/sra_waf_03.py +123 -0
  244. sraverify/services/waf/checks/sra_waf_04.py +94 -0
  245. sraverify/services/waf/checks/sra_waf_05.py +94 -0
  246. sraverify/services/waf/checks/sra_waf_06.py +91 -0
  247. sraverify/services/waf/checks/sra_waf_07.py +94 -0
  248. sraverify/services/waf/checks/sra_waf_08.py +66 -0
  249. sraverify/services/waf/checks/sra_waf_09.py +95 -0
  250. sraverify/services/waf/client.py +109 -0
  251. sraverify/utils/__init__.py +3 -0
  252. sraverify/utils/banner.py +65 -0
  253. sraverify/utils/outputs.py +57 -0
  254. sraverify/utils/progress.py +97 -0
  255. sraverify-0.1.0.dist-info/LICENSE +175 -0
  256. sraverify-0.1.0.dist-info/METADATA +516 -0
  257. sraverify-0.1.0.dist-info/NOTICE +1 -0
  258. sraverify-0.1.0.dist-info/RECORD +261 -0
  259. sraverify-0.1.0.dist-info/WHEEL +5 -0
  260. sraverify-0.1.0.dist-info/entry_points.txt +2 -0
  261. 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