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,271 @@
1
+ """
2
+ Base class for Macie security checks.
3
+ """
4
+ from typing import List, Optional, Dict, Any
5
+ from sraverify.core.check import SecurityCheck
6
+ from sraverify.services.macie.client import MacieClient
7
+ from sraverify.core.logging import logger
8
+
9
+
10
+ class MacieCheck(SecurityCheck):
11
+ """Base class for all Macie security checks."""
12
+
13
+ # Class-level caches shared across all instances
14
+ _findings_publication_cache = {}
15
+ _export_configuration_cache = {}
16
+ _macie_delegated_admin_cache = {}
17
+ _macie_members_cache = {}
18
+ _org_members_cache = {}
19
+ _auto_enable_cache = {}
20
+
21
+ def __init__(self):
22
+ """Initialize Macie base check."""
23
+ super().__init__(
24
+ account_type="application", # Default, can be overridden in subclasses
25
+ service="Macie",
26
+ resource_type="AWS::Macie::Session"
27
+ )
28
+
29
+ def _setup_clients(self):
30
+ """Set up Macie clients for each region."""
31
+ # Clear existing clients
32
+ self._clients.clear()
33
+ # Set up new clients only if regions are initialized
34
+ if hasattr(self, 'regions') and self.regions:
35
+ for region in self.regions:
36
+ self._clients[region] = MacieClient(region, session=self.session)
37
+
38
+ def get_client(self, region: str) -> Optional[MacieClient]:
39
+ """
40
+ Get Macie client for a specific region.
41
+
42
+ Args:
43
+ region: AWS region name
44
+
45
+ Returns:
46
+ MacieClient for the region or None if not available
47
+ """
48
+ return self._clients.get(region)
49
+
50
+ def get_findings_publication_configuration(self, region: str) -> Dict[str, Any]:
51
+ """
52
+ Get the findings publication configuration for Macie with caching.
53
+
54
+ Args:
55
+ region: AWS region name
56
+
57
+ Returns:
58
+ Dictionary containing findings publication configuration
59
+ """
60
+ # Check cache first
61
+ account_id = self.account_id
62
+ cache_key = f"{account_id}:{region}"
63
+
64
+ if cache_key in self.__class__._findings_publication_cache:
65
+ logger.debug(f"Using cached Macie findings publication configuration for {region}")
66
+ return self.__class__._findings_publication_cache[cache_key]
67
+
68
+ client = self.get_client(region)
69
+ if not client:
70
+ logger.warning(f"No Macie client available for region {region}")
71
+ return {}
72
+
73
+ # Get findings publication configuration from client
74
+ config = client.get_findings_publication_configuration()
75
+
76
+ # Cache the result
77
+ self.__class__._findings_publication_cache[cache_key] = config
78
+ logger.debug(f"Cached Macie findings publication configuration for {region}")
79
+
80
+ return config
81
+
82
+ def get_classification_export_configuration(self, region: str) -> Dict[str, Any]:
83
+ """
84
+ Get the classification export configuration for Macie with caching.
85
+
86
+ Args:
87
+ region: AWS region name
88
+
89
+ Returns:
90
+ Dictionary containing classification export configuration
91
+ """
92
+ # Check cache first
93
+ account_id = self.account_id
94
+ cache_key = f"{account_id}:{region}"
95
+
96
+ if cache_key in self.__class__._export_configuration_cache:
97
+ logger.debug(f"Using cached Macie classification export configuration for {region}")
98
+ return self.__class__._export_configuration_cache[cache_key]
99
+
100
+ client = self.get_client(region)
101
+ if not client:
102
+ logger.warning(f"No Macie client available for region {region}")
103
+ return {}
104
+
105
+ # Get classification export configuration from client
106
+ config = client.get_classification_export_configuration()
107
+
108
+ # Cache the result
109
+ self.__class__._export_configuration_cache[cache_key] = config
110
+ logger.debug(f"Cached Macie classification export configuration for {region}")
111
+
112
+ return config
113
+
114
+ def get_macie_delegated_admin(self, region: str) -> List[Dict[str, Any]]:
115
+ """
116
+ Get the Macie delegated administrator with caching.
117
+
118
+ Args:
119
+ region: AWS region name
120
+
121
+ Returns:
122
+ List of delegated administrators
123
+ """
124
+ # Check cache first
125
+ account_id = self.account_id
126
+ cache_key = f"{account_id}:{region}"
127
+
128
+ if cache_key in self.__class__._macie_delegated_admin_cache:
129
+ logger.debug(f"Using cached Macie delegated administrator for {region}")
130
+ return self.__class__._macie_delegated_admin_cache[cache_key]
131
+
132
+ client = self.get_client(region)
133
+ if not client:
134
+ logger.warning(f"No Macie client available for region {region}")
135
+ return []
136
+
137
+ # Get delegated administrator from client
138
+ delegated_admin = client.list_delegated_administrators()
139
+
140
+ # Cache the result
141
+ self.__class__._macie_delegated_admin_cache[cache_key] = delegated_admin
142
+ logger.debug(f"Cached Macie delegated administrator for {region}")
143
+
144
+ return delegated_admin
145
+
146
+ def get_macie_members(self, region: str) -> List[Dict[str, Any]]:
147
+ """
148
+ Get Macie members with caching.
149
+
150
+ Args:
151
+ region: AWS region name
152
+
153
+ Returns:
154
+ List of Macie members
155
+ """
156
+ # Check cache first
157
+ account_id = self.account_id
158
+ cache_key = f"{account_id}:{region}"
159
+
160
+ if cache_key in self.__class__._macie_members_cache:
161
+ logger.debug(f"Using cached Macie members for {region}")
162
+ return self.__class__._macie_members_cache[cache_key]
163
+
164
+ client = self.get_client(region)
165
+ if not client:
166
+ logger.warning(f"No Macie client available for region {region}")
167
+ return []
168
+
169
+ # Get members from client
170
+ members = client.list_members()
171
+
172
+ # Cache the result
173
+ self.__class__._macie_members_cache[cache_key] = members
174
+ logger.debug(f"Cached {len(members)} Macie members for {region}")
175
+
176
+ return members
177
+
178
+ def get_organization_members(self, region: str) -> List[Dict[str, Any]]:
179
+ """
180
+ Get AWS Organization members with caching.
181
+
182
+ Args:
183
+ region: AWS region name
184
+
185
+ Returns:
186
+ List of AWS Organization members
187
+ """
188
+ # Check cache first
189
+ account_id = self.account_id
190
+ cache_key = f"{account_id}:{region}"
191
+
192
+ if cache_key in self.__class__._org_members_cache:
193
+ logger.debug(f"Using cached AWS Organization members for {region}")
194
+ return self.__class__._org_members_cache[cache_key]
195
+
196
+ client = self.get_client(region)
197
+ if not client:
198
+ logger.warning(f"No Macie client available for region {region}")
199
+ return []
200
+
201
+ # Get organization members from client
202
+ members = client.list_organization_accounts()
203
+
204
+ # Cache the result
205
+ self.__class__._org_members_cache[cache_key] = members
206
+ logger.debug(f"Cached {len(members)} AWS Organization members for {region}")
207
+
208
+ return members
209
+
210
+ def get_organization_configuration(self, region: str) -> Dict[str, Any]:
211
+ """
212
+ Get Macie organization configuration with caching.
213
+
214
+ Args:
215
+ region: AWS region name
216
+
217
+ Returns:
218
+ Dictionary containing Macie organization configuration
219
+ """
220
+ # Check cache first
221
+ account_id = self.account_id
222
+ cache_key = f"{account_id}:{region}"
223
+
224
+ if cache_key in self.__class__._auto_enable_cache:
225
+ logger.debug(f"Using cached Macie organization configuration for {region}")
226
+ return self.__class__._auto_enable_cache[cache_key]
227
+
228
+ client = self.get_client(region)
229
+ if not client:
230
+ logger.warning(f"No Macie client available for region {region}")
231
+ return {}
232
+
233
+ # Get organization configuration from client
234
+ config = client.describe_organization_configuration()
235
+
236
+ # Cache the result
237
+ self.__class__._auto_enable_cache[cache_key] = config
238
+ logger.debug(f"Cached Macie organization configuration for {region}")
239
+
240
+ return config
241
+ def get_macie_administrator_account(self, region: str) -> Dict[str, Any]:
242
+ """
243
+ Get the Macie administrator account with caching.
244
+
245
+ Args:
246
+ region: AWS region name
247
+
248
+ Returns:
249
+ Dictionary containing Macie administrator account information
250
+ """
251
+ # Check cache first
252
+ account_id = self.account_id
253
+ cache_key = f"{account_id}:{region}"
254
+
255
+ if cache_key in self.__class__._macie_delegated_admin_cache:
256
+ logger.debug(f"Using cached Macie administrator account for {region}")
257
+ return self.__class__._macie_delegated_admin_cache[cache_key]
258
+
259
+ client = self.get_client(region)
260
+ if not client:
261
+ logger.warning(f"No Macie client available for region {region}")
262
+ return {}
263
+
264
+ # Get administrator account from client
265
+ admin_account = client.get_administrator_account()
266
+
267
+ # Cache the result
268
+ self.__class__._macie_delegated_admin_cache[cache_key] = admin_account
269
+ logger.debug(f"Cached Macie administrator account for {region}")
270
+
271
+ return admin_account
@@ -0,0 +1 @@
1
+ """Macie security checks."""
@@ -0,0 +1,100 @@
1
+ """
2
+ SRA-MACIE-01: Macie publish policy findings to Security Hub is enabled.
3
+ """
4
+ from typing import List, Dict, Any
5
+ from sraverify.services.macie.base import MacieCheck
6
+ from sraverify.core.logging import logger
7
+
8
+
9
+ class SRA_MACIE_01(MacieCheck):
10
+ """Check if Macie publish policy findings to Security Hub is enabled."""
11
+
12
+ def __init__(self):
13
+ """Initialize the check."""
14
+ super().__init__()
15
+ self.check_id = "SRA-MACIE-01"
16
+ self.check_name = "Macie publish policy findings to Security Hub is enabled"
17
+ self.description = (
18
+ "This check verifies whether Macie is configured to publish new and updated policy findings to AWS Security Hub. "
19
+ "Policy findings denotes potential security or privacy issue with a S3 bucket."
20
+ )
21
+ self.severity = "HIGH"
22
+ self.account_type = "application"
23
+ self.check_logic = "Check validates macie2 get-findings-publication-configuration. Check PASS if 'publishPolicyFindings': true"
24
+ self.resource_type = "AWS::Macie::Session"
25
+
26
+ def execute(self) -> List[Dict[str, Any]]:
27
+ """
28
+ Execute the check.
29
+
30
+ Returns:
31
+ List of findings
32
+ """
33
+ findings = []
34
+
35
+ for region in self.regions:
36
+ # Get findings publication configuration using the base class method with caching
37
+ config = self.get_findings_publication_configuration(region)
38
+
39
+ # Check if the API call was successful
40
+ if not config:
41
+ findings.append(
42
+ self.create_finding(
43
+ status="FAIL",
44
+ region=region,
45
+ resource_id=f"macie2/{self.account_id}/{region}",
46
+ checked_value="publishPolicyFindings: true",
47
+ actual_value="Failed to retrieve Macie findings publication configuration",
48
+ remediation="Ensure Macie is enabled and you have the necessary permissions to call the Macie GetFindingsPublicationConfiguration API"
49
+ )
50
+ )
51
+ continue
52
+
53
+ # Check if Security Hub configuration exists
54
+ security_hub_config = config.get('securityHubConfiguration', {})
55
+ if not security_hub_config:
56
+ findings.append(
57
+ self.create_finding(
58
+ status="FAIL",
59
+ region=region,
60
+ resource_id=f"macie2/{self.account_id}/{region}",
61
+ checked_value="publishPolicyFindings: true",
62
+ actual_value="Security Hub configuration not found in Macie findings publication configuration",
63
+ remediation=(
64
+ f"Configure Macie to publish findings to Security Hub in region {region} using the AWS CLI command: "
65
+ f"aws macie2 put-findings-publication-configuration --security-hub-configuration publishPolicyFindings=true --region {region}"
66
+ )
67
+ )
68
+ )
69
+ continue
70
+
71
+ # Check if policy findings are published to Security Hub
72
+ publish_policy_findings = security_hub_config.get('publishPolicyFindings', False)
73
+
74
+ if publish_policy_findings:
75
+ findings.append(
76
+ self.create_finding(
77
+ status="PASS",
78
+ region=region,
79
+ resource_id=f"macie2/{self.account_id}/{region}",
80
+ checked_value="publishPolicyFindings: true",
81
+ actual_value=f"Macie is configured to publish policy findings to Security Hub in region {region}",
82
+ remediation="No remediation needed"
83
+ )
84
+ )
85
+ else:
86
+ findings.append(
87
+ self.create_finding(
88
+ status="FAIL",
89
+ region=region,
90
+ resource_id=f"macie2/{self.account_id}/{region}",
91
+ checked_value="publishPolicyFindings: true",
92
+ actual_value=f"Macie is not configured to publish policy findings to Security Hub in region {region}",
93
+ remediation=(
94
+ f"Configure Macie to publish policy findings to Security Hub in region {region} using the AWS CLI command: "
95
+ f"aws macie2 put-findings-publication-configuration --security-hub-configuration publishPolicyFindings=true --region {region}"
96
+ )
97
+ )
98
+ )
99
+
100
+ return findings
@@ -0,0 +1,102 @@
1
+ """
2
+ SRA-MACIE-02: Macie publish classification findings to Security Hub is enabled.
3
+ """
4
+ from typing import List, Dict, Any
5
+ from sraverify.services.macie.base import MacieCheck
6
+ from sraverify.core.logging import logger
7
+
8
+
9
+ class SRA_MACIE_02(MacieCheck):
10
+ """Check if Macie publish classification findings to Security Hub is enabled."""
11
+
12
+ def __init__(self):
13
+ """Initialize the check."""
14
+ super().__init__()
15
+ self.check_id = "SRA-MACIE-02"
16
+ self.check_name = "Macie publish classification findings to Security Hub is enabled"
17
+ self.description = (
18
+ "This check verifies whether Macie is configured to publish sensitive data findings to AWS Security Hub. "
19
+ "Sensitive data findings denotes potential sensitive data in as S3 object. Macie continually evaluates your "
20
+ "S3 bucket inventory and uses sampling techniques to identify and select representative S3 objects from your buckets. "
21
+ "Macie then retrieves and analyzes the selected objects, inspecting them for sensitive data."
22
+ )
23
+ self.severity = "HIGH"
24
+ self.account_type = "application"
25
+ self.check_logic = "Check validates macie2 get-findings-publication-configuration. Check PASS if 'publishClassificationFindings': true"
26
+ self.resource_type = "AWS::Macie::Session"
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
+ for region in self.regions:
38
+ # Get findings publication configuration using the base class method with caching
39
+ config = self.get_findings_publication_configuration(region)
40
+
41
+ # Check if the API call was successful
42
+ if not config:
43
+ findings.append(
44
+ self.create_finding(
45
+ status="FAIL",
46
+ region=region,
47
+ resource_id=f"macie2/{self.account_id}/{region}",
48
+ checked_value="publishClassificationFindings: true",
49
+ actual_value="Failed to retrieve Macie findings publication configuration",
50
+ remediation="Ensure Macie is enabled and you have the necessary permissions to call the Macie GetFindingsPublicationConfiguration API"
51
+ )
52
+ )
53
+ continue
54
+
55
+ # Check if Security Hub configuration exists
56
+ security_hub_config = config.get('securityHubConfiguration', {})
57
+ if not security_hub_config:
58
+ findings.append(
59
+ self.create_finding(
60
+ status="FAIL",
61
+ region=region,
62
+ resource_id=f"macie2/{self.account_id}/{region}",
63
+ checked_value="publishClassificationFindings: true",
64
+ actual_value="Security Hub configuration not found in Macie findings publication configuration",
65
+ remediation=(
66
+ f"Configure Macie to publish findings to Security Hub in region {region} using the AWS CLI command: "
67
+ f"aws macie2 put-findings-publication-configuration --security-hub-configuration publishClassificationFindings=true --region {region}"
68
+ )
69
+ )
70
+ )
71
+ continue
72
+
73
+ # Check if classification findings are published to Security Hub
74
+ publish_classification_findings = security_hub_config.get('publishClassificationFindings', False)
75
+
76
+ if publish_classification_findings:
77
+ findings.append(
78
+ self.create_finding(
79
+ status="PASS",
80
+ region=region,
81
+ resource_id=f"macie2/{self.account_id}/{region}",
82
+ checked_value="publishClassificationFindings: true",
83
+ actual_value=f"Macie is configured to publish classification findings to Security Hub in region {region}",
84
+ remediation="No remediation needed"
85
+ )
86
+ )
87
+ else:
88
+ findings.append(
89
+ self.create_finding(
90
+ status="FAIL",
91
+ region=region,
92
+ resource_id=f"macie2/{self.account_id}/{region}",
93
+ checked_value="publishClassificationFindings: true",
94
+ actual_value=f"Macie is not configured to publish classification findings to Security Hub in region {region}",
95
+ remediation=(
96
+ f"Configure Macie to publish classification findings to Security Hub in region {region} using the AWS CLI command: "
97
+ f"aws macie2 put-findings-publication-configuration --security-hub-configuration publishClassificationFindings=true --region {region}"
98
+ )
99
+ )
100
+ )
101
+
102
+ return findings
@@ -0,0 +1,152 @@
1
+ """
2
+ SRA-MACIE-03: Macie findings exported to a S3 bucket in Log Archive account are encrypted at rest.
3
+ """
4
+ from typing import List, Dict, Any
5
+ from sraverify.services.macie.base import MacieCheck
6
+ from sraverify.core.logging import logger
7
+
8
+
9
+ class SRA_MACIE_03(MacieCheck):
10
+ """Check if Macie findings are exported to a S3 bucket in Log Archive account."""
11
+
12
+ def __init__(self):
13
+ """Initialize the check."""
14
+ super().__init__()
15
+ self.check_id = "SRA-MACIE-03"
16
+ self.check_name = "Macie findings exported to a S3 bucket in Log Archive account are encrypted at rest"
17
+ self.description = (
18
+ "This check verifies whether all Macie findings are being exported to a S3 bucket within the Log Archive account. "
19
+ "Log Archive account is the central repository of all AWS Organization logs."
20
+ )
21
+ self.severity = "HIGH"
22
+ self.account_type = "application"
23
+ self.check_logic = (
24
+ "Check validates using get-classification-export-configuration if Macie is set to export findings to S3 AND "
25
+ "if the S3 bucket is in the log archive account validated by EITHER the bucket name containing OR the KMS key "
26
+ "arn containing the --log-archive account ID. If bucket account can't be validated to --log-archive FAIL with value of bucket."
27
+ )
28
+ self.resource_type = "AWS::Macie::Session"
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 if log archive accounts are provided
40
+ log_archive_accounts = []
41
+ if hasattr(self, '_log_archive_accounts') and self._log_archive_accounts:
42
+ log_archive_accounts = self._log_archive_accounts
43
+
44
+ if not log_archive_accounts:
45
+ for region in self.regions:
46
+ findings.append(
47
+ self.create_finding(
48
+ status="FAIL",
49
+ region=region,
50
+ resource_id=f"macie2/{self.account_id}/{region}",
51
+ checked_value="S3 bucket in Log Archive account",
52
+ actual_value="Log Archive account ID not provided",
53
+ remediation="Provide the Log Archive account IDs using --log-archive-account flag"
54
+ )
55
+ )
56
+ return findings
57
+
58
+ for region in self.regions:
59
+ # Get classification export configuration using the base class method with caching
60
+ export_config = self.get_classification_export_configuration(region)
61
+
62
+ # Check if the API call was successful
63
+ if not export_config:
64
+ findings.append(
65
+ self.create_finding(
66
+ status="FAIL",
67
+ region=region,
68
+ resource_id=f"macie2/{self.account_id}/{region}",
69
+ checked_value="S3 bucket in Log Archive account",
70
+ actual_value="Failed to retrieve Macie classification export configuration",
71
+ remediation="Ensure Macie is enabled and you have the necessary permissions to call the Macie GetClassificationExportConfiguration API"
72
+ )
73
+ )
74
+ continue
75
+
76
+ # Check if export configuration exists
77
+ configuration = export_config.get('configuration', {})
78
+ if not configuration:
79
+ findings.append(
80
+ self.create_finding(
81
+ status="FAIL",
82
+ region=region,
83
+ resource_id=f"macie2/{self.account_id}/{region}",
84
+ checked_value="S3 bucket in Log Archive account",
85
+ actual_value="Macie findings export configuration not found",
86
+ remediation=(
87
+ f"Configure Macie to export findings to a S3 bucket in the Log Archive account in region {region} using the AWS CLI command: "
88
+ f"aws macie2 put-classification-export-configuration --s3-destination bucketName=macie-findings-{log_archive_accounts[0]},kmsKeyArn=arn:aws:kms:{region}:{log_archive_accounts[0]}:key/your-key-id --region {region}"
89
+ )
90
+ )
91
+ )
92
+ continue
93
+
94
+ # Check if S3 destination exists
95
+ s3_destination = configuration.get('s3Destination', {})
96
+ if not s3_destination:
97
+ findings.append(
98
+ self.create_finding(
99
+ status="FAIL",
100
+ region=region,
101
+ resource_id=f"macie2/{self.account_id}/{region}",
102
+ checked_value="S3 bucket in Log Archive account",
103
+ actual_value="S3 destination not found in Macie findings export configuration",
104
+ remediation=(
105
+ f"Configure Macie to export findings to a S3 bucket in the Log Archive account in region {region} using the AWS CLI command: "
106
+ f"aws macie2 put-classification-export-configuration --s3-destination bucketName=macie-findings-{log_archive_accounts[0]},kmsKeyArn=arn:aws:kms:{region}:{log_archive_accounts[0]}:key/your-key-id --region {region}"
107
+ )
108
+ )
109
+ )
110
+ continue
111
+
112
+ # Get bucket name and KMS key ARN
113
+ bucket_name = s3_destination.get('bucketName', '')
114
+ kms_key_arn = s3_destination.get('kmsKeyArn', '')
115
+
116
+ # Check if bucket name or KMS key ARN contains log archive account ID
117
+ is_in_log_archive = False
118
+ log_archive_account_found = None
119
+
120
+ for log_archive_account in log_archive_accounts:
121
+ if log_archive_account in bucket_name or log_archive_account in kms_key_arn:
122
+ is_in_log_archive = True
123
+ log_archive_account_found = log_archive_account
124
+ break
125
+
126
+ if is_in_log_archive:
127
+ findings.append(
128
+ self.create_finding(
129
+ status="PASS",
130
+ region=region,
131
+ resource_id=f"macie2/{self.account_id}/{region}",
132
+ checked_value="S3 bucket in Log Archive account",
133
+ actual_value=f"Macie findings are exported to S3 bucket '{bucket_name}' in Log Archive account {log_archive_account_found} in region {region}",
134
+ remediation="No remediation needed"
135
+ )
136
+ )
137
+ else:
138
+ findings.append(
139
+ self.create_finding(
140
+ status="FAIL",
141
+ region=region,
142
+ resource_id=f"macie2/{self.account_id}/{region}",
143
+ checked_value="S3 bucket in Log Archive account",
144
+ actual_value=f"Macie findings are exported to S3 bucket '{bucket_name}' which is not in any of the specified Log Archive accounts {', '.join(log_archive_accounts)} in region {region}",
145
+ remediation=(
146
+ f"Configure Macie to export findings to a S3 bucket in the Log Archive account in region {region} using the AWS CLI command: "
147
+ f"aws macie2 put-classification-export-configuration --s3-destination bucketName=macie-findings-{log_archive_accounts[0]},kmsKeyArn=arn:aws:kms:{region}:{log_archive_accounts[0]}:key/your-key-id --region {region}"
148
+ )
149
+ )
150
+ )
151
+
152
+ return findings