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,88 @@
1
+ """
2
+ SRA-S3-04: S3 block public policy is enabled.
3
+ """
4
+ from typing import List, Dict, Any
5
+ from sraverify.services.s3.base import S3Check
6
+ from sraverify.core.logging import logger
7
+
8
+
9
+ class SRA_S3_04(S3Check):
10
+ """Check if S3 block public policy is enabled for the account."""
11
+
12
+ def __init__(self):
13
+ """Initialize the check."""
14
+ super().__init__()
15
+ self.check_id = "SRA-S3-04"
16
+ self.check_name = "S3 block public policy is enabled"
17
+ self.account_type = "application"
18
+ self.severity = "HIGH"
19
+ self.description = (
20
+ "This check verifies whether S3 should block public bucket policies for buckets. "
21
+ "Setting this causes Amazon S3 to reject calls that attaches a public access bucket policy to a S3 bucket."
22
+ )
23
+ self.check_logic = (
24
+ "Check if BlockPublicPolicy is set to true in the account's public access block configuration."
25
+ )
26
+
27
+ def execute(self) -> List[Dict[str, Any]]:
28
+ """
29
+ Execute the check.
30
+
31
+ Returns:
32
+ List of findings
33
+ """
34
+ findings = []
35
+
36
+ # Get public access block configuration using the base class method
37
+ # This will use the cache if available or make API calls if needed
38
+ public_access_config = self.get_public_access()
39
+
40
+ # Check if the configuration exists and BlockPublicPolicy is enabled
41
+ if not public_access_config:
42
+ findings.append(
43
+ self.create_finding(
44
+ status="FAIL",
45
+ region="global", # S3 public access block is a global setting
46
+ resource_id=self.account_id,
47
+ checked_value="BlockPublicPolicy: true",
48
+ actual_value="No public access block configuration found",
49
+ remediation=(
50
+ "Enable S3 Block Public Access at the account level using the AWS CLI command: "
51
+ f"aws s3control put-public-access-block --account-id {self.account_id} "
52
+ "--public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true,"
53
+ "BlockPublicPolicy=true,RestrictPublicBuckets=true"
54
+ )
55
+ )
56
+ )
57
+ return findings
58
+
59
+ block_public_policy = public_access_config.get('BlockPublicPolicy', False)
60
+
61
+ if block_public_policy:
62
+ findings.append(
63
+ self.create_finding(
64
+ status="PASS",
65
+ region="global", # S3 public access block is a global setting
66
+ resource_id=self.account_id,
67
+ checked_value="BlockPublicPolicy: true",
68
+ actual_value="BlockPublicPolicy setting is true",
69
+ remediation="No remediation needed"
70
+ )
71
+ )
72
+ else:
73
+ findings.append(
74
+ self.create_finding(
75
+ status="FAIL",
76
+ region="global", # S3 public access block is a global setting
77
+ resource_id=self.account_id,
78
+ checked_value="BlockPublicPolicy: true",
79
+ actual_value="BlockPublicPolicy setting is false",
80
+ remediation=(
81
+ "Enable S3 Block Public Policy at the account level using the AWS CLI command: "
82
+ f"aws s3control put-public-access-block --account-id {self.account_id} "
83
+ "--public-access-block-configuration BlockPublicPolicy=true"
84
+ )
85
+ )
86
+ )
87
+
88
+ return findings
@@ -0,0 +1,52 @@
1
+ """
2
+ S3 client for interacting with AWS S3 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 S3Client:
11
+ """Client for interacting with AWS S3 service."""
12
+
13
+ def __init__(self, region: str, session: Optional[boto3.Session] = None):
14
+ """
15
+ Initialize S3 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('s3', region_name=region)
24
+ self.s3control_client = self.session.client('s3control', region_name=region)
25
+
26
+ def get_public_access_block(self, account_id: str) -> Dict[str, Any]:
27
+ """
28
+ Get the public access block configuration for an account.
29
+
30
+ Args:
31
+ account_id: AWS account ID
32
+
33
+ Returns:
34
+ Public access block configuration
35
+ """
36
+ try:
37
+ logger.debug(f"Getting public access block configuration for account {account_id} in {self.region}")
38
+ response = self.s3control_client.get_public_access_block(
39
+ AccountId=account_id
40
+ )
41
+ return response.get('PublicAccessBlockConfiguration', {})
42
+ except ClientError as e:
43
+ if 'NoSuchPublicAccessBlockConfiguration' in str(e):
44
+ # Silently handle the case where no configuration exists
45
+ # This is a common case and not an error condition
46
+ logger.debug(f"No public access block configuration found for account {account_id} in {self.region}")
47
+ return {}
48
+ logger.error(f"Error getting public access block configuration for account {account_id} in {self.region}: {e}")
49
+ return {}
50
+ except Exception as e:
51
+ logger.error(f"Unexpected error getting public access block configuration for account {account_id} in {self.region}: {e}")
52
+ return {}
@@ -0,0 +1,27 @@
1
+ """SecurityHub service checks."""
2
+
3
+ from sraverify.services.securityhub.checks.sra_securityhub_01 import SRA_SECURITYHUB_01
4
+ from sraverify.services.securityhub.checks.sra_securityhub_02 import SRA_SECURITYHUB_02
5
+ from sraverify.services.securityhub.checks.sra_securityhub_03 import SRA_SECURITYHUB_03
6
+ from sraverify.services.securityhub.checks.sra_securityhub_04 import SRA_SECURITYHUB_04
7
+ from sraverify.services.securityhub.checks.sra_securityhub_05 import SRA_SECURITYHUB_05
8
+ from sraverify.services.securityhub.checks.sra_securityhub_06 import SRA_SECURITYHUB_06
9
+ from sraverify.services.securityhub.checks.sra_securityhub_07 import SRA_SECURITYHUB_07
10
+ from sraverify.services.securityhub.checks.sra_securityhub_08 import SRA_SECURITYHUB_08
11
+ from sraverify.services.securityhub.checks.sra_securityhub_09 import SRA_SECURITYHUB_09
12
+ from sraverify.services.securityhub.checks.sra_securityhub_10 import SRA_SECURITYHUB_10
13
+ from sraverify.services.securityhub.checks.sra_securityhub_11 import SRA_SECURITYHUB_11
14
+
15
+ CHECKS = {
16
+ "SRA-SECURITYHUB-01": SRA_SECURITYHUB_01,
17
+ "SRA-SECURITYHUB-02": SRA_SECURITYHUB_02,
18
+ "SRA-SECURITYHUB-03": SRA_SECURITYHUB_03,
19
+ "SRA-SECURITYHUB-04": SRA_SECURITYHUB_04,
20
+ "SRA-SECURITYHUB-05": SRA_SECURITYHUB_05,
21
+ "SRA-SECURITYHUB-06": SRA_SECURITYHUB_06,
22
+ "SRA-SECURITYHUB-07": SRA_SECURITYHUB_07,
23
+ "SRA-SECURITYHUB-08": SRA_SECURITYHUB_08,
24
+ "SRA-SECURITYHUB-09": SRA_SECURITYHUB_09,
25
+ "SRA-SECURITYHUB-10": SRA_SECURITYHUB_10,
26
+ "SRA-SECURITYHUB-11": SRA_SECURITYHUB_11,
27
+ }
@@ -0,0 +1,349 @@
1
+ """
2
+ Base class for SecurityHub security checks.
3
+ """
4
+ from typing import List, Optional, Dict, Any
5
+ from sraverify.core.check import SecurityCheck
6
+ from sraverify.services.securityhub.client import SecurityHubClient
7
+ from sraverify.core.logging import logger
8
+
9
+
10
+ class SecurityHubCheck(SecurityCheck):
11
+ """Base class for all SecurityHub security checks."""
12
+
13
+ # Class-level caches shared across all instances
14
+ _enabled_standards_cache = {}
15
+ _admin_account_cache = {}
16
+ _organization_configuration_cache = {}
17
+ _product_integrations_cache = {}
18
+ _delegated_admin_cache = {}
19
+ _organization_accounts_cache = {}
20
+ _securityhub_members_cache = {}
21
+
22
+ def __init__(self):
23
+ """Initialize SecurityHub base check."""
24
+ super().__init__(
25
+ account_type="audit", # Default to audit, can be overridden in child classes
26
+ service="SecurityHub",
27
+ resource_type="AWS::SecurityHub::Hub"
28
+ )
29
+
30
+ def _setup_clients(self):
31
+ """Set up SecurityHub clients for each region."""
32
+ # Clear existing clients
33
+ self._clients.clear()
34
+ # Set up new clients only if regions are initialized
35
+ if hasattr(self, 'regions') and self.regions:
36
+ for region in self.regions:
37
+ self._clients[region] = SecurityHubClient(region, session=self.session)
38
+
39
+ def get_client(self, region: str) -> Optional[SecurityHubClient]:
40
+ """
41
+ Get SecurityHub client for a specific region.
42
+
43
+ Args:
44
+ region: AWS region name
45
+
46
+ Returns:
47
+ SecurityHubClient for the region or None if not available
48
+ """
49
+ return self._clients.get(region)
50
+
51
+ def get_enabled_standards(self, region: str) -> List[Dict[str, Any]]:
52
+ """
53
+ Get enabled Security Hub standards for a region with caching.
54
+
55
+ Args:
56
+ region: AWS region name
57
+
58
+ Returns:
59
+ List of enabled standards or None if Security Hub is not enabled
60
+ """
61
+ account_id = self.account_id
62
+ if not account_id:
63
+ logger.warning("Could not determine account ID")
64
+ return []
65
+
66
+ # Check cache first
67
+ cache_key = f"{account_id}:{region}"
68
+ if cache_key in self.__class__._enabled_standards_cache:
69
+ logger.debug(f"Using cached enabled standards for {cache_key}")
70
+ return self.__class__._enabled_standards_cache[cache_key]
71
+
72
+ client = self.get_client(region)
73
+ if not client:
74
+ logger.warning(f"No SecurityHub client available for region {region}")
75
+ return []
76
+
77
+ try:
78
+ # Get enabled standards from client
79
+ standards = client.get_enabled_standards()
80
+
81
+ # If standards is None (Security Hub not enabled), don't try to cache it
82
+ if standards is None:
83
+ logger.debug(f"Security Hub is not enabled in region {region}")
84
+ return None
85
+
86
+ # Cache the results
87
+ self.__class__._enabled_standards_cache[cache_key] = standards
88
+ logger.debug(f"Cached {len(standards)} enabled standards for {cache_key}")
89
+
90
+ return standards
91
+ except Exception as e:
92
+ # Check if this is the "not subscribed to AWS Security Hub" error
93
+ if hasattr(e, 'response') and isinstance(e.response, dict):
94
+ error = e.response.get('Error', {})
95
+ if error.get('Code') == 'InvalidAccessException' and 'not subscribed to AWS Security Hub' in error.get('Message', ''):
96
+ # Return None specifically for this error to indicate Security Hub is not enabled
97
+ # Don't log this as an error since it's an expected condition we want to check for
98
+ logger.debug(f"Security Hub is not enabled in region {region}")
99
+ return None
100
+
101
+ # For other errors, log a warning instead of an error to avoid cluttering the build logs
102
+ logger.warning(f"Error getting enabled standards in {region}: {e}")
103
+ return []
104
+
105
+ def get_administrator_account(self, region: str) -> Dict[str, Any]:
106
+ """
107
+ Get Security Hub administrator account with caching.
108
+
109
+ Args:
110
+ region: AWS region name
111
+
112
+ Returns:
113
+ Administrator account information
114
+ """
115
+ account_id = self.account_id
116
+ if not account_id:
117
+ logger.warning("Could not determine account ID")
118
+ return {}
119
+
120
+ # Check cache first
121
+ cache_key = f"{account_id}:{region}"
122
+ if cache_key in self.__class__._admin_account_cache:
123
+ logger.debug(f"Using cached administrator account for {cache_key}")
124
+ return self.__class__._admin_account_cache[cache_key]
125
+
126
+ client = self.get_client(region)
127
+ if not client:
128
+ logger.warning(f"No SecurityHub client available for region {region}")
129
+ return {}
130
+
131
+ # Get administrator account from client
132
+ admin_account = client.get_administrator_account()
133
+
134
+ # Cache the results
135
+ self.__class__._admin_account_cache[cache_key] = admin_account
136
+ logger.debug(f"Cached administrator account for {cache_key}")
137
+
138
+ return admin_account
139
+
140
+ def get_organization_configuration(self, region: str) -> Dict[str, Any]:
141
+ """
142
+ Get Security Hub organization configuration with caching.
143
+
144
+ Args:
145
+ region: AWS region name
146
+
147
+ Returns:
148
+ Organization configuration
149
+ """
150
+ account_id = self.account_id
151
+ if not account_id:
152
+ logger.warning("Could not determine account ID")
153
+ return {}
154
+
155
+ # Check cache first
156
+ cache_key = f"{account_id}:{region}"
157
+ if cache_key in self.__class__._organization_configuration_cache:
158
+ logger.debug(f"Using cached organization configuration for {cache_key}")
159
+ return self.__class__._organization_configuration_cache[cache_key]
160
+
161
+ client = self.get_client(region)
162
+ if not client:
163
+ logger.warning(f"No SecurityHub client available for region {region}")
164
+ return {}
165
+
166
+ # Get organization configuration from client
167
+ org_config = client.describe_organization_configuration()
168
+
169
+ # Cache the results
170
+ self.__class__._organization_configuration_cache[cache_key] = org_config
171
+ logger.debug(f"Cached organization configuration for {cache_key}")
172
+
173
+ return org_config
174
+
175
+ def get_enabled_products_for_import(self, region: str) -> Optional[List[str]]:
176
+ """
177
+ Get enabled products for import with caching.
178
+
179
+ Args:
180
+ region: AWS region name
181
+
182
+ Returns:
183
+ List of enabled product ARNs, or None if Security Hub is not enabled
184
+ """
185
+ account_id = self.account_id
186
+ if not account_id:
187
+ logger.warning("Could not determine account ID")
188
+ return []
189
+
190
+ # Check cache first
191
+ cache_key = f"{account_id}:{region}"
192
+ if cache_key in self.__class__._product_integrations_cache:
193
+ logger.debug(f"Using cached product integrations for {cache_key}")
194
+ return self.__class__._product_integrations_cache[cache_key]
195
+
196
+ client = self.get_client(region)
197
+ if not client:
198
+ logger.warning(f"No SecurityHub client available for region {region}")
199
+ return []
200
+
201
+ # Get enabled products from client
202
+ products = client.list_enabled_products_for_import()
203
+
204
+ # Only cache if we got a valid response (not None)
205
+ if products is not None:
206
+ self.__class__._product_integrations_cache[cache_key] = products
207
+ logger.debug(f"Cached {len(products)} product integrations for {cache_key}")
208
+
209
+ return products
210
+
211
+ def get_delegated_administrators(self, region: str) -> List[Dict[str, Any]]:
212
+ """
213
+ Get SecurityHub delegated administrators with caching.
214
+
215
+ Args:
216
+ region: AWS region name
217
+
218
+ Returns:
219
+ List of delegated administrators
220
+ """
221
+ account_id = self.account_id
222
+ if not account_id:
223
+ logger.warning("Could not determine account ID")
224
+ return []
225
+
226
+ # Check cache first
227
+ cache_key = f"{account_id}:{region}"
228
+ if cache_key in self.__class__._delegated_admin_cache:
229
+ logger.debug(f"Using cached delegated administrators for {cache_key}")
230
+ return self.__class__._delegated_admin_cache[cache_key]
231
+
232
+ client = self.get_client(region)
233
+ if not client:
234
+ logger.warning(f"No SecurityHub client available for region {region}")
235
+ return []
236
+
237
+ # Get delegated administrators from client
238
+ delegated_admins = client.list_delegated_administrators()
239
+
240
+ # Cache the results
241
+ self.__class__._delegated_admin_cache[cache_key] = delegated_admins
242
+ logger.debug(f"Cached {len(delegated_admins)} delegated administrators for {cache_key}")
243
+
244
+ return delegated_admins
245
+
246
+ def get_organization_admin_accounts(self, region: str) -> List[Dict[str, Any]]:
247
+ """
248
+ Get Security Hub organization admin accounts with caching.
249
+
250
+ Args:
251
+ region: AWS region name
252
+
253
+ Returns:
254
+ List of organization admin accounts
255
+ """
256
+ account_id = self.account_id
257
+ if not account_id:
258
+ logger.warning("Could not determine account ID")
259
+ return []
260
+
261
+ # Check cache first
262
+ cache_key = f"{account_id}:{region}"
263
+ if cache_key in self.__class__._admin_account_cache:
264
+ logger.debug(f"Using cached organization admin accounts for {cache_key}")
265
+ return self.__class__._admin_account_cache[cache_key]
266
+
267
+ client = self.get_client(region)
268
+ if not client:
269
+ logger.warning(f"No SecurityHub client available for region {region}")
270
+ return []
271
+
272
+ # Get organization admin accounts from client
273
+ admin_accounts = client.list_organization_admin_accounts()
274
+
275
+ # Cache the results
276
+ self.__class__._admin_account_cache[cache_key] = admin_accounts
277
+ logger.debug(f"Cached {len(admin_accounts)} organization admin accounts for {cache_key}")
278
+
279
+ return admin_accounts
280
+
281
+ def get_organization_accounts(self, region: str) -> List[Dict[str, Any]]:
282
+ """
283
+ Get all organization accounts with caching.
284
+
285
+ Args:
286
+ region: AWS region name
287
+
288
+ Returns:
289
+ List of organization accounts
290
+ """
291
+ account_id = self.account_id
292
+ if not account_id:
293
+ logger.warning("Could not determine account ID")
294
+ return []
295
+
296
+ # Check cache first
297
+ cache_key = f"{account_id}:{region}"
298
+ if cache_key in self.__class__._organization_accounts_cache:
299
+ logger.debug(f"Using cached organization accounts for {cache_key}")
300
+ return self.__class__._organization_accounts_cache[cache_key]
301
+
302
+ client = self.get_client(region)
303
+ if not client:
304
+ logger.warning(f"No SecurityHub client available for region {region}")
305
+ return []
306
+
307
+ # Get organization accounts from client
308
+ accounts = client.list_organization_accounts()
309
+
310
+ # Cache the results
311
+ self.__class__._organization_accounts_cache[cache_key] = accounts
312
+ logger.debug(f"Cached {len(accounts)} organization accounts for {cache_key}")
313
+
314
+ return accounts
315
+
316
+ def get_security_hub_members(self, region: str) -> List[Dict[str, Any]]:
317
+ """
318
+ Get Security Hub member accounts with caching.
319
+
320
+ Args:
321
+ region: AWS region name
322
+
323
+ Returns:
324
+ List of Security Hub member accounts
325
+ """
326
+ account_id = self.account_id
327
+ if not account_id:
328
+ logger.warning("Could not determine account ID")
329
+ return []
330
+
331
+ # Check cache first
332
+ cache_key = f"{account_id}:{region}"
333
+ if cache_key in self.__class__._securityhub_members_cache:
334
+ logger.debug(f"Using cached Security Hub members for {cache_key}")
335
+ return self.__class__._securityhub_members_cache[cache_key]
336
+
337
+ client = self.get_client(region)
338
+ if not client:
339
+ logger.warning(f"No SecurityHub client available for region {region}")
340
+ return []
341
+
342
+ # Get Security Hub members from client
343
+ members = client.list_members()
344
+
345
+ # Cache the results
346
+ self.__class__._securityhub_members_cache[cache_key] = members
347
+ logger.debug(f"Cached {len(members)} Security Hub members for {cache_key}")
348
+
349
+ return members
@@ -0,0 +1 @@
1
+ """SecurityHub checks."""
@@ -0,0 +1,115 @@
1
+ """
2
+ SRA-SECURITYHUB-01: 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_01(SecurityHubCheck):
10
+ """Check if Security Hub enabled account level standards exist."""
11
+
12
+ def __init__(self):
13
+ """Initialize the check."""
14
+ super().__init__()
15
+ self.check_id = "SRA-SECURITYHUB-01"
16
+ self.check_name = "Security Hub enabled account level standards exist"
17
+ self.account_type = "application" # This check is for application accounts
18
+ self.severity = "HIGH"
19
+ self.description = (
20
+ "This check verifies whether a list of enabled Security Hub standards for the current AWS account exists."
21
+ )
22
+ self.check_logic = (
23
+ "Check evaluates if there are any standards enabled in the AWS account and AWS region. "
24
+ "Check PASS if there are any standards enabled."
25
+ )
26
+
27
+ def execute(self) -> List[Dict[str, Any]]:
28
+ """
29
+ Execute the check.
30
+
31
+ Returns:
32
+ List of findings
33
+ """
34
+ findings = []
35
+
36
+ # If no regions have Security Hub available, return a single failure
37
+ if not self._clients:
38
+ findings.append(
39
+ self.create_finding(
40
+ status="FAIL",
41
+ region="global",
42
+ resource_id="securityhub:global",
43
+ checked_value="Security Hub is enabled",
44
+ actual_value="Security Hub not available in any region",
45
+ remediation="Enable Security Hub in at least one region"
46
+ )
47
+ )
48
+ return findings
49
+
50
+ # Check each region where Security Hub is available
51
+ for region in self.regions:
52
+ # Get enabled standards for the current account in this region
53
+ enabled_standards = self.get_enabled_standards(region)
54
+
55
+ # If None is returned, Security Hub is not enabled
56
+ if enabled_standards is None:
57
+ findings.append(
58
+ self.create_finding(
59
+ status="FAIL",
60
+ region=region,
61
+ resource_id=f"securityhub:service/{self.account_id}",
62
+ checked_value="Security Hub is enabled",
63
+ actual_value=f"Security Hub is not enabled in region {region}",
64
+ remediation=(
65
+ "Enable Security Hub in this region. In the AWS console, navigate to Security Hub and enable the service. "
66
+ "Alternatively, use the AWS CLI command: "
67
+ f"aws securityhub enable-security-hub --region {region}"
68
+ )
69
+ )
70
+ )
71
+ continue
72
+
73
+ # Extract standard names for better reporting
74
+ standard_names = []
75
+ for standard in enabled_standards:
76
+ standard_arn = standard.get('StandardsArn', '')
77
+ # Extract the standard name from the ARN
78
+ if '/standards/' in standard_arn:
79
+ standard_name = standard_arn.split('/standards/')[1]
80
+ standard_names.append(standard_name)
81
+ else:
82
+ standard_names.append(standard_arn)
83
+
84
+ # Format the list of standards for reporting
85
+ standards_list = ', '.join(standard_names) if standard_names else "None"
86
+
87
+ if not enabled_standards:
88
+ findings.append(
89
+ self.create_finding(
90
+ status="FAIL",
91
+ region=region,
92
+ resource_id=f"securityhub:standards/{self.account_id}",
93
+ checked_value="Security Hub standards are enabled",
94
+ actual_value=f"Account {self.account_id} region {region} has no Security Hub standards enabled",
95
+ remediation=(
96
+ "Enable Security Hub standards for this account. In the Security Hub console, "
97
+ "navigate to Settings > Standards and enable the required standards. "
98
+ "Alternatively, use the AWS CLI command: "
99
+ f"aws securityhub batch-enable-standards --standards-subscription-requests 'StandardsArn=arn:aws:securityhub:{region}::standards/aws-foundational-security-best-practices/v/1.0.0' --region {region}"
100
+ )
101
+ )
102
+ )
103
+ else:
104
+ findings.append(
105
+ self.create_finding(
106
+ status="PASS",
107
+ region=region,
108
+ resource_id=f"securityhub:standards/{self.account_id}",
109
+ checked_value="Security Hub standards are enabled",
110
+ actual_value=f"Account {self.account_id} region {region} has the following standards enabled: {standards_list}",
111
+ remediation="No remediation needed"
112
+ )
113
+ )
114
+
115
+ return findings