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,95 @@
1
+ from typing import Dict, Any
2
+ from sraverify.core.check import SecurityCheck
3
+ from sraverify.services.securityincidentresponse.client import SecurityIncidentResponseClient
4
+ from sraverify.core.logging import logger
5
+
6
+ class SecurityIncidentResponseCheck(SecurityCheck):
7
+ def __init__(self):
8
+ super().__init__(
9
+ account_type="management",
10
+ service="SecurityIncidentResponse",
11
+ resource_type="AWS::Organizations::DelegatedAdministrator"
12
+ )
13
+
14
+ def _setup_clients(self):
15
+ self._clients.clear()
16
+ # Use first region specified, or us-east-1 as fallback
17
+ region = self.regions[0] if self.regions else "us-east-1"
18
+ self._clients[region] = SecurityIncidentResponseClient(region, session=self.session)
19
+
20
+ def get_delegated_administrators(self) -> Dict[str, Any]:
21
+ """Get delegated administrators for Security Incident Response."""
22
+ region = self.regions[0] if self.regions else "us-east-1"
23
+ client = self.get_client(region)
24
+ if not client:
25
+ return {}
26
+ return client.list_delegated_administrators()
27
+
28
+ def list_memberships(self) -> Dict[str, Any]:
29
+ """List Security Incident Response memberships."""
30
+ region = self.regions[0] if self.regions else "us-east-1"
31
+ client = self.get_client(region)
32
+ if not client:
33
+ return {}
34
+ return client.list_memberships()
35
+
36
+ def get_membership(self, membership_id: str) -> Dict[str, Any]:
37
+ """Get Security Incident Response membership details."""
38
+ sir_region = self.discover_sir_region()
39
+ client = self.get_client(sir_region)
40
+ if not client:
41
+ self._clients[sir_region] = SecurityIncidentResponseClient(sir_region, session=self.session)
42
+ client = self.get_client(sir_region)
43
+ return client.get_membership(membership_id)
44
+
45
+ def batch_get_member_account_details(self, membership_id: str, account_ids: list) -> Dict[str, Any]:
46
+ """Get member account details for multiple accounts."""
47
+ sir_region = self.discover_sir_region()
48
+ client = self.get_client(sir_region)
49
+ if not client:
50
+ self._clients[sir_region] = SecurityIncidentResponseClient(sir_region, session=self.session)
51
+ client = self.get_client(sir_region)
52
+ return client.batch_get_member_account_details(membership_id, account_ids)
53
+
54
+ def get_organization_accounts(self) -> list:
55
+ """Get all accounts in the organization."""
56
+ region = self.regions[0] if self.regions else "us-east-1"
57
+ client = self.get_client(region)
58
+ if not client:
59
+ return []
60
+
61
+ response = client.list_accounts()
62
+ if "Error" in response:
63
+ return []
64
+
65
+ return response.get("Accounts", [])
66
+
67
+ def get_role(self, role_name: str) -> Dict[str, Any]:
68
+ """Get IAM role details."""
69
+ region = self.regions[0] if self.regions else "us-east-1"
70
+ client = self.get_client(region)
71
+ if not client:
72
+ return {}
73
+ return client.get_role(role_name)
74
+
75
+ def discover_sir_region(self) -> str:
76
+ """Discover the region where Security Incident Response is configured."""
77
+ # Try each region until we find one with memberships
78
+ regions_to_try = self.regions
79
+
80
+ for region in regions_to_try:
81
+ try:
82
+ # Create a temporary client for this region
83
+ temp_client = SecurityIncidentResponseClient(region, session=self.session)
84
+ response = temp_client.list_memberships()
85
+
86
+ if "Error" not in response:
87
+ memberships = response.get("items", [])
88
+ if memberships:
89
+ # Return the region from the first membership
90
+ return memberships[0].get("region", region)
91
+ except Exception:
92
+ continue
93
+
94
+ # Fallback to first region or us-east-1
95
+ return self.regions[0] if self.regions else "us-east-1"
@@ -0,0 +1 @@
1
+ # Security Incident Response checks
@@ -0,0 +1,77 @@
1
+ from typing import Dict, List, Any
2
+ from sraverify.services.securityincidentresponse.base import SecurityIncidentResponseCheck
3
+
4
+ class SRA_SECURITYINCIDENTRESPONSE_01(SecurityIncidentResponseCheck):
5
+ def __init__(self):
6
+ super().__init__()
7
+ self.check_id = "SRA-SECURITYINCIDENTRESPONSE-01"
8
+ self.check_name = "Security Incident Response delegated admin is audit account"
9
+ self.description = "Verifies that the Security Incident Response delegated administrator is configured and is the audit account"
10
+ self.severity = "HIGH"
11
+ self.check_logic = "Lists delegated administrators for security-ir.amazonaws.com and verifies the audit account is designated"
12
+
13
+ def execute(self) -> List[Dict[str, Any]]:
14
+ region = self.regions[0] if self.regions else "us-east-1"
15
+
16
+ # Check if audit accounts are provided
17
+ audit_accounts = getattr(self, '_audit_accounts', None)
18
+ if not audit_accounts:
19
+ self.findings.append(self.create_finding(
20
+ status="ERROR",
21
+ region=region,
22
+ resource_id=None,
23
+ actual_value="No audit accounts specified",
24
+ remediation="Run with --audit-account parameter to specify audit account IDs"
25
+ ))
26
+ return self.findings
27
+
28
+ response = self.get_delegated_administrators()
29
+
30
+ if "Error" in response:
31
+ self.findings.append(self.create_finding(
32
+ status="ERROR",
33
+ region=region,
34
+ resource_id=None,
35
+ actual_value=response["Error"].get("Message", "Unknown error"),
36
+ remediation="Check IAM permissions for Organizations API access"
37
+ ))
38
+ return self.findings
39
+
40
+ delegated_admins = response.get("DelegatedAdministrators", [])
41
+
42
+ if not delegated_admins:
43
+ self.findings.append(self.create_finding(
44
+ status="FAIL",
45
+ region=region,
46
+ resource_id=None,
47
+ actual_value="No delegated administrator configured for Security Incident Response",
48
+ remediation="Configure a delegated administrator for Security Incident Response using: aws organizations register-delegated-administrator --account-id <audit-account-id> --service-principal security-ir.amazonaws.com"
49
+ ))
50
+ else:
51
+ # Check if any of the delegated admins is the audit account
52
+ audit_admin_found = False
53
+
54
+ for admin in delegated_admins:
55
+ admin_id = admin.get("Id")
56
+ if admin_id in audit_accounts:
57
+ audit_admin_found = True
58
+ self.findings.append(self.create_finding(
59
+ status="PASS",
60
+ region=region,
61
+ resource_id=admin_id,
62
+ actual_value=f"Audit account {admin_id} is configured as delegated administrator",
63
+ remediation="No remediation needed"
64
+ ))
65
+ break
66
+
67
+ if not audit_admin_found:
68
+ admin_ids = [admin.get("Id") for admin in delegated_admins]
69
+ self.findings.append(self.create_finding(
70
+ status="FAIL",
71
+ region=region,
72
+ resource_id=None,
73
+ actual_value=f"Delegated administrators found: {admin_ids}, but none are audit accounts: {audit_accounts}",
74
+ remediation="Register the audit account as delegated administrator: aws organizations register-delegated-administrator --account-id <audit-account-id> --service-principal security-ir.amazonaws.com"
75
+ ))
76
+
77
+ return self.findings
@@ -0,0 +1,72 @@
1
+ from typing import Dict, List, Any
2
+ from sraverify.services.securityincidentresponse.base import SecurityIncidentResponseCheck
3
+
4
+ class SRA_SECURITYINCIDENTRESPONSE_02(SecurityIncidentResponseCheck):
5
+ def __init__(self):
6
+ super().__init__()
7
+ self.account_type = "audit"
8
+ self.check_id = "SRA-SECURITYINCIDENTRESPONSE-02"
9
+ self.check_name = "Security Incident Response membership active"
10
+ self.description = "Verifies that Security Incident Response membership is active"
11
+ self.severity = "HIGH"
12
+ self.check_logic = "Lists memberships and verifies status is Active"
13
+
14
+ def execute(self) -> List[Dict[str, Any]]:
15
+ region = self.regions[0] if self.regions else "us-east-1"
16
+
17
+ response = self.list_memberships()
18
+
19
+ if "Error" in response:
20
+ self.findings.append(self.create_finding(
21
+ status="ERROR",
22
+ region=region,
23
+ resource_id=None,
24
+ actual_value=response["Error"].get("Message", "Unknown error"),
25
+ remediation="Check IAM permissions for Security Incident Response API access"
26
+ ))
27
+ return self.findings
28
+
29
+ memberships = response.get("items", [])
30
+
31
+ if not memberships:
32
+ self.findings.append(self.create_finding(
33
+ status="FAIL",
34
+ region=region,
35
+ resource_id=None,
36
+ actual_value="No Security Incident Response memberships found",
37
+ remediation="Create a Security Incident Response membership through the AWS console or API"
38
+ ))
39
+ else:
40
+ active_found = False
41
+ for membership in memberships:
42
+ membership_id = membership.get("membershipId")
43
+ status = membership.get("membershipStatus")
44
+
45
+ if status == "Active":
46
+ active_found = True
47
+ self.findings.append(self.create_finding(
48
+ status="PASS",
49
+ region=region,
50
+ resource_id=membership_id,
51
+ actual_value=f"Membership {membership_id} is Active",
52
+ remediation="No remediation needed"
53
+ ))
54
+ else:
55
+ self.findings.append(self.create_finding(
56
+ status="FAIL",
57
+ region=region,
58
+ resource_id=membership_id,
59
+ actual_value=f"Membership {membership_id} status is {status}",
60
+ remediation="Activate the Security Incident Response membership through the AWS console"
61
+ ))
62
+
63
+ if not active_found:
64
+ self.findings.append(self.create_finding(
65
+ status="FAIL",
66
+ region=region,
67
+ resource_id=None,
68
+ actual_value="No active Security Incident Response memberships found",
69
+ remediation="Activate an existing membership or create a new active membership"
70
+ ))
71
+
72
+ return self.findings
@@ -0,0 +1,86 @@
1
+ from typing import Dict, List, Any
2
+ from sraverify.services.securityincidentresponse.base import SecurityIncidentResponseCheck
3
+
4
+ class SRA_SECURITYINCIDENTRESPONSE_03(SecurityIncidentResponseCheck):
5
+ def __init__(self):
6
+ super().__init__()
7
+ self.account_type = "audit"
8
+ self.check_id = "SRA-SECURITYINCIDENTRESPONSE-03"
9
+ self.check_name = "Security Incident Response proactive response enabled"
10
+ self.description = "Verifies that Security Incident Response proactive response (Triage) feature is enabled"
11
+ self.severity = "MEDIUM"
12
+ self.check_logic = "Lists memberships and checks if Triage opt-in feature is enabled"
13
+
14
+ def execute(self) -> List[Dict[str, Any]]:
15
+ # Discover the region where Security Incident Response is configured
16
+ region = self.discover_sir_region()
17
+
18
+ # First get list of memberships
19
+ memberships_response = self.list_memberships()
20
+
21
+ if "Error" in memberships_response:
22
+ self.findings.append(self.create_finding(
23
+ status="ERROR",
24
+ region=region,
25
+ resource_id=None,
26
+ actual_value=memberships_response["Error"].get("Message", "Unknown error"),
27
+ remediation="Check IAM permissions for Security Incident Response API access"
28
+ ))
29
+ return self.findings
30
+
31
+ memberships = memberships_response.get("items", [])
32
+
33
+ if not memberships:
34
+ self.findings.append(self.create_finding(
35
+ status="FAIL",
36
+ region=region,
37
+ resource_id=None,
38
+ actual_value="No Security Incident Response memberships found",
39
+ remediation="Create a Security Incident Response membership first"
40
+ ))
41
+ return self.findings
42
+
43
+ # Check each membership for proactive response
44
+ for membership in memberships:
45
+ membership_id = membership.get("membershipId")
46
+
47
+ # Get detailed membership info
48
+ membership_details = self.get_membership(membership_id)
49
+
50
+ if "Error" in membership_details:
51
+ self.findings.append(self.create_finding(
52
+ status="ERROR",
53
+ region=region,
54
+ resource_id=membership_id,
55
+ actual_value=membership_details["Error"].get("Message", "Unknown error"),
56
+ remediation="Check IAM permissions for Security Incident Response GetMembership API access"
57
+ ))
58
+ continue
59
+
60
+ # Check opt-in features for Triage
61
+ opt_in_features = membership_details.get("optInFeatures", [])
62
+ triage_enabled = False
63
+
64
+ for feature in opt_in_features:
65
+ if feature.get("featureName") == "Triage" and feature.get("isEnabled"):
66
+ triage_enabled = True
67
+ break
68
+
69
+ if triage_enabled:
70
+ self.findings.append(self.create_finding(
71
+ status="PASS",
72
+ region=region,
73
+ resource_id=membership_id,
74
+ actual_value="Proactive response (Triage) is enabled",
75
+ remediation="No remediation needed"
76
+ ))
77
+ else:
78
+ self.findings.append(self.create_finding(
79
+ status="FAIL",
80
+ region=region,
81
+ resource_id=membership_id,
82
+ actual_value="Proactive response (Triage) is not enabled",
83
+ remediation="Enable proactive response in the Security Incident Response console under membership settings"
84
+ ))
85
+
86
+ return self.findings
@@ -0,0 +1,117 @@
1
+ from typing import Dict, List, Any
2
+ from sraverify.services.securityincidentresponse.base import SecurityIncidentResponseCheck
3
+
4
+ class SRA_SECURITYINCIDENTRESPONSE_04(SecurityIncidentResponseCheck):
5
+ def __init__(self):
6
+ super().__init__()
7
+ self.account_type = "audit"
8
+ self.check_id = "SRA-SECURITYINCIDENTRESPONSE-04"
9
+ self.check_name = "Security Incident Response enabled for all organization accounts"
10
+ self.description = "Verifies that all active organization accounts are covered by Security Incident Response"
11
+ self.severity = "HIGH"
12
+ self.check_logic = "Gets all organization accounts and checks if each is associated with Security Incident Response membership"
13
+
14
+ def execute(self) -> List[Dict[str, Any]]:
15
+ # Discover the region where Security Incident Response is configured
16
+ region = self.discover_sir_region()
17
+
18
+ # Get all organization accounts
19
+ org_accounts = self.get_organization_accounts()
20
+ if not org_accounts:
21
+ self.findings.append(self.create_finding(
22
+ status="ERROR",
23
+ region=region,
24
+ resource_id=None,
25
+ actual_value="Unable to retrieve organization accounts",
26
+ remediation="Check IAM permissions for Organizations API access"
27
+ ))
28
+ return self.findings
29
+
30
+ # Get active memberships
31
+ memberships_response = self.list_memberships()
32
+ if "Error" in memberships_response:
33
+ self.findings.append(self.create_finding(
34
+ status="ERROR",
35
+ region=region,
36
+ resource_id=None,
37
+ actual_value=memberships_response["Error"].get("Message", "Unknown error"),
38
+ remediation="Check IAM permissions for Security Incident Response API access"
39
+ ))
40
+ return self.findings
41
+
42
+ memberships = memberships_response.get("items", [])
43
+ active_memberships = [m for m in memberships if m.get("membershipStatus") == "Active"]
44
+
45
+ if not active_memberships:
46
+ self.findings.append(self.create_finding(
47
+ status="ERROR",
48
+ region=region,
49
+ resource_id=None,
50
+ actual_value="No active Security Incident Response memberships found",
51
+ remediation="Create and activate a Security Incident Response membership first"
52
+ ))
53
+ return self.findings
54
+
55
+ # Use first active membership
56
+ membership_id = active_memberships[0].get("membershipId")
57
+
58
+ # Get active organization accounts
59
+ active_accounts = [acc for acc in org_accounts if acc.get("Status") == "ACTIVE"]
60
+ account_ids = [acc.get("Id") for acc in active_accounts]
61
+
62
+ # Process accounts in batches of 100 (API limit)
63
+ batch_size = 100
64
+ for i in range(0, len(account_ids), batch_size):
65
+ batch_account_ids = account_ids[i:i + batch_size]
66
+
67
+ response = self.batch_get_member_account_details(membership_id, batch_account_ids)
68
+
69
+ if "Error" in response:
70
+ for account_id in batch_account_ids:
71
+ self.findings.append(self.create_finding(
72
+ status="ERROR",
73
+ region=region,
74
+ resource_id=account_id,
75
+ actual_value=response["Error"].get("Message", "Unknown error"),
76
+ remediation="Check IAM permissions for Security Incident Response BatchGetMemberAccountDetails API access or ensure you specified the region where Security Incident Response is enabled with the --regions flag"
77
+ ))
78
+ continue
79
+
80
+ # Process results
81
+ items = response.get("items", [])
82
+ errors = response.get("errors", [])
83
+
84
+ # Handle errors
85
+ for error in errors:
86
+ account_id = error.get("accountId")
87
+ self.findings.append(self.create_finding(
88
+ status="ERROR",
89
+ region=region,
90
+ resource_id=account_id,
91
+ actual_value=error.get("message", "Unknown error"),
92
+ remediation="Check account status and Security Incident Response configuration"
93
+ ))
94
+
95
+ # Check each account's association status
96
+ for item in items:
97
+ account_id = item.get("accountId")
98
+ relationship_status = item.get("relationshipStatus")
99
+
100
+ if relationship_status == "Associated":
101
+ self.findings.append(self.create_finding(
102
+ status="PASS",
103
+ region=region,
104
+ resource_id=account_id,
105
+ actual_value=f"Account {account_id} is associated with Security Incident Response",
106
+ remediation="No remediation needed"
107
+ ))
108
+ else:
109
+ self.findings.append(self.create_finding(
110
+ status="FAIL",
111
+ region=region,
112
+ resource_id=account_id,
113
+ actual_value=f"Account {account_id} relationship status is {relationship_status}",
114
+ remediation="Associate the account with Security Incident Response membership through organizational units or direct association"
115
+ ))
116
+
117
+ return self.findings
@@ -0,0 +1,55 @@
1
+ from typing import Dict, List, Any
2
+ from sraverify.services.securityincidentresponse.base import SecurityIncidentResponseCheck
3
+
4
+ class SRA_SECURITYINCIDENTRESPONSE_05(SecurityIncidentResponseCheck):
5
+ def __init__(self):
6
+ super().__init__()
7
+ self.account_type = "application"
8
+ self.check_id = "SRA-SECURITYINCIDENTRESPONSE-05"
9
+ self.check_name = "Security Incident Response triage service linked role exists"
10
+ self.description = "Verifies that the AWSServiceRoleForSecurityIncidentResponse_Triage service linked role exists"
11
+ self.severity = "MEDIUM"
12
+ self.check_logic = "Checks if the AWSServiceRoleForSecurityIncidentResponse_Triage IAM role exists in the account"
13
+
14
+ def execute(self) -> List[Dict[str, Any]]:
15
+ region = "global" # IAM is global
16
+ role_name = "AWSServiceRoleForSecurityIncidentResponse_Triage"
17
+ management_account_id = self.get_management_accountId(self.session)
18
+ is_management_account = self.account_id == management_account_id
19
+
20
+ response = self.get_role(role_name)
21
+
22
+ if "Error" in response:
23
+ error_code = response["Error"].get("Code")
24
+ if error_code == "NoSuchEntity":
25
+ if is_management_account:
26
+ remediation = "Security Incident Response cannot automatically create the triage service linked role in the management account. Create it manually using: aws iam create-service-linked-role --aws-service-name triage.security-ir.amazonaws.com"
27
+ else:
28
+ remediation = "The triage service linked role is created when onboarding to Security Incident Response. If deleted, recreate by onboarding to the service again or manually using: aws iam create-service-linked-role --aws-service-name triage.security-ir.amazonaws.com"
29
+
30
+ self.findings.append(self.create_finding(
31
+ status="FAIL",
32
+ region=region,
33
+ resource_id=f"arn:aws:iam::{self.account_id}:role/{role_name}",
34
+ actual_value=f"Service linked role {role_name} does not exist",
35
+ remediation=remediation
36
+ ))
37
+ else:
38
+ self.findings.append(self.create_finding(
39
+ status="ERROR",
40
+ region=region,
41
+ resource_id=f"arn:aws:iam::{self.account_id}:role/{role_name}",
42
+ actual_value=response["Error"].get("Message", "Unknown error"),
43
+ remediation="Check IAM permissions for GetRole API access"
44
+ ))
45
+ else:
46
+ role_arn = response.get("Role", {}).get("Arn")
47
+ self.findings.append(self.create_finding(
48
+ status="PASS",
49
+ region=region,
50
+ resource_id=role_arn,
51
+ actual_value=f"Service linked role {role_name} exists",
52
+ remediation="No remediation needed"
53
+ ))
54
+
55
+ return self.findings
@@ -0,0 +1,71 @@
1
+ from typing import Dict, Optional, Any, List
2
+ import boto3
3
+ from botocore.exceptions import ClientError
4
+ from sraverify.core.logging import logger
5
+
6
+ class SecurityIncidentResponseClient:
7
+ def __init__(self, region: str, session: Optional[boto3.Session] = None):
8
+ self.region = region
9
+ self.session = session or boto3.Session()
10
+ self.org_client = self.session.client('organizations', region_name=region)
11
+ self.sir_client = self.session.client('security-ir', region_name=region)
12
+ self.iam_client = self.session.client('iam', region_name=region)
13
+
14
+ def list_delegated_administrators(self, service_principal: str = "security-ir.amazonaws.com") -> Dict[str, Any]:
15
+ """List delegated administrators for Security Incident Response service."""
16
+ try:
17
+ response = self.org_client.list_delegated_administrators(
18
+ ServicePrincipal=service_principal
19
+ )
20
+ return response
21
+ except ClientError as e:
22
+ logger.error(f"Error listing delegated administrators in {self.region}: {e}")
23
+ return {"Error": {"Code": e.response['Error']['Code'], "Message": e.response['Error']['Message']}}
24
+
25
+ def list_memberships(self) -> Dict[str, Any]:
26
+ """List Security Incident Response memberships."""
27
+ try:
28
+ response = self.sir_client.list_memberships()
29
+ return response
30
+ except ClientError as e:
31
+ logger.error(f"Error listing memberships in {self.region}: {e}")
32
+ return {"Error": {"Code": e.response['Error']['Code'], "Message": e.response['Error']['Message']}}
33
+
34
+ def get_membership(self, membership_id: str) -> Dict[str, Any]:
35
+ """Get Security Incident Response membership details."""
36
+ try:
37
+ response = self.sir_client.get_membership(membershipId=membership_id)
38
+ return response
39
+ except ClientError as e:
40
+ logger.error(f"Error getting membership {membership_id} in {self.region}: {e}")
41
+ return {"Error": {"Code": e.response['Error']['Code'], "Message": e.response['Error']['Message']}}
42
+
43
+ def batch_get_member_account_details(self, membership_id: str, account_ids: List[str]) -> Dict[str, Any]:
44
+ """Get member account details for multiple accounts."""
45
+ try:
46
+ response = self.sir_client.batch_get_member_account_details(
47
+ membershipId=membership_id,
48
+ accountIds=account_ids
49
+ )
50
+ return response
51
+ except ClientError as e:
52
+ logger.error(f"Error getting member account details for membership {membership_id} in {self.region}: {e}")
53
+ return {"Error": {"Code": e.response['Error']['Code'], "Message": e.response['Error']['Message']}}
54
+
55
+ def list_accounts(self) -> Dict[str, Any]:
56
+ """List all accounts in the organization."""
57
+ try:
58
+ response = self.org_client.list_accounts()
59
+ return response
60
+ except ClientError as e:
61
+ logger.error(f"Error listing organization accounts in {self.region}: {e}")
62
+ return {"Error": {"Code": e.response['Error']['Code'], "Message": e.response['Error']['Message']}}
63
+
64
+ def get_role(self, role_name: str) -> Dict[str, Any]:
65
+ """Get IAM role details."""
66
+ try:
67
+ response = self.iam_client.get_role(RoleName=role_name)
68
+ return response
69
+ except ClientError as e:
70
+ logger.error(f"Error getting role {role_name}: {e}")
71
+ return {"Error": {"Code": e.response['Error']['Code'], "Message": e.response['Error']['Message']}}
@@ -0,0 +1,39 @@
1
+ """Security Lake checks."""
2
+
3
+ from sraverify.services.securitylake.checks.sra_securitylake_01 import SRA_SECURITYLAKE_01
4
+ from sraverify.services.securitylake.checks.sra_securitylake_02 import SRA_SECURITYLAKE_02
5
+ from sraverify.services.securitylake.checks.sra_securitylake_03 import SRA_SECURITYLAKE_03
6
+ from sraverify.services.securitylake.checks.sra_securitylake_04 import SRA_SECURITYLAKE_04
7
+ from sraverify.services.securitylake.checks.sra_securitylake_05 import SRA_SECURITYLAKE_05
8
+ from sraverify.services.securitylake.checks.sra_securitylake_06 import SRA_SECURITYLAKE_06
9
+ from sraverify.services.securitylake.checks.sra_securitylake_07 import SRA_SECURITYLAKE_07
10
+ from sraverify.services.securitylake.checks.sra_securitylake_08 import SRA_SECURITYLAKE_08
11
+ from sraverify.services.securitylake.checks.sra_securitylake_09 import SRA_SECURITYLAKE_09
12
+ from sraverify.services.securitylake.checks.sra_securitylake_10 import SRA_SECURITYLAKE_10
13
+ from sraverify.services.securitylake.checks.sra_securitylake_11 import SRA_SECURITYLAKE_11
14
+ from sraverify.services.securitylake.checks.sra_securitylake_12 import SRA_SECURITYLAKE_12
15
+ from sraverify.services.securitylake.checks.sra_securitylake_13 import SRA_SECURITYLAKE_13
16
+ from sraverify.services.securitylake.checks.sra_securitylake_14 import SRA_SECURITYLAKE_14
17
+ from sraverify.services.securitylake.checks.sra_securitylake_15 import SRA_SECURITYLAKE_15
18
+ from sraverify.services.securitylake.checks.sra_securitylake_16 import SRA_SECURITYLAKE_16
19
+ from sraverify.services.securitylake.checks.sra_securitylake_17 import SRA_SECURITYLAKE_17
20
+
21
+ CHECKS = {
22
+ "SRA-SECURITYLAKE-01": SRA_SECURITYLAKE_01,
23
+ "SRA-SECURITYLAKE-02": SRA_SECURITYLAKE_02,
24
+ "SRA-SECURITYLAKE-03": SRA_SECURITYLAKE_03,
25
+ "SRA-SECURITYLAKE-04": SRA_SECURITYLAKE_04,
26
+ "SRA-SECURITYLAKE-05": SRA_SECURITYLAKE_05,
27
+ "SRA-SECURITYLAKE-06": SRA_SECURITYLAKE_06,
28
+ "SRA-SECURITYLAKE-07": SRA_SECURITYLAKE_07,
29
+ "SRA-SECURITYLAKE-08": SRA_SECURITYLAKE_08,
30
+ "SRA-SECURITYLAKE-09": SRA_SECURITYLAKE_09,
31
+ "SRA-SECURITYLAKE-10": SRA_SECURITYLAKE_10,
32
+ "SRA-SECURITYLAKE-11": SRA_SECURITYLAKE_11,
33
+ "SRA-SECURITYLAKE-12": SRA_SECURITYLAKE_12,
34
+ "SRA-SECURITYLAKE-13": SRA_SECURITYLAKE_13,
35
+ "SRA-SECURITYLAKE-14": SRA_SECURITYLAKE_14,
36
+ "SRA-SECURITYLAKE-15": SRA_SECURITYLAKE_15,
37
+ "SRA-SECURITYLAKE-16": SRA_SECURITYLAKE_16,
38
+ "SRA-SECURITYLAKE-17": SRA_SECURITYLAKE_17
39
+ }