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,113 @@
1
+ """
2
+ SRA-SECURITYHUB-08: Security Hub check.
3
+ """
4
+ from typing import List, Dict, Any, Set
5
+ from sraverify.services.securityhub.base import SecurityHubCheck
6
+ from sraverify.core.logging import logger
7
+
8
+
9
+ class SRA_SECURITYHUB_08(SecurityHubCheck):
10
+ """Check if all active organization accounts are Security Hub members."""
11
+
12
+ def __init__(self):
13
+ """Initialize the check."""
14
+ super().__init__()
15
+ self.check_id = "SRA-SECURITYHUB-08"
16
+ self.check_name = "All active organization accounts are Security Hub members"
17
+ self.account_type = "audit" # This check is for the audit account
18
+ self.severity = "HIGH"
19
+ self.description = (
20
+ "This check verifies whether all active members accounts of the AWS Organization are Security Hub members. "
21
+ "Security Hub provides comprehensive security state and should include all AWS accounts."
22
+ )
23
+ self.check_logic = (
24
+ "Compare the outputs of organizations list-accounts and securityhub list-members. "
25
+ "Make sure that the list includes all accounts, excluding the Security Hub admin (audit account) "
26
+ "which is not considered a member."
27
+ )
28
+ self._audit_accounts = [] # Will be populated from command line args
29
+
30
+ def execute(self) -> List[Dict[str, Any]]:
31
+ """
32
+ Execute the check.
33
+
34
+ Returns:
35
+ List of findings
36
+ """
37
+ findings = []
38
+
39
+ # Check each region separately
40
+ for region in self.regions:
41
+ # Get all organization accounts
42
+ org_accounts = self.get_organization_accounts(region)
43
+
44
+ # Get Security Hub members
45
+ securityhub_members = self.get_security_hub_members(region)
46
+
47
+ resource_id = f"securityhub:members/{self.account_id}/{region}"
48
+
49
+ # Create sets of account IDs for comparison
50
+ active_org_account_ids = set()
51
+ for account in org_accounts:
52
+ if account.get('Status') == 'ACTIVE':
53
+ active_org_account_ids.add(account.get('Id'))
54
+
55
+ securityhub_member_ids = set()
56
+ for member in securityhub_members:
57
+ securityhub_member_ids.add(member.get('AccountId'))
58
+
59
+ # Determine the audit account ID
60
+ audit_account_id = None
61
+ if self._audit_accounts:
62
+ audit_account_id = self._audit_accounts[0]
63
+ else:
64
+ # If no audit account is provided, assume the current account is the audit account
65
+ audit_account_id = self.account_id
66
+
67
+ # Remove the audit account from the list of active organization accounts
68
+ # since the audit account is the Security Hub admin and not a member
69
+ if audit_account_id in active_org_account_ids:
70
+ active_org_account_ids.remove(audit_account_id)
71
+
72
+ # Find accounts that should be Security Hub members but aren't
73
+ missing_accounts = active_org_account_ids - securityhub_member_ids
74
+
75
+ if missing_accounts:
76
+ missing_accounts_list = ', '.join(missing_accounts)
77
+ findings.append(
78
+ self.create_finding(
79
+ status="FAIL",
80
+ region=region,
81
+ resource_id=resource_id,
82
+ checked_value="All active organization accounts are Security Hub members",
83
+ actual_value=(
84
+ f"The following active organization accounts are not Security Hub members in region {region}: "
85
+ f"{missing_accounts_list}. "
86
+ f"Active organization accounts: {len(active_org_account_ids)}, "
87
+ f"Security Hub members: {len(securityhub_member_ids)}"
88
+ ),
89
+ remediation=(
90
+ f"Add the missing accounts as Security Hub members in region {region}. "
91
+ f"In the AWS Console, navigate to Security Hub in the audit account, go to Settings > Accounts, "
92
+ f"and add the missing accounts. Alternatively, use the AWS CLI command: "
93
+ f"aws securityhub create-members --account-details 'AccountId={missing_accounts_list.replace(', ', ',AccountId=')}' --region {region}"
94
+ )
95
+ )
96
+ )
97
+ else:
98
+ findings.append(
99
+ self.create_finding(
100
+ status="PASS",
101
+ region=region,
102
+ resource_id=resource_id,
103
+ checked_value="All active organization accounts are Security Hub members",
104
+ actual_value=(
105
+ f"All active organization accounts are Security Hub members in region {region}. "
106
+ f"Active organization accounts (excluding admin): {len(active_org_account_ids)}, "
107
+ f"Security Hub members: {len(securityhub_member_ids)}"
108
+ ),
109
+ remediation="No remediation needed"
110
+ )
111
+ )
112
+
113
+ return findings
@@ -0,0 +1,100 @@
1
+ """
2
+ SRA-SECURITYHUB-09: Security Hub check.
3
+ """
4
+ from typing import List, Dict, Any
5
+ from sraverify.services.securityhub.base import SecurityHubCheck
6
+ from sraverify.core.logging import logger
7
+
8
+
9
+ class SRA_SECURITYHUB_09(SecurityHubCheck):
10
+ """Check if all Security Hub member accounts have Enabled status."""
11
+
12
+ def __init__(self):
13
+ """Initialize the check."""
14
+ super().__init__()
15
+ self.check_id = "SRA-SECURITYHUB-09"
16
+ self.check_name = "All Security Hub member accounts have Enabled status"
17
+ self.account_type = "audit" # This check is for the audit account
18
+ self.severity = "HIGH"
19
+ self.description = (
20
+ "This check verifies whether each Security Hub member account has member status Enabled. "
21
+ "Enabled status indicates that the member account is currently active. For manually invited "
22
+ "member accounts, it indicates that the member account accepted the invitation."
23
+ )
24
+ self.check_logic = (
25
+ "Check runs aws securityhub list-members in each region and verifies that all members have "
26
+ "MemberStatus: Enabled. PASS if all members have Enabled status."
27
+ )
28
+
29
+ def execute(self) -> List[Dict[str, Any]]:
30
+ """
31
+ Execute the check.
32
+
33
+ Returns:
34
+ List of findings
35
+ """
36
+ findings = []
37
+
38
+ # Check each region separately
39
+ for region in self.regions:
40
+ # Get Security Hub members
41
+ securityhub_members = self.get_security_hub_members(region)
42
+
43
+ resource_id = f"securityhub:members/{self.account_id}/{region}"
44
+
45
+ # Check if there are any members
46
+ if not securityhub_members:
47
+ findings.append(
48
+ self.create_finding(
49
+ status="PASS",
50
+ region=region,
51
+ resource_id=resource_id,
52
+ checked_value="All Security Hub member accounts have Enabled status",
53
+ actual_value=f"No Security Hub member accounts found in region {region}",
54
+ remediation="No remediation needed"
55
+ )
56
+ )
57
+ continue
58
+
59
+ # Find members that don't have Enabled status
60
+ non_enabled_members = []
61
+ for member in securityhub_members:
62
+ member_id = member.get('AccountId')
63
+ member_status = member.get('MemberStatus')
64
+
65
+ if member_status != 'Enabled':
66
+ non_enabled_members.append(f"{member_id} (Status: {member_status})")
67
+
68
+ if non_enabled_members:
69
+ findings.append(
70
+ self.create_finding(
71
+ status="FAIL",
72
+ region=region,
73
+ resource_id=resource_id,
74
+ checked_value="All Security Hub member accounts have Enabled status",
75
+ actual_value=(
76
+ f"The following Security Hub member accounts do not have Enabled status in region {region}: "
77
+ f"{', '.join(non_enabled_members)}"
78
+ ),
79
+ remediation=(
80
+ f"Ensure all Security Hub member accounts have Enabled status in region {region}. "
81
+ f"For manually invited accounts, the member account needs to accept the invitation. "
82
+ f"For organization-based members, verify the account is properly configured. "
83
+ f"In the AWS Console, navigate to Security Hub in the audit account, go to Settings > Accounts, "
84
+ f"and check the status of each member account."
85
+ )
86
+ )
87
+ )
88
+ else:
89
+ findings.append(
90
+ self.create_finding(
91
+ status="PASS",
92
+ region=region,
93
+ resource_id=resource_id,
94
+ checked_value="All Security Hub member accounts have Enabled status",
95
+ actual_value=f"All {len(securityhub_members)} Security Hub member accounts have Enabled status in region {region}",
96
+ remediation="No remediation needed"
97
+ )
98
+ )
99
+
100
+ return findings
@@ -0,0 +1,94 @@
1
+ """
2
+ SRA-SECURITYHUB-10: Security Hub check.
3
+ """
4
+ from typing import List, Dict, Any
5
+ from sraverify.services.securityhub.base import SecurityHubCheck
6
+ from sraverify.core.logging import logger
7
+
8
+
9
+ class SRA_SECURITYHUB_10(SecurityHubCheck):
10
+ """Check if Security Hub auto-enable is configured for new member accounts."""
11
+
12
+ def __init__(self):
13
+ """Initialize the check."""
14
+ super().__init__()
15
+ self.check_id = "SRA-SECURITYHUB-10"
16
+ self.check_name = "Security Hub auto-enable is configured"
17
+ self.account_type = "audit" # This check is for the audit account
18
+ self.severity = "MEDIUM"
19
+ self.description = (
20
+ "This check verifies whether Security Hub is configured to be automatically enabled "
21
+ "for new member accounts when they join the organization."
22
+ )
23
+ self.check_logic = (
24
+ "Check evaluates Security Hub organization configuration. For central configuration, "
25
+ "PASS if ConfigurationType is CENTRAL (uses configuration policies). For local configuration, "
26
+ "PASS if AutoEnable is true."
27
+ )
28
+
29
+ def execute(self) -> List[Dict[str, Any]]:
30
+ """
31
+ Execute the check.
32
+
33
+ Returns:
34
+ List of findings
35
+ """
36
+ findings = []
37
+
38
+ # Check each region separately
39
+ for region in self.regions:
40
+ # Get organization configuration in this specific region
41
+ org_config = self.get_organization_configuration(region)
42
+
43
+ resource_id = f"securityhub:organization-configuration/{self.account_id}"
44
+
45
+ # Check if using central configuration
46
+ org_configuration = org_config.get('OrganizationConfiguration', {})
47
+ config_type = org_configuration.get('ConfigurationType')
48
+
49
+ if config_type == 'CENTRAL':
50
+ # In central configuration, AutoEnable is always false and not relevant
51
+ # Configuration policies handle new account enablement
52
+ findings.append(
53
+ self.create_finding(
54
+ status="PASS",
55
+ region=region,
56
+ resource_id=resource_id,
57
+ checked_value="Security Hub auto-enable configured for new accounts",
58
+ actual_value=f"Central configuration enabled [ConfigurationType: CENTRAL] in region {region} - new accounts managed via configuration policies",
59
+ remediation="No remediation needed - central configuration manages new account enablement through configuration policies"
60
+ )
61
+ )
62
+ else:
63
+ # For local configuration, check AutoEnable
64
+ auto_enable = org_config.get('AutoEnable', False)
65
+
66
+ if not auto_enable:
67
+ findings.append(
68
+ self.create_finding(
69
+ status="FAIL",
70
+ region=region,
71
+ resource_id=resource_id,
72
+ checked_value="Security Hub is set to auto-enable for new member accounts",
73
+ actual_value=f"AutoEnable is set to false in region {region}",
74
+ remediation=(
75
+ f"Configure Security Hub to automatically enable for new member accounts in region {region}. "
76
+ f"In the AWS Console, navigate to Security Hub in region {region}, go to Settings > Configuration, "
77
+ f"and enable 'Auto-enable Security Hub for new accounts'. Alternatively, use the AWS CLI command: "
78
+ f"aws securityhub update-organization-configuration --auto-enable --region {region}"
79
+ )
80
+ )
81
+ )
82
+ else:
83
+ findings.append(
84
+ self.create_finding(
85
+ status="PASS",
86
+ region=region,
87
+ resource_id=resource_id,
88
+ checked_value="Security Hub is set to auto-enable for new member accounts",
89
+ actual_value=f"AutoEnable is set to true in region {region}",
90
+ remediation="No remediation needed"
91
+ )
92
+ )
93
+
94
+ return findings
@@ -0,0 +1,73 @@
1
+ """
2
+ SRA-SECURITYHUB-11: Security Hub check.
3
+ """
4
+ from typing import List, Dict, Any
5
+ from sraverify.services.securityhub.base import SecurityHubCheck
6
+ from sraverify.core.logging import logger
7
+
8
+
9
+ class SRA_SECURITYHUB_11(SecurityHubCheck):
10
+ """Check if Security Hub member account limit has not been reached."""
11
+
12
+ def __init__(self):
13
+ """Initialize the check."""
14
+ super().__init__()
15
+ self.check_id = "SRA-SECURITYHUB-11"
16
+ self.check_name = "Security Hub member account limit not reached"
17
+ self.account_type = "audit" # This check is for the audit account
18
+ self.severity = "HIGH"
19
+ self.description = (
20
+ "This check verifies whether the maximum number of allowed member accounts are already associated "
21
+ "with the delegated administrator account for the AWS Organization."
22
+ )
23
+ self.check_logic = (
24
+ "Check evaluates if Security Hub describe-organization-configuration returns \"MemberAccountLimitReached\": false. "
25
+ "PASS if MemberAccountLimitReached is false."
26
+ )
27
+
28
+ def execute(self) -> List[Dict[str, Any]]:
29
+ """
30
+ Execute the check.
31
+
32
+ Returns:
33
+ List of findings
34
+ """
35
+ findings = []
36
+
37
+ # Check each region separately
38
+ for region in self.regions:
39
+ # Get organization configuration in this specific region
40
+ org_config = self.get_organization_configuration(region)
41
+
42
+ resource_id = f"securityhub:member-quota/{self.account_id}"
43
+
44
+ # Check if MemberAccountLimitReached is false
45
+ limit_reached = org_config.get('MemberAccountLimitReached', True)
46
+
47
+ if limit_reached:
48
+ findings.append(
49
+ self.create_finding(
50
+ status="FAIL",
51
+ region=region,
52
+ resource_id=resource_id,
53
+ checked_value="Security Hub has not hit member account limit",
54
+ actual_value=f"Security Hub has hit member account limit in region {region}",
55
+ remediation=(
56
+ f"Contact AWS Support to request an increase in the Security Hub member account limit for region {region}. "
57
+ f"Alternatively, review your Security Hub member accounts and consider removing inactive or unnecessary accounts."
58
+ )
59
+ )
60
+ )
61
+ else:
62
+ findings.append(
63
+ self.create_finding(
64
+ status="PASS",
65
+ region=region,
66
+ resource_id=resource_id,
67
+ checked_value="Security Hub has not hit member account limit",
68
+ actual_value=f"Security Hub has not hit member account limit in region {region}",
69
+ remediation="No remediation needed"
70
+ )
71
+ )
72
+
73
+ return findings
@@ -0,0 +1,249 @@
1
+ """
2
+ SecurityHub client for interacting with AWS SecurityHub service.
3
+ """
4
+ from typing import Dict, List, Optional, Any
5
+ import boto3
6
+ from botocore.exceptions import ClientError
7
+ from sraverify.core.logging import logger
8
+
9
+
10
+ class SecurityHubClient:
11
+ """Client for interacting with AWS SecurityHub service."""
12
+
13
+ def __init__(self, region: str, session: Optional[boto3.Session] = None):
14
+ """
15
+ Initialize SecurityHub client for a specific region.
16
+
17
+ Args:
18
+ region: AWS region name
19
+ session: AWS session to use (if None, a new session will be created)
20
+ """
21
+ self.region = region
22
+ self.session = session or boto3.Session()
23
+ self.client = self.session.client('securityhub', region_name=region)
24
+ self.org_client = self.session.client('organizations', region_name=region)
25
+
26
+ def get_enabled_standards(self) -> List[Dict[str, Any]]:
27
+ """
28
+ Get all enabled Security Hub standards.
29
+
30
+ Returns:
31
+ List of enabled standards or None if Security Hub is not enabled
32
+ """
33
+ try:
34
+ logger.debug(f"Getting enabled standards in {self.region}")
35
+ response = self.client.get_enabled_standards()
36
+ standards = response.get('StandardsSubscriptions', [])
37
+
38
+ # Handle pagination
39
+ while response.get('NextToken'):
40
+ response = self.client.get_enabled_standards(NextToken=response['NextToken'])
41
+ standards.extend(response.get('StandardsSubscriptions', []))
42
+
43
+ logger.debug(f"Found {len(standards)} enabled standards in {self.region}")
44
+ return standards
45
+ except ClientError as e:
46
+ error_code = e.response.get('Error', {}).get('Code', '')
47
+ error_message = e.response.get('Error', {}).get('Message', '')
48
+
49
+ # Check if this is the "not subscribed to AWS Security Hub" error
50
+ if error_code == 'InvalidAccessException' and 'not subscribed to AWS Security Hub' in error_message:
51
+ # Return None specifically for this error to indicate Security Hub is not enabled
52
+ # Don't log this as an error since it's an expected condition we want to check for
53
+ logger.debug(f"Security Hub is not enabled in {self.region}")
54
+ return None
55
+
56
+ # For other errors, log a warning instead of an error
57
+ logger.warning(f"Error getting enabled standards in {self.region}: {e}")
58
+ return []
59
+ except Exception as e:
60
+ logger.warning(f"Unexpected error getting enabled standards in {self.region}: {e}")
61
+ return []
62
+
63
+ def list_organization_admin_accounts(self) -> List[Dict[str, Any]]:
64
+ """
65
+ List Security Hub administrator accounts for the organization.
66
+
67
+ Returns:
68
+ List of administrator accounts
69
+ """
70
+ try:
71
+ logger.debug(f"Listing organization admin accounts in {self.region}")
72
+ response = self.client.list_organization_admin_accounts()
73
+ admin_accounts = response.get('AdminAccounts', [])
74
+
75
+ # Handle pagination
76
+ while response.get('NextToken'):
77
+ response = self.client.list_organization_admin_accounts(NextToken=response['NextToken'])
78
+ admin_accounts.extend(response.get('AdminAccounts', []))
79
+
80
+ logger.debug(f"Found {len(admin_accounts)} organization admin accounts in {self.region}")
81
+ return admin_accounts
82
+ except ClientError as e:
83
+ logger.error(f"Error listing organization admin accounts in {self.region}: {e}")
84
+ return []
85
+ except Exception as e:
86
+ logger.error(f"Unexpected error listing organization admin accounts in {self.region}: {e}")
87
+ return []
88
+
89
+ def get_administrator_account(self) -> Dict[str, Any]:
90
+ """
91
+ Get the Security Hub administrator account for the current account.
92
+
93
+ Returns:
94
+ Administrator account information
95
+ """
96
+ try:
97
+ logger.debug(f"Getting administrator account in {self.region}")
98
+ response = self.client.get_administrator_account()
99
+ logger.debug(f"Administrator account: {response}")
100
+ return response
101
+ except ClientError as e:
102
+ logger.error(f"Error getting administrator account in {self.region}: {e}")
103
+ return {}
104
+ except Exception as e:
105
+ logger.error(f"Unexpected error getting administrator account in {self.region}: {e}")
106
+ return {}
107
+
108
+ def describe_organization_configuration(self) -> Dict[str, Any]:
109
+ """
110
+ Describe the Security Hub organization configuration.
111
+
112
+ Returns:
113
+ Organization configuration
114
+ """
115
+ try:
116
+ logger.debug(f"Describing organization configuration in {self.region}")
117
+ response = self.client.describe_organization_configuration()
118
+ logger.debug(f"Organization configuration: {response}")
119
+ return response
120
+ except ClientError as e:
121
+ # Don't log the error here, let the check handle it
122
+ return {}
123
+ except Exception as e:
124
+ # Only log unexpected errors
125
+ logger.error(f"Unexpected error describing organization configuration in {self.region}: {e}")
126
+ return {}
127
+
128
+
129
+ def list_enabled_products_for_import(self) -> Optional[List[str]]:
130
+ """
131
+ List enabled products for import into Security Hub.
132
+
133
+ Returns:
134
+ List of enabled product ARNs, or None if Security Hub is not enabled
135
+ """
136
+ try:
137
+ logger.debug(f"Listing enabled products for import in {self.region}")
138
+ response = self.client.list_enabled_products_for_import()
139
+ product_subscriptions = response.get('ProductSubscriptions', [])
140
+
141
+ # Handle pagination
142
+ while response.get('NextToken'):
143
+ response = self.client.list_enabled_products_for_import(NextToken=response['NextToken'])
144
+ product_subscriptions.extend(response.get('ProductSubscriptions', []))
145
+
146
+ logger.debug(f"Found {len(product_subscriptions)} enabled products in {self.region}")
147
+ return product_subscriptions
148
+ except ClientError as e:
149
+ error_code = e.response.get('Error', {}).get('Code', '')
150
+ error_message = e.response.get('Error', {}).get('Message', '')
151
+
152
+ # Check if this is the "not subscribed to AWS Security Hub" error
153
+ if error_code == 'InvalidAccessException' and 'not subscribed to AWS Security Hub' in error_message:
154
+ # Return None specifically for this error to indicate Security Hub is not enabled
155
+ logger.debug(f"Security Hub is not enabled in {self.region}")
156
+ return None
157
+
158
+ # For other errors, log as error and return empty list
159
+ logger.error(f"Error listing enabled products in {self.region}: {e}")
160
+ return []
161
+ except Exception as e:
162
+ logger.error(f"Unexpected error listing enabled products in {self.region}: {e}")
163
+ return []
164
+
165
+ def list_delegated_administrators(self, service_principal: str = "securityhub.amazonaws.com") -> List[Dict[str, Any]]:
166
+ """
167
+ List delegated administrators for SecurityHub.
168
+
169
+ Args:
170
+ service_principal: Service principal to check for delegated administrators
171
+
172
+ Returns:
173
+ List of delegated administrators
174
+ """
175
+ try:
176
+ logger.debug(f"Listing delegated administrators for {service_principal} in {self.region}")
177
+ response = self.org_client.list_delegated_administrators(ServicePrincipal=service_principal)
178
+ delegated_admins = response.get('DelegatedAdministrators', [])
179
+
180
+ # Handle pagination
181
+ while response.get('NextToken'):
182
+ response = self.org_client.list_delegated_administrators(
183
+ ServicePrincipal=service_principal,
184
+ NextToken=response['NextToken']
185
+ )
186
+ delegated_admins.extend(response.get('DelegatedAdministrators', []))
187
+
188
+ logger.debug(f"Found {len(delegated_admins)} delegated administrators for {service_principal}")
189
+ for admin in delegated_admins:
190
+ logger.debug(f"Delegated admin: {admin.get('Id')} - {admin.get('Name')}")
191
+ return delegated_admins
192
+ except ClientError as e:
193
+ logger.error(f"Error listing delegated administrators for {service_principal}: {e}")
194
+ return []
195
+ except Exception as e:
196
+ logger.error(f"Unexpected error listing delegated administrators: {e}")
197
+ return []
198
+
199
+ def list_members(self) -> List[Dict[str, Any]]:
200
+ """
201
+ List Security Hub member accounts.
202
+
203
+ Returns:
204
+ List of member accounts
205
+ """
206
+ try:
207
+ logger.debug(f"Listing Security Hub members in {self.region}")
208
+ response = self.client.list_members()
209
+ members = response.get('Members', [])
210
+
211
+ # Handle pagination
212
+ while response.get('NextToken'):
213
+ response = self.client.list_members(NextToken=response['NextToken'])
214
+ members.extend(response.get('Members', []))
215
+
216
+ logger.debug(f"Found {len(members)} Security Hub members in {self.region}")
217
+ return members
218
+ except ClientError as e:
219
+ logger.error(f"Error listing Security Hub members in {self.region}: {e}")
220
+ return []
221
+ except Exception as e:
222
+ logger.error(f"Unexpected error listing Security Hub members in {self.region}: {e}")
223
+ return []
224
+
225
+ def list_organization_accounts(self) -> List[Dict[str, Any]]:
226
+ """
227
+ List all accounts in the organization.
228
+
229
+ Returns:
230
+ List of organization accounts
231
+ """
232
+ try:
233
+ logger.debug(f"Listing organization accounts in {self.region}")
234
+ response = self.org_client.list_accounts()
235
+ accounts = response.get('Accounts', [])
236
+
237
+ # Handle pagination
238
+ while response.get('NextToken'):
239
+ response = self.org_client.list_accounts(NextToken=response['NextToken'])
240
+ accounts.extend(response.get('Accounts', []))
241
+
242
+ logger.debug(f"Found {len(accounts)} organization accounts")
243
+ return accounts
244
+ except ClientError as e:
245
+ logger.error(f"Error listing organization accounts: {e}")
246
+ return []
247
+ except Exception as e:
248
+ logger.error(f"Unexpected error listing organization accounts: {e}")
249
+ return []
@@ -0,0 +1,13 @@
1
+ from sraverify.services.securityincidentresponse.checks.sra_securityincidentresponse_01 import SRA_SECURITYINCIDENTRESPONSE_01
2
+ from sraverify.services.securityincidentresponse.checks.sra_securityincidentresponse_02 import SRA_SECURITYINCIDENTRESPONSE_02
3
+ from sraverify.services.securityincidentresponse.checks.sra_securityincidentresponse_03 import SRA_SECURITYINCIDENTRESPONSE_03
4
+ from sraverify.services.securityincidentresponse.checks.sra_securityincidentresponse_04 import SRA_SECURITYINCIDENTRESPONSE_04
5
+ from sraverify.services.securityincidentresponse.checks.sra_securityincidentresponse_05 import SRA_SECURITYINCIDENTRESPONSE_05
6
+
7
+ CHECKS = {
8
+ "SRA-SECURITYINCIDENTRESPONSE-01": SRA_SECURITYINCIDENTRESPONSE_01,
9
+ "SRA-SECURITYINCIDENTRESPONSE-02": SRA_SECURITYINCIDENTRESPONSE_02,
10
+ "SRA-SECURITYINCIDENTRESPONSE-03": SRA_SECURITYINCIDENTRESPONSE_03,
11
+ "SRA-SECURITYINCIDENTRESPONSE-04": SRA_SECURITYINCIDENTRESPONSE_04,
12
+ "SRA-SECURITYINCIDENTRESPONSE-05": SRA_SECURITYINCIDENTRESPONSE_05,
13
+ }