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
sraverify/__init__.py ADDED
@@ -0,0 +1,36 @@
1
+ """
2
+ sraverify - Security Reference Architecture Verification Tool
3
+
4
+ This package provides both a command-line interface and a Python library for verifying
5
+ AWS Security Reference Architecture implementations.
6
+
7
+ Example usage as a library:
8
+
9
+ from sraverify import SRAVerify
10
+
11
+ # Create an instance with optional AWS profile and regions
12
+ sra = SRAVerify(profile='my-profile', regions=['us-east-1', 'us-west-2'])
13
+
14
+ # Get available checks and services
15
+ checks = sra.get_available_checks()
16
+ services = sra.get_available_services()
17
+
18
+ # Run checks with various filters
19
+ findings = sra.run_checks(
20
+ account_type='application', # or 'audit', 'log-archive', 'management', 'all'
21
+ service='GuardDuty', # optional service filter
22
+ check_id='SRA-GD-1', # optional specific check
23
+ audit_accounts=['123456789012'], # optional audit account IDs
24
+ log_archive_accounts=['987654321098'] # optional log archive account IDs
25
+ )
26
+
27
+ # Process findings
28
+ for finding in findings:
29
+ print(f"{finding['CheckId']}: {finding['Status']} - {finding['Title']}")
30
+ """
31
+
32
+ __version__ = "0.1.0"
33
+
34
+ from sraverify.main import SRAVerify
35
+
36
+ __all__ = ['SRAVerify']
@@ -0,0 +1,56 @@
1
+ # sraverify/checks/__init__.py
2
+ """
3
+ Base classes for security checks
4
+ """
5
+ from typing import List, Optional
6
+ import boto3
7
+ from sraverify.lib.org_mgmt_checker import OrgMgmtChecker
8
+
9
+
10
+ class SecurityCheck:
11
+ """Base class for all security checks"""
12
+ def __init__(self, check_type="account"):
13
+ self.check_type = check_type
14
+ self.check_id = None
15
+ self.title = None
16
+ self.description = None
17
+ self.rationale = None
18
+ self.remediation = None
19
+ self.impact = "Unknown"
20
+ self.findings = []
21
+ self._regions = None
22
+ self.org_checker = OrgMgmtChecker()
23
+
24
+ def initialize(self, regions: Optional[List[str]] = None):
25
+ """Initialize check with optional regions"""
26
+ if self.check_type == "account":
27
+ self._regions = regions if regions else self._get_enabled_regions()
28
+ # Organization checks don't use regions, so we don't set them
29
+
30
+ def _get_enabled_regions(self) -> List[str]:
31
+ """Get all enabled regions in the AWS account"""
32
+ try:
33
+ session = boto3.Session()
34
+ ec2_client = session.client('ec2', region_name='us-east-1')
35
+ response = ec2_client.describe_regions(AllRegions=False)
36
+ return [region['RegionName'] for region in response['Regions']]
37
+ except Exception as e:
38
+ raise Exception(f"Failed to get enabled regions: {str(e)}")
39
+
40
+ def validate_regions(self, regions: List[str]) -> bool:
41
+ """Validate if specified regions are valid and enabled"""
42
+ enabled_regions = set(self._get_enabled_regions())
43
+ return all(region in enabled_regions for region in regions)
44
+
45
+ @property
46
+ def regions(self) -> List[str]:
47
+ """Get regions for this check"""
48
+ return self._regions if self._regions else []
49
+
50
+ def run(self, session):
51
+ """Run the security check"""
52
+ raise NotImplementedError("Subclasses must implement run()")
53
+
54
+ def get_findings(self):
55
+ """Return findings from the check"""
56
+ return self.findings
@@ -0,0 +1,188 @@
1
+ # sraverify/checks/accessanalyzer/SRA_IAA_1.py
2
+
3
+ from typing import Dict, List, Any, Optional
4
+ from botocore.exceptions import ClientError
5
+ import boto3
6
+ from sraverify.lib.check_loader import SecurityCheck
7
+
8
+ class SRAIAA1(SecurityCheck):
9
+ """SRA-IAA-1: IAM Access Analyzer External Access"""
10
+
11
+ def __init__(self, check_type="account"):
12
+ """Initialize the check with account type"""
13
+ super().__init__(check_type=check_type)
14
+ self.check_type = check_type
15
+ self.check_id = "SRA-IAA-1"
16
+ self.check_type = "account"
17
+ self.check_name = "IAM Access Analyzer External Access"
18
+ self.severity = 'HIGH'
19
+ self.description = ('This check verifies whether IAA external access analyzer is configured with a zone of trust '
20
+ 'of AWS account. IAM Access Analyzer generates a finding for each instance of a resource-based '
21
+ 'policy that grants access to a resource within your zone of trust to a principal that is not '
22
+ 'within your zone of trust.')
23
+ self.check_logic = ('1. Check for active analyzer within account with account zone of trust | '
24
+ '2. Verify archive rules configuration for findings management | '
25
+ '3. Verify analyzer status and configuration | '
26
+ '4. Check passes if account-level analyzer is active with proper configuration')
27
+ self.service = 'IAM'
28
+ self.findings = []
29
+ self._regions = None
30
+
31
+ def initialize(self, regions: Optional[List[str]] = None):
32
+ """Initialize check with optional regions"""
33
+ self._regions = regions
34
+
35
+ def get_findings(self):
36
+ """Return the findings"""
37
+ return self.findings
38
+
39
+ def _create_finding(self, status: str, region: str, account_id: str,
40
+ resource_id: str, actual_value: str,
41
+ remediation: str) -> Dict[str, Any]:
42
+ """Create a standardized finding"""
43
+ return {
44
+ 'CheckId': self.check_id,
45
+ 'Status': status,
46
+ 'Region': region,
47
+ "Severity": self.severity,
48
+ 'Title': f"{self.check_id} {self.check_name}",
49
+ 'Description': self.description,
50
+ 'ResourceId': resource_id,
51
+ 'ResourceType': 'AWS::AccessAnalyzer::Analyzer',
52
+ 'AccountId': account_id,
53
+ 'CheckedValue': 'Access Analyzer Configuration',
54
+ 'ActualValue': actual_value,
55
+ 'Remediation': remediation,
56
+ 'Service': self.service,
57
+ 'CheckLogic': self.check_logic,
58
+ 'CheckType': self.check_type
59
+ }
60
+
61
+ def _check_region(self, session: boto3.Session, region: str) -> Optional[Dict[str, Any]]:
62
+ """Check Access Analyzer configuration in a specific region"""
63
+ try:
64
+ account_id = session.client('sts').get_caller_identity()['Account']
65
+ analyzer_client = session.client('accessanalyzer', region_name=region)
66
+
67
+ # Step 1: Check for account-level analyzer
68
+ try:
69
+ analyzers = analyzer_client.list_analyzers()['analyzers']
70
+ account_analyzer = None
71
+
72
+ for analyzer in analyzers:
73
+ if (analyzer['status'] == 'ACTIVE' and
74
+ analyzer['type'] == 'ACCOUNT'):
75
+ account_analyzer = analyzer
76
+ break
77
+
78
+ if not account_analyzer:
79
+ return self._create_finding(
80
+ status='FAIL',
81
+ region=region,
82
+ account_id=account_id,
83
+ resource_id=account_id,
84
+ actual_value='No active account-level analyzer found',
85
+ remediation='Create an account-level IAM Access Analyzer'
86
+ )
87
+
88
+ # Step 2: Check archive rules configuration
89
+ try:
90
+ archive_rules = analyzer_client.list_archive_rules(
91
+ analyzerName=account_analyzer['name']
92
+ )['archiveRules']
93
+
94
+ # Step 3: Verify analyzer configuration
95
+ try:
96
+ analyzer_details = analyzer_client.get_analyzer(
97
+ analyzerName=account_analyzer['name']
98
+ )
99
+
100
+ # Step 4: All checks passed
101
+ return self._create_finding(
102
+ status='PASS',
103
+ region=region,
104
+ account_id=account_id,
105
+ resource_id=account_analyzer['arn'],
106
+ actual_value=(f"Active account analyzer: {account_analyzer['name']}, "
107
+ f"Archive Rules: {len(archive_rules)}"),
108
+ remediation='None required'
109
+ )
110
+
111
+ except ClientError as e:
112
+ return self._create_finding(
113
+ status='ERROR',
114
+ region=region,
115
+ account_id=account_id,
116
+ resource_id=account_analyzer['arn'],
117
+ actual_value=f'Error checking analyzer configuration: {str(e)}',
118
+ remediation='Verify IAM Access Analyzer permissions'
119
+ )
120
+
121
+ except ClientError as e:
122
+ return self._create_finding(
123
+ status='ERROR',
124
+ region=region,
125
+ account_id=account_id,
126
+ resource_id=account_analyzer['arn'],
127
+ actual_value=f'Error checking archive rules: {str(e)}',
128
+ remediation='Verify IAM Access Analyzer permissions'
129
+ )
130
+
131
+ except ClientError as e:
132
+ return self._create_finding(
133
+ status='ERROR',
134
+ region=region,
135
+ account_id=account_id,
136
+ resource_id=account_id,
137
+ actual_value=f'Error accessing Access Analyzer: {str(e)}',
138
+ remediation='Verify IAM Access Analyzer permissions'
139
+ )
140
+
141
+ except Exception as e:
142
+ return self._create_finding(
143
+ status='ERROR',
144
+ region=region,
145
+ account_id='Unknown',
146
+ resource_id='Unknown',
147
+ actual_value=f'Error: {str(e)}',
148
+ remediation='Check logs for more details'
149
+ )
150
+
151
+ def run(self, session: boto3.Session):
152
+ """Run the security check"""
153
+ try:
154
+ # Get regions to check
155
+ regions_to_check = self._regions if self._regions else [session.region_name]
156
+
157
+ # Check each region
158
+ for region in regions_to_check:
159
+ try:
160
+ finding = self._check_region(session, region)
161
+ if finding:
162
+ self.findings.append(finding)
163
+ except Exception as e:
164
+ self.findings.append(
165
+ self._create_finding(
166
+ status='ERROR',
167
+ region=region,
168
+ account_id='Unknown',
169
+ resource_id='Unknown',
170
+ actual_value=f'Region check failed: {str(e)}',
171
+ remediation='Check regional access and permissions'
172
+ )
173
+ )
174
+
175
+ except Exception as e:
176
+ # Handle any unexpected errors during check execution
177
+ self.findings.append(
178
+ self._create_finding(
179
+ status='ERROR',
180
+ region='Unknown',
181
+ account_id='Unknown',
182
+ resource_id='Unknown',
183
+ actual_value=f'Check execution failed: {str(e)}',
184
+ remediation='Check logs for more details'
185
+ )
186
+ )
187
+
188
+ return self.findings
@@ -0,0 +1,162 @@
1
+ from typing import Dict, List, Any
2
+ from sraverify.checks import SecurityCheck
3
+ from botocore.exceptions import ClientError
4
+
5
+ class SRAIAA2(SecurityCheck):
6
+ """SRA-IAA-2: IAM Access Analyzer Delegated Administration"""
7
+
8
+ def __init__(self, check_type="organization"):
9
+ # Ensure parent class is initialized first
10
+ super().__init__(check_type=check_type)
11
+ self.check_id = "SRA-IAA-2"
12
+ self.check_name = "IAM Access Analyzer Delegated Administration"
13
+ self.severity = "HIGH"
14
+ self.description = ('This check verifies whether IAA service administration for your AWS Organization is '
15
+ 'delegated out of your AWS Organization management account. The delegated administrator '
16
+ 'has permissions to create and manage analyzers with the AWS organization as the zone of trust.')
17
+ self.check_logic = ('1. Verify execution from Organization Management account | '
18
+ '2. Check for delegated administrator for IAA service | '
19
+ '3. Confirm that delegated administrator is not management account | '
20
+ '4. Check passes if IAA delegated administrator is not in management account')
21
+ self.service = 'IAM'
22
+
23
+ def run(self, session):
24
+ """Run the security check"""
25
+ try:
26
+ region = session.region_name
27
+ account_id = session.client('sts').get_caller_identity()['Account']
28
+
29
+ # Step 1: Verify we're in management account using org_mgmt_checker
30
+ is_management, error_message = self.org_checker.verify_org_management()
31
+ if not is_management:
32
+ finding = {
33
+ 'CheckId': self.check_id,
34
+ 'Status': 'ERROR',
35
+ 'Region': region,
36
+ "Severity": self.severity,
37
+ 'Title': f"{self.check_id} {self.check_name}",
38
+ 'Description': self.description,
39
+ 'ResourceId': account_id,
40
+ 'ResourceType': 'AWS::Organizations::Account',
41
+ 'AccountId': account_id,
42
+ 'CheckedValue': 'Management Account Access',
43
+ 'ActualValue': error_message if error_message else 'Not running from management account',
44
+ 'Remediation': 'Run this check from the Organization Management Account',
45
+ 'Service': self.service,
46
+ 'CheckLogic': self.check_logic,
47
+ 'CheckType': self.check_type
48
+ }
49
+ self.findings.append(finding)
50
+ return self.findings
51
+
52
+ # Step 2: Check for delegated administrator
53
+ try:
54
+ org_client = session.client('organizations')
55
+ delegated_admins = org_client.list_delegated_administrators(
56
+ ServicePrincipal='access-analyzer.amazonaws.com'
57
+ ).get('DelegatedAdministrators', [])
58
+
59
+ if not delegated_admins:
60
+ finding = {
61
+ 'CheckId': self.check_id,
62
+ 'Status': 'FAIL',
63
+ 'Region': region,
64
+ "Severity": self.severity,
65
+ 'Title': f"{self.check_id} {self.check_name}",
66
+ 'Description': self.description,
67
+ 'ResourceId': account_id,
68
+ 'ResourceType': 'AWS::Organizations::Account',
69
+ 'AccountId': account_id,
70
+ 'CheckedValue': 'IAA Delegated Administrator',
71
+ 'ActualValue': 'No delegated administrator configured',
72
+ 'Remediation': 'Configure a member account as IAA delegated administrator',
73
+ 'Service': self.service,
74
+ 'CheckLogic': self.check_logic,
75
+ 'CheckType': self.check_type
76
+ }
77
+ self.findings.append(finding)
78
+ return self.findings
79
+
80
+ # Step 3: Confirm delegated administrator is not management account
81
+ delegated_admin = delegated_admins[0]
82
+ if delegated_admin['Id'] == account_id:
83
+ finding = {
84
+ 'CheckId': self.check_id,
85
+ 'Status': 'FAIL',
86
+ 'Region': region,
87
+ "Severity": self.severity,
88
+ 'Title': f"{self.check_id} {self.check_name}",
89
+ 'Description': self.description,
90
+ 'ResourceId': account_id,
91
+ 'ResourceType': 'AWS::Organizations::Account',
92
+ 'AccountId': account_id,
93
+ 'CheckedValue': 'IAA Delegated Administrator Configuration',
94
+ 'ActualValue': f'Delegated administrator is management account: {account_id}',
95
+ 'Remediation': 'Configure a member account (not management account) as IAA delegated administrator',
96
+ 'Service': self.service,
97
+ 'CheckLogic': self.check_logic,
98
+ 'CheckType': self.check_type
99
+ }
100
+ self.findings.append(finding)
101
+ else:
102
+ # Step 4: Check passes if delegated administrator is not management account
103
+ finding = {
104
+ 'CheckId': self.check_id,
105
+ 'Status': 'PASS',
106
+ 'Region': region,
107
+ "Severity": self.severity,
108
+ 'Title': f"{self.check_id} {self.check_name}",
109
+ 'Description': self.description,
110
+ 'ResourceId': delegated_admin['Id'],
111
+ 'ResourceType': 'AWS::Organizations::Account',
112
+ 'AccountId': account_id,
113
+ 'CheckedValue': 'IAA Delegated Administrator Configuration',
114
+ 'ActualValue': f'Delegated administrator account: {delegated_admin["Id"]}',
115
+ 'Remediation': 'None required',
116
+ 'Service': self.service,
117
+ 'CheckLogic': self.check_logic,
118
+ 'CheckType': self.check_type
119
+ }
120
+ self.findings.append(finding)
121
+
122
+ except ClientError as e:
123
+ finding = {
124
+ 'CheckId': self.check_id,
125
+ 'Status': 'ERROR',
126
+ 'Region': region,
127
+ "Severity": self.severity,
128
+ 'Title': f"{self.check_id} {self.check_name}",
129
+ 'Description': self.description,
130
+ 'ResourceId': account_id,
131
+ 'ResourceType': 'AWS::Organizations::Account',
132
+ 'AccountId': account_id,
133
+ 'CheckedValue': 'Delegated Administrator Access',
134
+ 'ActualValue': f'Error checking delegated administrator: {str(e)}',
135
+ 'Remediation': 'Verify Organizations permissions',
136
+ 'Service': self.service,
137
+ 'CheckLogic': self.check_logic,
138
+ 'CheckType': self.check_type
139
+ }
140
+ self.findings.append(finding)
141
+
142
+ except Exception as e:
143
+ finding = {
144
+ 'CheckId': self.check_id,
145
+ 'Status': 'ERROR',
146
+ 'Region': region,
147
+ "Severity": self.severity,
148
+ 'Title': f"{self.check_id} {self.check_name}",
149
+ 'Description': self.description,
150
+ 'ResourceId': account_id,
151
+ 'ResourceType': 'AWS::Organizations::Account',
152
+ 'AccountId': account_id,
153
+ 'CheckedValue': 'Check Execution',
154
+ 'ActualValue': f'Error: {str(e)}',
155
+ 'Remediation': 'Check logs for more details',
156
+ 'Service': self.service,
157
+ 'CheckLogic': self.check_logic,
158
+ 'CheckType': self.check_type
159
+ }
160
+ self.findings.append(finding)
161
+
162
+ return self.findings