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,260 @@
1
+ from typing import Dict, List, Any
2
+ from sraverify.checks import SecurityCheck
3
+ from botocore.exceptions import ClientError
4
+
5
+ class SRAIAA3(SecurityCheck):
6
+ """SRA-IAA-3: IAM Access Analyzer Security Tooling Admin"""
7
+
8
+ def __init__(self, check_type="organization", security_ou_name=None):
9
+ super().__init__(check_type=check_type)
10
+ self.check_id = "SRA-IAA-3"
11
+ self.check_name = "IAM Access Analyzer Security Tooling Admin"
12
+ self.severity = "HIGH"
13
+ self.security_ou_name = security_ou_name.lower() if security_ou_name else None
14
+ self.description = ('This check verifies whether IAA delegated admin account is the security tooling account of '
15
+ 'your AWS organization. Security Tooling account is dedicated to operating security services + '
16
+ 'monitoring AWS accounts + automating security alerting and response. IAA helps monitor '
17
+ 'resources shared outside zone of trust.')
18
+ self.check_logic = ('1. Verify execution from Organization Management account | '
19
+ '2. List all Organization Units and find specified OU (via flag --security-ou-name) or OU containing "security" | '
20
+ '3. Create list of all accounts in Security OU | '
21
+ '4. List delegated administrators for IAM Access Analyzer service | '
22
+ '5. Verify delegated admin account exists in specified Security OU or OU containing "security" | '
23
+ '6. Check passes if delegated admin is found in Security OU account list')
24
+ self.service = 'IAM'
25
+
26
+ def get_findings(self):
27
+ """Return the findings"""
28
+ return self.findings
29
+
30
+ def find_security_ou(self, org_client, root_id):
31
+ """Find the security OU based on name parameter or default search"""
32
+ paginator = org_client.get_paginator('list_organizational_units_for_parent')
33
+ search_term = self.security_ou_name if self.security_ou_name else 'security'
34
+
35
+ for page in paginator.paginate(ParentId=root_id):
36
+ for ou in page['OrganizationalUnits']:
37
+ # If security_ou_name is provided, use exact match
38
+ if self.security_ou_name and self.security_ou_name == ou['Name'].lower():
39
+ return ou['Id'], ou['Name'], search_term
40
+ # If no security_ou_name provided, look for 'security' in name
41
+ elif not self.security_ou_name and 'security' in ou['Name'].lower():
42
+ return ou['Id'], ou['Name'], search_term
43
+
44
+ return None, None, search_term
45
+
46
+ def run(self, session):
47
+ """Run the security check and return findings"""
48
+ try:
49
+ region = session.region_name
50
+ account_id = session.client('sts').get_caller_identity()['Account']
51
+ org_client = session.client('organizations')
52
+
53
+ # Step 1: Verify we're in management account using org_mgmt_checker
54
+ is_management, error_message = self.org_checker.verify_org_management()
55
+ if not is_management:
56
+ finding = {
57
+ 'CheckId': self.check_id,
58
+ 'Status': 'ERROR',
59
+ 'Region': region,
60
+ "Severity": self.severity,
61
+ 'Title': f"{self.check_id} {self.check_name}",
62
+ 'Description': self.description,
63
+ 'ResourceId': account_id,
64
+ 'ResourceType': 'AWS::Organizations::Account',
65
+ 'AccountId': account_id,
66
+ 'CheckedValue': 'Management Account Access',
67
+ 'ActualValue': error_message if error_message else 'Not running from management account',
68
+ 'Remediation': 'Run this check from the Organization Management Account',
69
+ 'Service': self.service,
70
+ 'CheckLogic': self.check_logic,
71
+ 'CheckType': self.check_type
72
+ }
73
+ self.findings.append(finding)
74
+ return self.findings
75
+
76
+ # Step 2 & 3: Find Security OU and list all accounts in it
77
+ security_ou_accounts = []
78
+ try:
79
+ root_id = org_client.list_roots()['Roots'][0]['Id']
80
+
81
+ # Find Security OU using the helper method
82
+ security_ou_id, ou_name, search_term = self.find_security_ou(org_client, root_id)
83
+
84
+ if not security_ou_id:
85
+ finding = {
86
+ 'CheckId': self.check_id,
87
+ 'Status': 'FAIL',
88
+ 'Region': region,
89
+ "Severity": self.severity,
90
+ 'Title': f"{self.check_id} {self.check_name}",
91
+ 'Description': self.description,
92
+ 'ResourceId': account_id,
93
+ 'ResourceType': 'AWS::Organizations::OrganizationalUnit',
94
+ 'AccountId': account_id,
95
+ 'CheckedValue': 'Security OU',
96
+ 'ActualValue': f'No OU matching "{search_term}" found',
97
+ 'Remediation': f'Create appropriate OU matching "{search_term}"',
98
+ 'Service': self.service,
99
+ 'CheckLogic': self.check_logic,
100
+ 'CheckType': self.check_type
101
+ }
102
+ self.findings.append(finding)
103
+ return self.findings
104
+
105
+ # Get all accounts in Security OU
106
+ accounts_paginator = org_client.get_paginator('list_accounts_for_parent')
107
+ for accounts_page in accounts_paginator.paginate(ParentId=security_ou_id):
108
+ security_ou_accounts.extend(accounts_page['Accounts'])
109
+
110
+ if not security_ou_accounts:
111
+ finding = {
112
+ 'CheckId': self.check_id,
113
+ 'Status': 'FAIL',
114
+ 'Region': region,
115
+ "Severity": self.severity,
116
+ 'Title': f"{self.check_id} {self.check_name}",
117
+ 'Description': self.description,
118
+ 'ResourceId': security_ou_id,
119
+ 'ResourceType': 'AWS::Organizations::OrganizationalUnit',
120
+ 'AccountId': account_id,
121
+ 'CheckedValue': f'Accounts in {ou_name} OU',
122
+ 'ActualValue': f'OU: {ou_name}, No accounts found',
123
+ 'Remediation': f'Add accounts to {ou_name} OU',
124
+ 'Service': self.service,
125
+ 'CheckLogic': self.check_logic,
126
+ 'CheckType': self.check_type
127
+ }
128
+ self.findings.append(finding)
129
+ return self.findings
130
+
131
+ # Step 4 & 5: Check IAA delegated administrator and verify it's in Security OU
132
+ try:
133
+ delegated_admins = org_client.list_delegated_administrators(
134
+ ServicePrincipal='access-analyzer.amazonaws.com'
135
+ ).get('DelegatedAdministrators', [])
136
+
137
+ if not delegated_admins:
138
+ finding = {
139
+ 'CheckId': self.check_id,
140
+ 'Status': 'FAIL',
141
+ 'Region': region,
142
+ "Severity": self.severity,
143
+ 'Title': f"{self.check_id} {self.check_name}",
144
+ 'Description': self.description,
145
+ 'ResourceId': security_ou_id,
146
+ 'ResourceType': 'AWS::Organizations::Account',
147
+ 'AccountId': account_id,
148
+ 'CheckedValue': 'IAA Delegated Administrator',
149
+ 'ActualValue': f'OU: {ou_name}, No delegated administrator configured',
150
+ 'Remediation': f'Configure an account from {ou_name} OU as IAA delegated administrator',
151
+ 'Service': self.service,
152
+ 'CheckLogic': self.check_logic,
153
+ 'CheckType': self.check_type
154
+ }
155
+ self.findings.append(finding)
156
+ return self.findings
157
+
158
+ delegated_admin = delegated_admins[0]
159
+ security_ou_account_ids = [acc['Id'] for acc in security_ou_accounts]
160
+
161
+ if delegated_admin['Id'] not in security_ou_account_ids:
162
+ finding = {
163
+ 'CheckId': self.check_id,
164
+ 'Status': 'FAIL',
165
+ 'Region': region,
166
+ "Severity": self.severity,
167
+ 'Title': f"{self.check_id} {self.check_name}",
168
+ 'Description': self.description,
169
+ 'ResourceId': delegated_admin['Id'],
170
+ 'ResourceType': 'AWS::Organizations::Account',
171
+ 'AccountId': account_id,
172
+ 'CheckedValue': f'IAA Delegated Administrator Configuration in {ou_name} OU',
173
+ 'ActualValue': f'OU: {ou_name}, Account: {delegated_admin["Id"]} (not in OU)',
174
+ 'Remediation': f'Configure an account from {ou_name} OU as IAA delegated administrator',
175
+ 'Service': self.service,
176
+ 'CheckLogic': self.check_logic,
177
+ 'CheckType': self.check_type
178
+ }
179
+ self.findings.append(finding)
180
+ else:
181
+ finding = {
182
+ 'CheckId': self.check_id,
183
+ 'Status': 'PASS',
184
+ 'Region': region,
185
+ "Severity": self.severity,
186
+ 'Title': f"{self.check_id} {self.check_name}",
187
+ 'Description': self.description,
188
+ 'ResourceId': delegated_admin['Id'],
189
+ 'ResourceType': 'AWS::Organizations::Account',
190
+ 'AccountId': account_id,
191
+ 'CheckedValue': f'IAA Delegated Administrator Configuration in {ou_name} OU',
192
+ 'ActualValue': f'OU: {ou_name}, Account: {delegated_admin["Id"]}',
193
+ 'Remediation': 'None required',
194
+ 'Service': self.service,
195
+ 'CheckLogic': self.check_logic,
196
+ 'CheckType': self.check_type
197
+ }
198
+ self.findings.append(finding)
199
+
200
+ except ClientError as e:
201
+ finding = {
202
+ 'CheckId': self.check_id,
203
+ 'Status': 'ERROR',
204
+ 'Region': region,
205
+ "Severity": self.severity,
206
+ 'Title': f"{self.check_id} {self.check_name}",
207
+ 'Description': self.description,
208
+ 'ResourceId': account_id,
209
+ 'ResourceType': 'AWS::Organizations::Account',
210
+ 'AccountId': account_id,
211
+ 'CheckedValue': 'Delegated Administrator Access',
212
+ 'ActualValue': f'Error checking delegated administrator: {str(e)}',
213
+ 'Remediation': 'Verify Organizations permissions',
214
+ 'Service': self.service,
215
+ 'CheckLogic': self.check_logic,
216
+ 'CheckType': self.check_type
217
+ }
218
+ self.findings.append(finding)
219
+
220
+ except ClientError as e:
221
+ finding = {
222
+ 'CheckId': self.check_id,
223
+ 'Status': 'ERROR',
224
+ 'Region': region,
225
+ "Severity": self.severity,
226
+ 'Title': f"{self.check_id} {self.check_name}",
227
+ 'Description': self.description,
228
+ 'ResourceId': account_id,
229
+ 'ResourceType': 'AWS::Organizations::OrganizationalUnit',
230
+ 'AccountId': account_id,
231
+ 'CheckedValue': 'Organizations Structure',
232
+ 'ActualValue': f'Error accessing Organizations structure: {str(e)}',
233
+ 'Remediation': 'Verify Organizations permissions and structure',
234
+ 'Service': self.service,
235
+ 'CheckLogic': self.check_logic,
236
+ 'CheckType': self.check_type
237
+ }
238
+ self.findings.append(finding)
239
+
240
+ except Exception as e:
241
+ finding = {
242
+ 'CheckId': self.check_id,
243
+ 'Status': 'ERROR',
244
+ 'Region': region,
245
+ "Severity": self.severity,
246
+ 'Title': f"{self.check_id} {self.check_name}",
247
+ 'Description': self.description,
248
+ 'ResourceId': account_id,
249
+ 'ResourceType': 'AWS::Organizations::Account',
250
+ 'AccountId': account_id,
251
+ 'CheckedValue': 'Check Execution',
252
+ 'ActualValue': f'Error: {str(e)}',
253
+ 'Remediation': 'Check logs for more details',
254
+ 'Service': self.service,
255
+ 'CheckLogic': self.check_logic,
256
+ 'CheckType': self.check_type
257
+ }
258
+ self.findings.append(finding)
259
+
260
+ return self.findings
@@ -0,0 +1,207 @@
1
+ from typing import Dict, List, Any
2
+ from sraverify.checks import SecurityCheck
3
+ from botocore.exceptions import ClientError
4
+
5
+ class SRAIAA4(SecurityCheck):
6
+ """SRA-IAA-4: IAM Access Analyzer Organization Zone of Trust"""
7
+
8
+ def __init__(self, check_type="organization"):
9
+ super().__init__(check_type=check_type)
10
+ self.check_id = "SRA-IAA-4"
11
+ self.check_name = "IAM Access Analyzer Organization Zone of Trust"
12
+ self.severity = "HIGH"
13
+ self.description = ('This check verifies whether IAA external access analyzer is configured with a zone of trust '
14
+ 'of your AWS organization. IAM Access Analyzer generates a finding for each instance of a '
15
+ 'resource-based policy that grants access to a resource within your zone of trust to a principal '
16
+ 'that is not within your zone of trust. When you configure an organization as the zone of trust '
17
+ 'for an analyzer- IAA generates findings or each instance of a resource-based policy that grants '
18
+ 'access to a resource within your AWS organization to a principal that is not within your AWS '
19
+ 'organization.')
20
+ self.check_logic = ('1. Verify execution from Organization Management account | '
21
+ '2. List IAM Access Analyzers in current region | '
22
+ '3. Check for analyzer with type=ORGANIZATION and status=ACTIVE | '
23
+ '4. Verify IAM Analyzer configuration has Organization scope | '
24
+ '5. Check passes if organization-level analyzer is properly configured')
25
+ self.service = 'IAM'
26
+
27
+ def get_findings(self):
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
+ # Initialize clients
38
+ org_client = session.client('organizations')
39
+ analyzer_client = session.client('accessanalyzer')
40
+
41
+ # Step 1: Verify we're in management account using org_mgmt_checker
42
+ is_management, error_message = self.org_checker.verify_org_management()
43
+ if not is_management:
44
+ finding = {
45
+ 'CheckId': self.check_id,
46
+ 'Status': 'ERROR',
47
+ 'Region': region,
48
+ "Severity": self.severity,
49
+ 'Title': f"{self.check_id} {self.check_name}",
50
+ 'Description': self.description,
51
+ 'ResourceId': account_id,
52
+ 'ResourceType': 'AWS::Organizations::Account',
53
+ 'AccountId': account_id,
54
+ 'CheckedValue': 'Management Account Access',
55
+ 'ActualValue': error_message if error_message else 'Not running from management account',
56
+ 'Remediation': 'Run this check from the Organization Management Account',
57
+ 'Service': self.service,
58
+ 'CheckLogic': self.check_logic,
59
+ 'CheckType': self.check_type
60
+ }
61
+ self.findings.append(finding)
62
+ return self.findings
63
+
64
+ # Steps 2 & 3: Check for organization-level analyzer
65
+ try:
66
+ analyzers = analyzer_client.list_analyzers()['analyzers']
67
+ org_analyzer = None
68
+ account_analyzers = []
69
+
70
+ for analyzer in analyzers:
71
+ if analyzer['type'] == 'ORGANIZATION' and analyzer['status'] == 'ACTIVE':
72
+ org_analyzer = analyzer
73
+ break
74
+ elif analyzer['type'] == 'ACCOUNT':
75
+ account_analyzers.append(analyzer['name'])
76
+
77
+ if not org_analyzer:
78
+ failure_details = []
79
+ if not analyzers:
80
+ failure_details.append("No analyzers found in the region")
81
+ if account_analyzers:
82
+ failure_details.append(f"Found account-level analyzers instead of organization-level: {', '.join(account_analyzers)}")
83
+
84
+ self.findings.append({
85
+ 'CheckId': self.check_id,
86
+ 'Status': 'FAIL',
87
+ 'Region': region,
88
+ "Severity": self.severity,
89
+ 'Title': f"{self.check_id} {self.check_name}",
90
+ 'Description': self.description,
91
+ 'ResourceId': account_id,
92
+ 'ResourceType': 'AWS::AccessAnalyzer::Analyzer',
93
+ 'AccountId': account_id,
94
+ 'CheckedValue': 'Organization-level Access Analyzer',
95
+ 'ActualValue': ' | '.join(failure_details) if failure_details else 'No active organization-level analyzer found',
96
+ 'Remediation': 'Create an active organization-level IAM Access Analyzer in this region',
97
+ 'Service': self.service,
98
+ 'CheckLogic': self.check_logic,
99
+ 'CheckType': self.check_type
100
+ })
101
+ return self.findings
102
+
103
+ # Step 4: Verify analyzer configuration
104
+ try:
105
+ analyzer_details = analyzer_client.get_analyzer(
106
+ analyzerName=org_analyzer['name']
107
+ )['analyzer']
108
+
109
+ # Verify organization scope
110
+ if analyzer_details.get('type') != 'ORGANIZATION':
111
+ self.findings.append({
112
+ 'CheckId': self.check_id,
113
+ 'Status': 'FAIL',
114
+ 'Region': region,
115
+ "Severity": self.severity,
116
+ 'Title': f"{self.check_id} {self.check_name}",
117
+ 'Description': self.description,
118
+ 'ResourceId': org_analyzer['arn'],
119
+ 'ResourceType': 'AWS::AccessAnalyzer::Analyzer',
120
+ 'AccountId': account_id,
121
+ 'CheckedValue': 'Analyzer Organization Scope',
122
+ 'ActualValue': f"Analyzer type is {analyzer_details.get('type')} instead of ORGANIZATION",
123
+ 'Remediation': 'Reconfigure analyzer with organization scope or create new organization-level analyzer',
124
+ 'Service': self.service,
125
+ 'CheckLogic': self.check_logic,
126
+ 'CheckType': self.check_type
127
+ })
128
+ else:
129
+ # Step 5: All checks passed
130
+ self.findings.append({
131
+ 'CheckId': self.check_id,
132
+ 'Status': 'PASS',
133
+ 'Region': region,
134
+ "Severity": self.severity,
135
+ 'Title': f"{self.check_id} {self.check_name}",
136
+ 'Description': self.description,
137
+ 'ResourceId': org_analyzer['arn'],
138
+ 'ResourceType': 'AWS::AccessAnalyzer::Analyzer',
139
+ 'AccountId': account_id,
140
+ 'CheckedValue': 'Organization-level Access Analyzer Configuration',
141
+ 'ActualValue': (f"Active organization analyzer: {org_analyzer['name']} | "
142
+ f"Type: {analyzer_details['type']} | "
143
+ f"Status: {analyzer_details['status']}"),
144
+ 'Remediation': 'None required',
145
+ 'Service': self.service,
146
+ 'CheckLogic': self.check_logic,
147
+ 'CheckType': self.check_type
148
+ })
149
+
150
+ except ClientError as e:
151
+ self.findings.append({
152
+ 'CheckId': self.check_id,
153
+ 'Status': 'ERROR',
154
+ 'Region': region,
155
+ "Severity": self.severity,
156
+ 'Title': f"{self.check_id} {self.check_name}",
157
+ 'Description': self.description,
158
+ 'ResourceId': org_analyzer['arn'],
159
+ 'ResourceType': 'AWS::AccessAnalyzer::Analyzer',
160
+ 'AccountId': account_id,
161
+ 'CheckedValue': 'Analyzer Configuration',
162
+ 'ActualValue': f'Error checking analyzer configuration: {str(e)}',
163
+ 'Remediation': 'Verify IAM Access Analyzer permissions',
164
+ 'Service': self.service,
165
+ 'CheckLogic': self.check_logic,
166
+ 'CheckType': self.check_type
167
+ })
168
+
169
+ except ClientError as e:
170
+ self.findings.append({
171
+ 'CheckId': self.check_id,
172
+ 'Status': 'ERROR',
173
+ 'Region': region,
174
+ "Severity": self.severity,
175
+ 'Title': f"{self.check_id} {self.check_name}",
176
+ 'Description': self.description,
177
+ 'ResourceId': account_id,
178
+ 'ResourceType': 'AWS::AccessAnalyzer::Analyzer',
179
+ 'AccountId': account_id,
180
+ 'CheckedValue': 'Access Analyzer Access',
181
+ 'ActualValue': f'Error accessing Access Analyzer: {str(e)}',
182
+ 'Remediation': 'Verify IAM Access Analyzer permissions and service availability',
183
+ 'Service': self.service,
184
+ 'CheckLogic': self.check_logic,
185
+ 'CheckType': self.check_type
186
+ })
187
+
188
+ except Exception as e:
189
+ self.findings.append({
190
+ 'CheckId': self.check_id,
191
+ 'Status': 'ERROR',
192
+ 'Region': region,
193
+ "Severity": self.severity,
194
+ 'Title': f"{self.check_id} {self.check_name}",
195
+ 'Description': self.description,
196
+ 'ResourceId': account_id,
197
+ 'ResourceType': 'AWS::AccessAnalyzer::Analyzer',
198
+ 'AccountId': account_id,
199
+ 'CheckedValue': 'Check Execution',
200
+ 'ActualValue': f'Error: {str(e)}',
201
+ 'Remediation': 'Review error logs and verify AWS credentials and permissions',
202
+ 'Service': self.service,
203
+ 'CheckLogic': self.check_logic,
204
+ 'CheckType': self.check_type
205
+ })
206
+
207
+ return self.findings
@@ -0,0 +1,3 @@
1
+ """
2
+ Package containing Access Analyzer security checks.
3
+ """