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,37 @@
1
+ """
2
+ Logging configuration for SRA Verify.
3
+ """
4
+ import logging
5
+ import sys
6
+
7
+ # Create a logger
8
+ logger = logging.getLogger("sraverify")
9
+
10
+ # Create handlers
11
+ console_handler = logging.StreamHandler(sys.stdout)
12
+
13
+ # Create formatters
14
+ default_format = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
15
+ console_formatter = logging.Formatter(default_format)
16
+
17
+ # Add formatters to handlers
18
+ console_handler.setFormatter(console_formatter)
19
+
20
+ # Add handlers to logger
21
+ logger.addHandler(console_handler)
22
+
23
+ # Set default level
24
+ logger.setLevel(logging.INFO)
25
+
26
+ def configure_logging(debug=False):
27
+ """
28
+ Configure logging level based on debug flag.
29
+
30
+ Args:
31
+ debug: If True, set logging level to DEBUG, otherwise INFO
32
+ """
33
+ if debug:
34
+ logger.setLevel(logging.DEBUG)
35
+ logger.debug("Debug logging enabled")
36
+ else:
37
+ logger.setLevel(logging.INFO)
@@ -0,0 +1,47 @@
1
+ """
2
+ AWS session management.
3
+ """
4
+ from typing import Optional
5
+ import boto3
6
+
7
+
8
+ def get_session(region: Optional[str] = None, profile: Optional[str] = None,
9
+ role_arn: Optional[str] = None) -> boto3.Session:
10
+ """
11
+ Get AWS session with optional region, profile, and role.
12
+
13
+ Args:
14
+ region: AWS region name
15
+ profile: AWS profile name
16
+ role_arn: ARN of IAM role to assume
17
+
18
+ Returns:
19
+ AWS session
20
+
21
+ Raises:
22
+ Exception: If session creation fails
23
+ """
24
+ try:
25
+ # First create a session with the provided profile or default credentials
26
+ session = boto3.Session(region_name=region, profile_name=profile)
27
+
28
+ # If a role ARN is provided, assume that role
29
+ if role_arn:
30
+ sts_client = session.client('sts')
31
+ response = sts_client.assume_role(
32
+ RoleArn=role_arn,
33
+ RoleSessionName='sraverify-session'
34
+ )
35
+
36
+ # Create a new session with the assumed role credentials
37
+ credentials = response['Credentials']
38
+ return boto3.Session(
39
+ aws_access_key_id=credentials['AccessKeyId'],
40
+ aws_secret_access_key=credentials['SecretAccessKey'],
41
+ aws_session_token=credentials['SessionToken'],
42
+ region_name=region
43
+ )
44
+
45
+ return session
46
+ except Exception as e:
47
+ raise Exception(f"Failed to create AWS session: {str(e)}")
@@ -0,0 +1,4 @@
1
+ """
2
+ SRAVerify library package
3
+ """
4
+ from . import outputs
@@ -0,0 +1,37 @@
1
+ # sraverify/lib/audit_info.py
2
+ from typing import List, Optional
3
+ import boto3
4
+ from .session import get_session
5
+ from .regions import validate_regions
6
+ from .org_mgmt_checker import OrgMgmtChecker
7
+
8
+ class AuditInfo:
9
+ """Class to hold audit context information"""
10
+ def __init__(self,
11
+ regions: Optional[List[str]] = None,
12
+ profile: Optional[str] = None,
13
+ session: Optional[boto3.Session] = None):
14
+ self.session = session or get_session(profile=profile)
15
+ self.regions = self._initialize_regions(regions)
16
+ self.profile = profile
17
+ self.account_id = self._get_account_id()
18
+ self.org_checker = OrgMgmtChecker()
19
+ if session:
20
+ self.org_checker.initialize(session)
21
+
22
+ def _initialize_regions(self, specified_regions: Optional[List[str]] = None) -> List[str]:
23
+ """Initialize and validate regions"""
24
+ return validate_regions(specified_regions, self.session)
25
+
26
+ def _get_account_id(self) -> str:
27
+ """Get AWS account ID"""
28
+ try:
29
+ return self.session.client('sts').get_caller_identity()['Account']
30
+ except Exception as e:
31
+ raise Exception(f"Failed to get AWS account ID: {str(e)}")
32
+
33
+ def get_regional_session(self, region: str) -> boto3.Session:
34
+ """Get a session for a specific region"""
35
+ if region not in self.regions:
36
+ raise ValueError(f"Region {region} is not in the list of validated regions")
37
+ return get_session(region=region, profile=self.profile)
@@ -0,0 +1,42 @@
1
+ from colorama import Fore, Style
2
+ import datetime
3
+ import os
4
+ import boto3
5
+
6
+ def print_banner(profile: str, region: str, session: boto3.Session = None):
7
+ """Print the SRAVerify banner and initial execution information."""
8
+ # ASCII art banner with version
9
+ print(f"""
10
+ _____ _____ ___ ___ _ __
11
+ / ____| __ \ /\ \ \ / / (_)/ _|
12
+ | (___ | |__) | / \ \ \ / /__ _ __ _| |_ _ _
13
+ \___ \| _ / / /\ \ \ v / _ \| '__| | _| | | |
14
+ ____) | | \ \ / ____ \ \ / __/| | | | | | |_| |
15
+ |_____/|_| \_\/_/ \_\ \___/ \___||_| |_|_| \__, |
16
+ __/ |
17
+ |___/ {Fore.BLUE}
18
+ the security architecture verifier tool{Style.RESET_ALL}
19
+ """)
20
+
21
+ print(f"{Fore.YELLOW}Date: {datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}{Style.RESET_ALL}\n")
22
+
23
+ # Print AWS credentials information
24
+ print("-> Using the AWS credentials below:")
25
+ print(f" · AWS-CLI Profile: {profile}")
26
+ print(f" · AWS Region: {region}")
27
+
28
+ if session:
29
+ try:
30
+ sts = session.client('sts')
31
+ caller_identity = sts.get_caller_identity()
32
+ print(f" · AWS Account: {caller_identity['Account']}")
33
+ print(f" · User Id: {caller_identity['UserId']}")
34
+ print(f" · Caller Identity ARN: {caller_identity['Arn']}")
35
+ except Exception as e:
36
+ print(f" · Unable to retrieve identity information: {str(e)}")
37
+
38
+ print("\n-> Using the following configuration:")
39
+ config_dir = os.path.join(os.path.dirname(__file__), "..", "config")
40
+ print(f" · Config File: {os.path.join(config_dir, 'config.yaml')}")
41
+ print(f" · Mutelist File: {os.path.join(config_dir, 'mutelist.yaml')}")
42
+ print(" · Scanning unused services and resources: False\n")
@@ -0,0 +1,80 @@
1
+ # sraverify/lib/check_loader.py
2
+
3
+ import os
4
+ import importlib.util
5
+ from typing import List, Type, Dict
6
+ from sraverify.checks import SecurityCheck
7
+
8
+ def discover_checks(check_type: str = "all", debug: bool = False, security_ou_name: str = None) -> List[Type[SecurityCheck]]:
9
+ """
10
+ Discover and load all security check classes.
11
+
12
+ Args:
13
+ check_type: Type of check to run ("all", "account" or "organization")
14
+ debug: Whether to print debug information
15
+ security_ou_name: Optional name of security OU to search for
16
+
17
+ Returns:
18
+ List of security check classes
19
+ """
20
+ check_classes = []
21
+ checks_dir = os.path.join(os.path.dirname(__file__), '..', 'checks')
22
+
23
+ # Keep track of loaded check IDs to avoid duplicates
24
+ loaded_check_ids = set()
25
+
26
+ for root, _, files in os.walk(checks_dir):
27
+ for file in files:
28
+ if file.endswith('.py') and not file.startswith('__'):
29
+ file_path = os.path.join(root, file)
30
+
31
+ try:
32
+ # Import the module
33
+ spec = importlib.util.spec_from_file_location(
34
+ f"sraverify.checks.{file[:-3]}",
35
+ file_path
36
+ )
37
+ if spec and spec.loader:
38
+ module = importlib.util.module_from_spec(spec)
39
+ spec.loader.exec_module(module)
40
+
41
+ # Find security check classes in the module
42
+ for item_name in dir(module):
43
+ item = getattr(module, item_name)
44
+ if (isinstance(item, type) and
45
+ issubclass(item, SecurityCheck) and
46
+ item != SecurityCheck):
47
+
48
+ # Create an instance to check its type
49
+ check_instance = item()
50
+
51
+ check_id = getattr(check_instance, 'check_id', None)
52
+ instance_check_type = getattr(check_instance, 'check_type', 'account')
53
+
54
+ # Skip if we've already loaded this check
55
+ if check_id in loaded_check_ids:
56
+ continue
57
+
58
+ # Filter based on check_type parameter
59
+ if check_type != "all" and instance_check_type != check_type:
60
+ if debug:
61
+ print(f"Debug: Skipping {check_id} (type: {instance_check_type}) - not matching requested type: {check_type}")
62
+ continue
63
+
64
+ loaded_check_ids.add(check_id)
65
+ check_classes.append(item)
66
+
67
+ if debug:
68
+ print(f"Debug: Loaded check {check_id} (type: {instance_check_type}) from {file}")
69
+
70
+ except Exception as e:
71
+ if debug:
72
+ print(f"Debug: Error loading {file}: {str(e)}")
73
+ continue
74
+
75
+ if debug:
76
+ print(f"\nDebug: Total checks loaded: {len(check_classes)}")
77
+ if check_type != "all":
78
+ print(f"Debug: Filtered for check_type: {check_type}")
79
+
80
+ return check_classes
@@ -0,0 +1,86 @@
1
+ """Organization Management Account Checker"""
2
+
3
+ from typing import Optional, Tuple
4
+ import boto3
5
+ from botocore.exceptions import ClientError
6
+ import logging
7
+
8
+ class OrgMgmtChecker:
9
+ """Singleton class to check and cache organization management account status"""
10
+
11
+ _instance = None
12
+ _initialized = False
13
+ _is_org_management = False
14
+ _management_account_id = None
15
+ _current_account_id = None
16
+ _error_message = None
17
+ _logger = logging.getLogger(__name__)
18
+
19
+ def __new__(cls):
20
+ if cls._instance is None:
21
+ cls._instance = super(OrgMgmtChecker, cls).__new__(cls)
22
+ return cls._instance
23
+
24
+ def __init__(self):
25
+ if not self._initialized:
26
+ self._initialized = True
27
+
28
+ def initialize(self, session: boto3.Session) -> None:
29
+ """Initialize the checker with a session"""
30
+ try:
31
+ # Get current account ID
32
+ sts_client = session.client('sts')
33
+ self._current_account_id = sts_client.get_caller_identity()['Account']
34
+
35
+ # Get organization details
36
+ org_client = session.client('organizations')
37
+ try:
38
+ org_details = org_client.describe_organization()['Organization']
39
+ self._management_account_id = org_details.get('MasterAccountId') # For older API versions
40
+ if not self._management_account_id:
41
+ self._management_account_id = org_details.get('ManagementAccountId') # For newer API versions
42
+
43
+ # Check if current account is management account
44
+ self._is_org_management = self._current_account_id == self._management_account_id
45
+ self._error_message = None
46
+
47
+ if self._logger.isEnabledFor(logging.DEBUG):
48
+ self._logger.debug(f"Current Account: {self._current_account_id}")
49
+ self._logger.debug(f"Management Account: {self._management_account_id}")
50
+ self._logger.debug(f"Is Management: {self._is_org_management}")
51
+
52
+ except ClientError as e:
53
+ error_code = e.response['Error']['Code']
54
+ if error_code == 'AWSOrganizationsNotInUseException':
55
+ self._error_message = "AWS Organizations is not in use for this account"
56
+ else:
57
+ self._error_message = f"Organizations API error: {str(e)}"
58
+ self._is_org_management = False
59
+ self._management_account_id = None
60
+
61
+ except Exception as e:
62
+ self._error_message = str(e)
63
+ self._is_org_management = False
64
+ self._management_account_id = None
65
+ if self._logger.isEnabledFor(logging.DEBUG):
66
+ self._logger.debug(f"Error during initialization: {str(e)}")
67
+
68
+ def verify_org_management(self) -> Tuple[bool, Optional[str]]:
69
+ """
70
+ Verify if current account is organization management account
71
+ Returns: (is_management_account, error_message)
72
+ """
73
+ return self._is_org_management, self._error_message
74
+
75
+ def get_management_account_id(self) -> Optional[str]:
76
+ """Get the management account ID if available"""
77
+ return self._management_account_id
78
+
79
+ def get_current_account_id(self) -> Optional[str]:
80
+ """Get the current account ID"""
81
+ return self._current_account_id
82
+
83
+ @property
84
+ def is_initialized(self) -> bool:
85
+ """Check if the checker has been initialized"""
86
+ return self._initialized
@@ -0,0 +1,46 @@
1
+ """
2
+ Output handling for sraverify scan results
3
+ """
4
+ import csv
5
+ from typing import List, Dict
6
+
7
+ # Required fields as per developer guide
8
+ REQUIRED_FIELDS = [
9
+ 'CheckId',
10
+ 'Status',
11
+ 'Region',
12
+ 'Severity',
13
+ 'Title',
14
+ 'Description',
15
+ 'ResourceId',
16
+ 'ResourceType',
17
+ 'AccountId',
18
+ 'CheckedValue',
19
+ 'ActualValue',
20
+ 'Remediation',
21
+ 'Service',
22
+ 'CheckLogic',
23
+ 'CheckType'
24
+ ]
25
+
26
+ def write_csv_output(findings: List[Dict], output_file: str):
27
+ """
28
+ Write scan findings to a CSV file ensuring all required fields are present
29
+ """
30
+ # Always create the CSV file, even if there are no findings
31
+ if not findings:
32
+ findings = []
33
+
34
+ # Ensure each finding has all required fields
35
+ for finding in findings:
36
+ for field in REQUIRED_FIELDS:
37
+ if field not in finding:
38
+ finding[field] = '' # Add empty string for missing fields
39
+
40
+ with open(output_file, 'w', newline='') as csvfile:
41
+ writer = csv.DictWriter(csvfile, fieldnames=REQUIRED_FIELDS)
42
+ writer.writeheader()
43
+ for finding in findings:
44
+ # Only write the required fields, in the correct order
45
+ row = {field: finding.get(field, '') for field in REQUIRED_FIELDS}
46
+ writer.writerow(row)
@@ -0,0 +1,75 @@
1
+ import time
2
+ from typing import Optional
3
+
4
+ class ScanProgress:
5
+ SPINNER = ['/', '-', '\\', '|']
6
+
7
+ def __init__(self, total_checks: int):
8
+ """Initialize the progress tracker.
9
+
10
+ Args:
11
+ total_checks: The total number of checks to be performed
12
+
13
+ Raises:
14
+ ValueError: If total_checks is less than or equal to 0
15
+ """
16
+ if total_checks <= 0:
17
+ raise ValueError("total_checks must be greater than 0")
18
+ self.total_checks = total_checks
19
+ self.completed_checks = 0
20
+ self.start_time = time.time()
21
+ self.current_service: Optional[str] = None
22
+ self.spinner_index = 0
23
+ self.last_print_time = 0
24
+ self.print_interval = 0.1 # Update display every 0.1 seconds
25
+
26
+ @property
27
+ def progress(self) -> float:
28
+ """Calculate the progress percentage."""
29
+ return (self.completed_checks / self.total_checks * 100)
30
+
31
+ @property
32
+ def duration(self) -> str:
33
+ """Calculate the elapsed time in minutes:seconds format."""
34
+ elapsed = int(time.time() - self.start_time)
35
+ minutes = elapsed // 60
36
+ seconds = elapsed % 60
37
+ return f"{minutes}:{seconds:02d}"
38
+
39
+ def update(self, service: str):
40
+ """Update the current service being scanned."""
41
+ self.current_service = service
42
+ self.print_progress()
43
+
44
+ def increment(self):
45
+ """Increment the completed checks counter."""
46
+ self.completed_checks += 1
47
+ self.spinner_index = (self.spinner_index + 1) % len(self.SPINNER)
48
+ self.print_progress()
49
+
50
+ def print_progress(self):
51
+ """Print the current progress status with rate limiting."""
52
+ current_time = time.time()
53
+ # Only update display if enough time has passed since last update
54
+ if current_time - self.last_print_time >= self.print_interval:
55
+ self._do_print()
56
+ self.last_print_time = current_time
57
+
58
+ def _do_print(self):
59
+ """Actually perform the progress printing."""
60
+ spinner = self.SPINNER[self.spinner_index]
61
+
62
+ # Calculate the width of the progress bar (50 characters)
63
+ bar_width = 50
64
+ filled_length = int(self.progress / 100 * bar_width)
65
+ bar = '=' * filled_length + ' ' * (bar_width - filled_length)
66
+
67
+ # Format the progress bar with current status
68
+ print(f"\r-> Scanning {self.current_service} service |{bar}| {spinner} "
69
+ f"{self.completed_checks}/{self.total_checks} "
70
+ f"[{self.progress:.0f}%] in {self.duration}",
71
+ end="", flush=True)
72
+
73
+ def finish(self):
74
+ """Complete the progress display with a newline."""
75
+ print() # Print newline to finish the progress display
@@ -0,0 +1,27 @@
1
+ # sraverify/lib/regions.py
2
+ from typing import List, Optional
3
+ import boto3
4
+
5
+ def get_enabled_regions(session: boto3.Session) -> List[str]:
6
+ """Get all enabled regions in the AWS account"""
7
+ try:
8
+ ec2_client = session.client('ec2', region_name='us-east-1')
9
+ response = ec2_client.describe_regions(AllRegions=False)
10
+ return [region['RegionName'] for region in response['Regions']]
11
+ except Exception as e:
12
+ raise Exception(f"Failed to get enabled regions: {str(e)}")
13
+
14
+ def validate_regions(regions: List[str], session: boto3.Session) -> List[str]:
15
+ """Validate if specified regions are valid and enabled"""
16
+ try:
17
+ enabled_regions = set(get_enabled_regions(session))
18
+
19
+ if regions:
20
+ invalid_regions = set(regions) - enabled_regions
21
+ if invalid_regions:
22
+ raise ValueError(f"Invalid or disabled regions: {', '.join(invalid_regions)}")
23
+ return regions
24
+
25
+ return list(enabled_regions)
26
+ except Exception as e:
27
+ raise Exception(f"Failed to validate regions: {str(e)}")
@@ -0,0 +1,23 @@
1
+ # sraverify/lib/session.py
2
+ import boto3
3
+ from typing import Optional
4
+
5
+ def get_session(region: Optional[str] = None, profile: Optional[str] = None) -> boto3.Session:
6
+ """Get AWS session with optional region and profile"""
7
+ try:
8
+ return boto3.Session(region_name=region, profile_name=profile)
9
+ except Exception as e:
10
+ raise Exception(f"Failed to create AWS session: {str(e)}")
11
+
12
+ def get_regional_session(base_session: boto3.Session, region: str) -> boto3.Session:
13
+ """Create a new session for a specific region while maintaining credentials"""
14
+ try:
15
+ credentials = base_session.get_credentials()
16
+ return boto3.Session(
17
+ aws_access_key_id=credentials.access_key,
18
+ aws_secret_access_key=credentials.secret_key,
19
+ aws_session_token=credentials.token,
20
+ region_name=region
21
+ )
22
+ except Exception as e:
23
+ raise Exception(f"Failed to create regional session: {str(e)}")