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,51 @@
1
+ """
2
+ Account client for interacting with AWS Account Management service.
3
+ """
4
+ from typing import Dict, Optional, Any
5
+ import boto3
6
+ from botocore.exceptions import ClientError
7
+ from sraverify.core.logging import logger
8
+
9
+
10
+ class AccountClient:
11
+ """Client for interacting with AWS Account Management service."""
12
+
13
+ def __init__(self, region: str, session: Optional[boto3.Session] = None):
14
+ """
15
+ Initialize Account client for a specific region.
16
+
17
+ Args:
18
+ region: AWS region name
19
+ session: AWS session to use (if None, a new session will be created)
20
+ """
21
+ self.region = region
22
+ self.session = session or boto3.Session()
23
+ self.client = self.session.client('account', region_name=region)
24
+
25
+ def get_alternate_contact(self, contact_type: str, account_id: Optional[str] = None) -> Dict[str, Any]:
26
+ """
27
+ Get alternate contact information for the specified type.
28
+
29
+ Args:
30
+ contact_type: Type of contact (BILLING, OPERATIONS, or SECURITY)
31
+ account_id: Optional account ID (defaults to current account)
32
+
33
+ Returns:
34
+ Dictionary containing contact details or error information
35
+ """
36
+ try:
37
+ params = {"AlternateContactType": contact_type}
38
+ if account_id:
39
+ params["AccountId"] = account_id
40
+
41
+ return self.client.get_alternate_contact(**params)
42
+ except ClientError as e:
43
+ error_code = e.response.get('Error', {}).get('Code', '')
44
+ error_message = str(e)
45
+ logger.debug(f"Error getting {contact_type} alternate contact in {self.region}: {error_message}")
46
+ return {
47
+ "Error": {
48
+ "Code": error_code,
49
+ "Message": error_message
50
+ }
51
+ }
@@ -0,0 +1,10 @@
1
+ """
2
+ Audit Manager security checks.
3
+ """
4
+ from sraverify.services.auditmanager.checks.sra_auditmanager_01 import SRA_AUDITMANAGER_01
5
+ from sraverify.services.auditmanager.checks.sra_auditmanager_02 import SRA_AUDITMANAGER_02
6
+
7
+ CHECKS = {
8
+ "SRA-AUDITMANAGER-01": SRA_AUDITMANAGER_01,
9
+ "SRA-AUDITMANAGER-02": SRA_AUDITMANAGER_02,
10
+ }
@@ -0,0 +1,72 @@
1
+ """
2
+ Base class for Audit Manager security checks.
3
+ """
4
+ from typing import Dict, Any
5
+ from sraverify.core.check import SecurityCheck
6
+ from sraverify.services.auditmanager.client import AuditManagerClient
7
+
8
+
9
+ class AuditManagerCheck(SecurityCheck):
10
+ """Base class for all Audit Manager security checks."""
11
+
12
+ # Class-level cache shared across all instances
13
+ _account_status_cache = {}
14
+
15
+ def __init__(self):
16
+ """Initialize Audit Manager base check."""
17
+ super().__init__(
18
+ account_type="application",
19
+ service="AuditManager",
20
+ resource_type="AWS::AuditManager::Account"
21
+ )
22
+
23
+ def _setup_clients(self):
24
+ """Set up Audit Manager clients for each region."""
25
+ self._clients.clear()
26
+ if hasattr(self, 'regions') and self.regions:
27
+ for region in self.regions:
28
+ self._clients[region] = AuditManagerClient(region, session=self.session)
29
+
30
+ def get_account_status(self, region: str) -> Dict[str, Any]:
31
+ """
32
+ Get account status for a specific region with caching.
33
+
34
+ Args:
35
+ region: AWS region name
36
+
37
+ Returns:
38
+ Account status response or error information
39
+ """
40
+ cache_key = f"{self.account_id}:{region}"
41
+ if cache_key in AuditManagerCheck._account_status_cache:
42
+ return AuditManagerCheck._account_status_cache[cache_key]
43
+
44
+ client = self.get_client(region)
45
+ if not client:
46
+ return {"Error": {"Code": "NoClient", "Message": f"No client available for region {region}"}}
47
+
48
+ status = client.get_account_status()
49
+ AuditManagerCheck._account_status_cache[cache_key] = status
50
+ return status
51
+
52
+ def get_organization_admin_account(self, region: str) -> Dict[str, Any]:
53
+ """
54
+ Get organization admin account for a specific region with caching.
55
+
56
+ Args:
57
+ region: AWS region name
58
+
59
+ Returns:
60
+ Organization admin account response or error information
61
+ """
62
+ cache_key = f"org_admin:{region}"
63
+ if cache_key in AuditManagerCheck._account_status_cache:
64
+ return AuditManagerCheck._account_status_cache[cache_key]
65
+
66
+ client = self.get_client(region)
67
+ if not client:
68
+ return {"Error": {"Code": "NoClient", "Message": f"No client available for region {region}"}}
69
+
70
+ admin_info = client.get_organization_admin_account()
71
+ AuditManagerCheck._account_status_cache[cache_key] = admin_info
72
+ return admin_info
@@ -0,0 +1 @@
1
+ # Audit Manager checks
@@ -0,0 +1,58 @@
1
+ """
2
+ Check if AWS Audit Manager is enabled.
3
+ """
4
+ from typing import Dict, List, Any
5
+ from sraverify.services.auditmanager.base import AuditManagerCheck
6
+
7
+
8
+ class SRA_AUDITMANAGER_01(AuditManagerCheck):
9
+ """Check if AWS Audit Manager is enabled."""
10
+
11
+ def __init__(self):
12
+ """Initialize Audit Manager enabled check."""
13
+ super().__init__()
14
+ self.check_id = "SRA-AUDITMANAGER-01"
15
+ self.check_name = "AWS Audit Manager is enabled"
16
+ self.description = "This check verifies that AWS Audit Manager is enabled in the AWS account. Audit Manager helps you continuously audit your AWS usage to simplify how you assess risk and compliance with regulations and industry standards."
17
+ self.severity = "MEDIUM"
18
+ self.check_logic = "Check account registration status using GetAccountStatus API. Check passes if status is ACTIVE."
19
+
20
+ def execute(self) -> List[Dict[str, Any]]:
21
+ """
22
+ Execute the check.
23
+
24
+ Returns:
25
+ List of findings
26
+ """
27
+ for region in self.regions:
28
+ status_response = self.get_account_status(region)
29
+
30
+ if "Error" in status_response:
31
+ self.findings.append(self.create_finding(
32
+ status="ERROR",
33
+ region=region,
34
+ resource_id=None,
35
+ actual_value=status_response["Error"].get("Message", "Unknown error"),
36
+ remediation="Check IAM permissions for Audit Manager API access"
37
+ ))
38
+ else:
39
+ account_status = status_response.get("status", "UNKNOWN")
40
+
41
+ if account_status == "ACTIVE":
42
+ self.findings.append(self.create_finding(
43
+ status="PASS",
44
+ region=region,
45
+ resource_id=f"auditmanager:{self.account_id}",
46
+ actual_value=account_status,
47
+ remediation=""
48
+ ))
49
+ else:
50
+ self.findings.append(self.create_finding(
51
+ status="FAIL",
52
+ region=region,
53
+ resource_id=None,
54
+ actual_value=account_status,
55
+ remediation=f"Enable AWS Audit Manager in {region} by registering the account using the RegisterAccount API or AWS console"
56
+ ))
57
+
58
+ return self.findings
@@ -0,0 +1,80 @@
1
+ """
2
+ Check if Audit Manager delegated admin is the audit account.
3
+ """
4
+ from typing import Dict, List, Any
5
+ from sraverify.services.auditmanager.base import AuditManagerCheck
6
+
7
+
8
+ class SRA_AUDITMANAGER_02(AuditManagerCheck):
9
+ """Check if Audit Manager delegated admin is the audit account."""
10
+
11
+ def __init__(self):
12
+ """Initialize Audit Manager delegated admin check."""
13
+ super().__init__()
14
+ self.account_type = "management"
15
+ self.check_id = "SRA-AUDITMANAGER-02"
16
+ self.check_name = "Audit Manager delegated admin is the audit account"
17
+ self.description = "This check verifies that the AWS Audit Manager delegated administrator is configured as the audit account. The delegated administrator should be the security tooling account to centralize audit management."
18
+ self.severity = "HIGH"
19
+ self.check_logic = "Get organization admin account using GetOrganizationAdminAccount API and verify it matches the audit account ID."
20
+
21
+ def execute(self) -> List[Dict[str, Any]]:
22
+ """
23
+ Execute the check.
24
+
25
+ Returns:
26
+ List of findings
27
+ """
28
+ for region in self.regions:
29
+ admin_response = self.get_organization_admin_account(region)
30
+
31
+ if "Error" in admin_response:
32
+ error_code = admin_response["Error"].get("Code", "")
33
+ error_message = admin_response["Error"].get("Message", "")
34
+
35
+ if error_code == "ResourceNotFoundException":
36
+ self.findings.append(self.create_finding(
37
+ status="FAIL",
38
+ region=region,
39
+ resource_id=None,
40
+ actual_value="No delegated administrator configured",
41
+ remediation=f"Configure a delegated administrator for Audit Manager in {region} using RegisterOrganizationAdminAccount API"
42
+ ))
43
+ elif "Please complete AWS Audit Manager setup" in error_message:
44
+ self.findings.append(self.create_finding(
45
+ status="FAIL",
46
+ region=region,
47
+ resource_id=None,
48
+ actual_value="Audit Manager setup not completed in this account",
49
+ remediation=f"Complete AWS Audit Manager setup from the home page in {region} before configuring delegated administrator"
50
+ ))
51
+ else:
52
+ self.findings.append(self.create_finding(
53
+ status="ERROR",
54
+ region=region,
55
+ resource_id=None,
56
+ actual_value=error_message,
57
+ remediation="Check IAM permissions for Audit Manager API access"
58
+ ))
59
+ else:
60
+ admin_account_id = admin_response.get("adminAccountId")
61
+ audit_accounts = getattr(self, '_audit_accounts', [])
62
+
63
+ if admin_account_id in audit_accounts:
64
+ self.findings.append(self.create_finding(
65
+ status="PASS",
66
+ region=region,
67
+ resource_id=f"auditmanager:admin:{admin_account_id}",
68
+ actual_value=admin_account_id,
69
+ remediation=""
70
+ ))
71
+ else:
72
+ self.findings.append(self.create_finding(
73
+ status="FAIL",
74
+ region=region,
75
+ resource_id=f"auditmanager:admin:{admin_account_id}",
76
+ actual_value=admin_account_id,
77
+ remediation=f"Change delegated administrator to audit account in {region}. Current admin: {admin_account_id}, Expected audit accounts: {audit_accounts}"
78
+ ))
79
+
80
+ return self.findings
@@ -0,0 +1,58 @@
1
+ """
2
+ Audit Manager client for interacting with AWS Audit Manager service.
3
+ """
4
+ from typing import Dict, Optional, Any
5
+ import boto3
6
+ from botocore.exceptions import ClientError
7
+ from sraverify.core.logging import logger
8
+
9
+
10
+ class AuditManagerClient:
11
+ """Client for interacting with AWS Audit Manager service."""
12
+
13
+ def __init__(self, region: str, session: Optional[boto3.Session] = None):
14
+ """
15
+ Initialize Audit Manager client for a specific region.
16
+
17
+ Args:
18
+ region: AWS region name
19
+ session: AWS session to use (if None, a new session will be created)
20
+ """
21
+ self.region = region
22
+ self.session = session or boto3.Session()
23
+ self.client = self.session.client('auditmanager', region_name=region)
24
+
25
+ def get_account_status(self) -> Dict[str, Any]:
26
+ """
27
+ Get the registration status of the account in Audit Manager.
28
+
29
+ Returns:
30
+ Dictionary containing status or error information
31
+ """
32
+ try:
33
+ response = self.client.get_account_status()
34
+ return response
35
+ except ClientError as e:
36
+ error_code = e.response.get('Error', {}).get('Code', '')
37
+ error_message = str(e)
38
+ logger.error(f"Error getting account status in {self.region}: {error_message}")
39
+
40
+ def get_organization_admin_account(self) -> Dict[str, Any]:
41
+ """
42
+ Get the delegated administrator account for the organization.
43
+
44
+ Returns:
45
+ Dictionary containing admin account info or error information
46
+ """
47
+ try:
48
+ response = self.client.get_organization_admin_account()
49
+ return response
50
+ except ClientError as e:
51
+ error_code = e.response.get('Error', {}).get('Code', '')
52
+ error_message = str(e)
53
+
54
+ # Don't log setup required errors as they're handled as FAIL in the check
55
+ if "Please complete AWS Audit Manager setup" not in error_message:
56
+ logger.error(f"Error getting organization admin account in {self.region}: {error_message}")
57
+
58
+ return {"Error": {"Code": error_code, "Message": error_message}}
@@ -0,0 +1,33 @@
1
+ """
2
+ Cloudtrail security checks.
3
+ """
4
+ from sraverify.services.cloudtrail.checks.sra_cloudtrail_01 import SRA_CLOUDTRAIL_01
5
+ from sraverify.services.cloudtrail.checks.sra_cloudtrail_02 import SRA_CLOUDTRAIL_02
6
+ from sraverify.services.cloudtrail.checks.sra_cloudtrail_03 import SRA_CLOUDTRAIL_03
7
+ from sraverify.services.cloudtrail.checks.sra_cloudtrail_04 import SRA_CLOUDTRAIL_04
8
+ from sraverify.services.cloudtrail.checks.sra_cloudtrail_05 import SRA_CLOUDTRAIL_05
9
+ from sraverify.services.cloudtrail.checks.sra_cloudtrail_06 import SRA_CLOUDTRAIL_06
10
+ from sraverify.services.cloudtrail.checks.sra_cloudtrail_07 import SRA_CLOUDTRAIL_07
11
+ from sraverify.services.cloudtrail.checks.sra_cloudtrail_08 import SRA_CLOUDTRAIL_08
12
+ from sraverify.services.cloudtrail.checks.sra_cloudtrail_09 import SRA_CLOUDTRAIL_09
13
+ from sraverify.services.cloudtrail.checks.sra_cloudtrail_10 import SRA_CLOUDTRAIL_10
14
+ from sraverify.services.cloudtrail.checks.sra_cloudtrail_11 import SRA_CLOUDTRAIL_11
15
+ from sraverify.services.cloudtrail.checks.sra_cloudtrail_12 import SRA_CLOUDTRAIL_12
16
+ from sraverify.services.cloudtrail.checks.sra_cloudtrail_13 import SRA_CLOUDTRAIL_13
17
+
18
+ # Register checks
19
+ CHECKS = {
20
+ "SRA-CLOUDTRAIL-01": SRA_CLOUDTRAIL_01,
21
+ "SRA-CLOUDTRAIL-02": SRA_CLOUDTRAIL_02,
22
+ "SRA-CLOUDTRAIL-03": SRA_CLOUDTRAIL_03,
23
+ "SRA-CLOUDTRAIL-04": SRA_CLOUDTRAIL_04,
24
+ "SRA-CLOUDTRAIL-05": SRA_CLOUDTRAIL_05,
25
+ "SRA-CLOUDTRAIL-06": SRA_CLOUDTRAIL_06,
26
+ "SRA-CLOUDTRAIL-07": SRA_CLOUDTRAIL_07,
27
+ "SRA-CLOUDTRAIL-08": SRA_CLOUDTRAIL_08,
28
+ "SRA-CLOUDTRAIL-09": SRA_CLOUDTRAIL_09,
29
+ "SRA-CLOUDTRAIL-10": SRA_CLOUDTRAIL_10,
30
+ "SRA-CLOUDTRAIL-11": SRA_CLOUDTRAIL_11,
31
+ "SRA-CLOUDTRAIL-12": SRA_CLOUDTRAIL_12,
32
+ "SRA-CLOUDTRAIL-13": SRA_CLOUDTRAIL_13,
33
+ }
@@ -0,0 +1,167 @@
1
+ """
2
+ Base class for CloudTrail security checks.
3
+ """
4
+ from typing import List, Optional, Dict, Any
5
+ from sraverify.core.check import SecurityCheck
6
+ from sraverify.services.cloudtrail.client import CloudTrailClient
7
+ from sraverify.core.logging import logger
8
+
9
+
10
+ class CloudTrailCheck(SecurityCheck):
11
+ """Base class for all CloudTrail security checks."""
12
+
13
+ # Class-level caches shared across all instances - only keeping the ones specified
14
+ _describe_trails_cache = {}
15
+ _trail_status_cache = {}
16
+ _delegated_admin_account_id_cache = {}
17
+
18
+ def __init__(self):
19
+ """Initialize CloudTrail base check."""
20
+ super().__init__(
21
+ account_type="management",
22
+ service="CloudTrail",
23
+ resource_type="AWS::CloudTrail::Trail"
24
+ )
25
+
26
+ def _setup_clients(self):
27
+ """Set up CloudTrail clients for each region."""
28
+ # Clear existing clients
29
+ self._clients.clear()
30
+ # Set up new clients only if regions are initialized
31
+ if hasattr(self, 'regions') and self.regions:
32
+ for region in self.regions:
33
+ self._clients[region] = CloudTrailClient(region, session=self.session)
34
+
35
+ def get_client(self, region: str) -> Optional[CloudTrailClient]:
36
+ """
37
+ Get CloudTrail client for a specific region.
38
+
39
+ Args:
40
+ region: AWS region name
41
+
42
+ Returns:
43
+ CloudTrailClient for the region or None if not available
44
+ """
45
+ return self._clients.get(region)
46
+
47
+ def describe_trails(self, include_shadow_trails: bool = True) -> List[Dict[str, Any]]:
48
+ """
49
+ Get all CloudTrail trails across all regions using the client with caching.
50
+
51
+ Args:
52
+ include_shadow_trails: Include shadow trails in the response
53
+
54
+ Returns:
55
+ List of all trails
56
+ """
57
+ if not self.regions:
58
+ logger.warning("No regions specified")
59
+ return []
60
+
61
+ # Use session region name as part of cache key
62
+ cache_key = f"describe_trails:{self.session.region_name}:{include_shadow_trails}"
63
+ if cache_key in self.__class__._describe_trails_cache:
64
+ logger.debug(f"Using cached trails for {cache_key}")
65
+ return self.__class__._describe_trails_cache[cache_key]
66
+
67
+ # Use any region to get all trails
68
+ client = self.get_client(self.regions[0])
69
+ if not client:
70
+ logger.warning("No CloudTrail client available")
71
+ return []
72
+
73
+ # Get all trails using the client
74
+ trails = client.describe_trails(include_shadow_trails=include_shadow_trails)
75
+
76
+ # Cache the results
77
+ self.__class__._describe_trails_cache[cache_key] = trails
78
+ logger.debug(f"Cached {len(trails)} trails for {cache_key}")
79
+
80
+ return trails
81
+
82
+ def get_organization_trails(self) -> List[Dict[str, Any]]:
83
+ """
84
+ Get all organization CloudTrail trails.
85
+
86
+ Returns:
87
+ List of organization trails
88
+ """
89
+ # Get all trails first
90
+ all_trails = self.describe_trails()
91
+
92
+ # Filter for organization trails
93
+ org_trails = [
94
+ trail for trail in all_trails
95
+ if trail.get('IsOrganizationTrail', False)
96
+ ]
97
+
98
+ logger.debug(f"Found {len(org_trails)} organization trails")
99
+ return org_trails
100
+
101
+ def get_trail_status(self, region: str, trail_arn: str) -> Dict[str, Any]:
102
+ """
103
+ Get status of a specific CloudTrail trail using the client with caching.
104
+
105
+ Args:
106
+ region: AWS region name
107
+ trail_arn: ARN of the trail
108
+
109
+ Returns:
110
+ Dictionary containing trail status
111
+ """
112
+ # Check cache first
113
+ cache_key = f"{trail_arn}:{region}"
114
+ if cache_key in self.__class__._trail_status_cache:
115
+ logger.debug(f"Using cached trail status for {trail_arn} in {region}")
116
+ return self.__class__._trail_status_cache[cache_key]
117
+
118
+ client = self.get_client(region)
119
+ if not client:
120
+ logger.warning(f"No CloudTrail client available for region {region}")
121
+ return {}
122
+
123
+ # Get trail status from client
124
+ status = client.get_trail_status(trail_arn)
125
+
126
+ # Cache the result
127
+ self.__class__._trail_status_cache[cache_key] = status
128
+ logger.debug(f"Cached trail status for {trail_arn} in {region}")
129
+
130
+ return status
131
+
132
+ def get_delegated_administrators(self) -> List[Dict[str, Any]]:
133
+ """
134
+ Get CloudTrail delegated administrators with caching.
135
+
136
+ Returns:
137
+ List of delegated administrators
138
+ """
139
+ if not self.regions:
140
+ logger.warning("No regions specified")
141
+ return []
142
+
143
+ account_id = self.account_id
144
+ if not account_id:
145
+ logger.warning("Could not determine account ID")
146
+ return []
147
+
148
+ # Check cache first
149
+ cache_key = f"{account_id}:{self.session.region_name}"
150
+ if cache_key in self.__class__._delegated_admin_account_id_cache:
151
+ logger.debug(f"Using cached delegated administrators for {cache_key}")
152
+ return self.__class__._delegated_admin_account_id_cache[cache_key]
153
+
154
+ # Use any region to get delegated administrators
155
+ client = self.get_client(self.regions[0])
156
+ if not client:
157
+ logger.warning("No CloudTrail client available")
158
+ return []
159
+
160
+ # Get delegated administrators from client
161
+ delegated_admins = client.list_delegated_administrators()
162
+
163
+ # Cache the results
164
+ self.__class__._delegated_admin_account_id_cache[cache_key] = delegated_admins
165
+ logger.debug(f"Cached {len(delegated_admins)} delegated administrators for {cache_key}")
166
+
167
+ return delegated_admins
@@ -0,0 +1 @@
1
+ """CloudTrail security checks."""
@@ -0,0 +1,83 @@
1
+ """
2
+ SRA-CLOUDTRAIL-01: Organization CloudTrail Configuration.
3
+ """
4
+ from typing import List, Dict, Any
5
+ from sraverify.services.cloudtrail.base import CloudTrailCheck
6
+ from sraverify.core.logging import logger
7
+
8
+
9
+ class SRA_CLOUDTRAIL_01(CloudTrailCheck):
10
+ """Check if an Organization trail is configured for the AWS Organization."""
11
+
12
+ def __init__(self):
13
+ """Initialize the check."""
14
+ super().__init__()
15
+ self.check_id = "SRA-CLOUDTRAIL-01"
16
+ self.check_name = "An Organization trail is configured for the AWS Organization"
17
+ self.account_type = "management"
18
+ self.severity = "HIGH"
19
+ self.description = (
20
+ "This check verifies that an organization trail is configured for your AWS Organization. "
21
+ "It is important to have uniform logging strategy for your AWS environment. Organization trail "
22
+ "logs all events for all AWS accounts in that organization and delivers logs to a single S3 bucket, "
23
+ "CloudWatch Logs and Event Bridge. Organization trails are automatically applied to all member accounts "
24
+ "in the organization. Member accounts can see the organization trail, but can't modify or delete it. "
25
+ "Organization trail should be configured for all AWS regions even if you are not operating out of any region."
26
+ )
27
+ self.check_logic = (
28
+ "Check if at least one trail has IsOrganizationTrail set to true."
29
+ )
30
+
31
+ def execute(self) -> List[Dict[str, Any]]:
32
+ """
33
+ Execute the check.
34
+
35
+ Returns:
36
+ List of findings
37
+ """
38
+ findings = []
39
+
40
+ # Get all trails using the base class method
41
+ # This will use the cache if available or make API calls if needed
42
+ all_trails = self.describe_trails()
43
+
44
+ # Filter for organization trails
45
+ org_trails = [
46
+ trail for trail in all_trails
47
+ if trail.get('IsOrganizationTrail', False)
48
+ ]
49
+
50
+ if not org_trails:
51
+ findings.append(
52
+ self.create_finding(
53
+ status="FAIL",
54
+ region="global",
55
+ resource_id=f"organization/{self.account_id}",
56
+ checked_value="IsOrganizationTrail: true",
57
+ actual_value="No organization trails found",
58
+ remediation=(
59
+ "Create an organization trail in the management account using the AWS CLI command: "
60
+ f"aws cloudtrail create-trail --name org-trail --is-organization-trail --s3-bucket-name cloudtrail-logs-{self.account_id} "
61
+ f"--is-multi-region-trail --region {self.regions[0] if self.regions else 'us-east-1'}"
62
+ )
63
+ )
64
+ )
65
+ return findings
66
+
67
+ # If we have organization trails, create a PASS finding for each one
68
+ for trail in org_trails:
69
+ trail_name = trail.get('Name', 'Unknown')
70
+ trail_arn = trail.get('TrailARN', 'Unknown')
71
+
72
+ findings.append(
73
+ self.create_finding(
74
+ status="PASS",
75
+ region="global",
76
+ resource_id=trail_arn,
77
+ checked_value="IsOrganizationTrail: true",
78
+ actual_value=f"Organization trail '{trail_name}' is configured",
79
+ remediation="No remediation needed"
80
+ )
81
+ )
82
+
83
+ return findings