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,82 @@
1
+ from typing import Dict, List, Any
2
+ from sraverify.services.waf.base import WAFCheck
3
+
4
+ class SRA_WAF_02(WAFCheck):
5
+ def __init__(self):
6
+ super().__init__()
7
+ self.check_id = "SRA-WAF-02"
8
+ self.check_name = "Application Load Balancers should be associated with AWS WAF"
9
+ self.description = "Ensures that all Application Load Balancers are protected by AWS WAF web ACLs to filter malicious traffic"
10
+ self.severity = "HIGH"
11
+ self.check_logic = "Lists all Application Load Balancers and verifies each has a WAF web ACL associated"
12
+
13
+ def execute(self) -> List[Dict[str, Any]]:
14
+ for region in self.regions:
15
+ load_balancers_response = self.get_load_balancers(region)
16
+
17
+ if "Error" in load_balancers_response:
18
+ self.findings.append(self.create_finding(
19
+ status="ERROR",
20
+ region=region,
21
+ resource_id=None,
22
+ actual_value=load_balancers_response["Error"].get("Message", "Unknown error"),
23
+ remediation="Check IAM permissions for ELB and WAF API access"
24
+ ))
25
+ continue
26
+
27
+ load_balancers = load_balancers_response.get("LoadBalancers", [])
28
+
29
+ # Filter for Application Load Balancers only
30
+ albs = [lb for lb in load_balancers if lb.get("Type") == "application"]
31
+
32
+ if not albs:
33
+ self.findings.append(self.create_finding(
34
+ status="PASS",
35
+ region=region,
36
+ resource_id="No ALBs",
37
+ actual_value="No Application Load Balancers found",
38
+ remediation="No action needed"
39
+ ))
40
+ continue
41
+
42
+ for alb in albs:
43
+ alb_arn = alb.get("LoadBalancerArn")
44
+ alb_name = alb.get("LoadBalancerName")
45
+
46
+ client = self.get_client(region)
47
+ if not client:
48
+ continue
49
+
50
+ web_acl_response = client.get_web_acl_for_resource(alb_arn)
51
+
52
+ if "Error" in web_acl_response:
53
+ self.findings.append(self.create_finding(
54
+ status="ERROR",
55
+ region=region,
56
+ resource_id=alb_name,
57
+ actual_value=web_acl_response["Error"].get("Message", "Unknown error"),
58
+ remediation="Check IAM permissions for WAF API access"
59
+ ))
60
+ continue
61
+
62
+ web_acl = web_acl_response.get("WebACL")
63
+
64
+ if web_acl:
65
+ web_acl_name = web_acl.get("Name", "Unknown")
66
+ self.findings.append(self.create_finding(
67
+ status="PASS",
68
+ region=region,
69
+ resource_id=alb_name,
70
+ actual_value=f"WAF Web ACL associated: {web_acl_name}",
71
+ remediation="No action needed"
72
+ ))
73
+ else:
74
+ self.findings.append(self.create_finding(
75
+ status="FAIL",
76
+ region=region,
77
+ resource_id=alb_name,
78
+ actual_value="No WAF Web ACL associated",
79
+ remediation="Associate a WAF Web ACL with this Application Load Balancer using the AWS Console, CLI, or API"
80
+ ))
81
+
82
+ return self.findings
@@ -0,0 +1,123 @@
1
+ from typing import Dict, List, Any
2
+ from sraverify.services.waf.base import WAFCheck
3
+
4
+ class SRA_WAF_03(WAFCheck):
5
+ def __init__(self):
6
+ super().__init__()
7
+ self.resource_type = "AWS::ApiGateway::RestApi"
8
+ self.check_id = "SRA-WAF-03"
9
+ self.check_name = "API Gateway REST APIs should be associated with AWS WAF"
10
+ self.description = "Ensures that all API Gateway REST APIs are protected by AWS WAF web ACLs to filter malicious traffic"
11
+ self.severity = "HIGH"
12
+ self.check_logic = "Lists all API Gateway REST APIs and verifies each has a WAF web ACL associated"
13
+
14
+ def execute(self) -> List[Dict[str, Any]]:
15
+ for region in self.regions:
16
+ rest_apis_response = self.get_rest_apis(region)
17
+
18
+ if "Error" in rest_apis_response:
19
+ self.findings.append(self.create_finding(
20
+ status="ERROR",
21
+ region=region,
22
+ resource_id=None,
23
+ actual_value=rest_apis_response["Error"].get("Message", "Unknown error"),
24
+ remediation="Check IAM permissions for API Gateway and WAF API access"
25
+ ))
26
+ continue
27
+
28
+ rest_apis = rest_apis_response.get("items", [])
29
+
30
+ if not rest_apis:
31
+ self.findings.append(self.create_finding(
32
+ status="PASS",
33
+ region=region,
34
+ resource_id="No REST APIs",
35
+ actual_value="No API Gateway REST APIs found",
36
+ remediation="No action needed"
37
+ ))
38
+ continue
39
+
40
+ for api in rest_apis:
41
+ api_id = api.get("id")
42
+ api_name = api.get("name")
43
+
44
+ # Get all stages for this API
45
+ stages_response = self.get_stages(region, api_id)
46
+
47
+ if "Error" in stages_response:
48
+ self.findings.append(self.create_finding(
49
+ status="ERROR",
50
+ region=region,
51
+ resource_id=api_name or api_id,
52
+ actual_value=stages_response["Error"].get("Message", "Unknown error"),
53
+ remediation="Check IAM permissions for API Gateway access"
54
+ ))
55
+ continue
56
+
57
+ stages = stages_response.get("item", [])
58
+
59
+ if not stages:
60
+ self.findings.append(self.create_finding(
61
+ status="FAIL",
62
+ region=region,
63
+ resource_id=api_name or api_id,
64
+ actual_value="No stages deployed",
65
+ remediation="Deploy the API to a stage and associate a WAF Web ACL"
66
+ ))
67
+ continue
68
+
69
+ # Check each stage for WAF association
70
+ for stage in stages:
71
+ stage_name = stage.get("stageName")
72
+ resource_id = f"{api_name or api_id}/{stage_name}"
73
+
74
+ # Construct the API Gateway stage ARN for WAF association check
75
+ api_arn = f"arn:aws:apigateway:{region}::/restapis/{api_id}/stages/{stage_name}"
76
+
77
+ client = self.get_client(region)
78
+ if not client:
79
+ continue
80
+
81
+ web_acl_response = client.get_web_acl_for_resource(api_arn)
82
+
83
+ if "Error" in web_acl_response:
84
+ error_code = web_acl_response["Error"].get("Code")
85
+ if error_code == "AccessDeniedException":
86
+ self.findings.append(self.create_finding(
87
+ status="ERROR",
88
+ region=region,
89
+ resource_id=resource_id,
90
+ actual_value=web_acl_response["Error"].get("Message", "Access denied"),
91
+ remediation="Check IAM permissions for wafv2:GetWebACLForResource"
92
+ ))
93
+ else:
94
+ self.findings.append(self.create_finding(
95
+ status="FAIL",
96
+ region=region,
97
+ resource_id=resource_id,
98
+ actual_value="No WAF Web ACL associated",
99
+ remediation="Associate a WAF Web ACL with this API Gateway stage using the AWS Console, CLI, or API"
100
+ ))
101
+ continue
102
+
103
+ web_acl = web_acl_response.get("WebACL")
104
+
105
+ if web_acl:
106
+ web_acl_name = web_acl.get("Name", "Unknown")
107
+ self.findings.append(self.create_finding(
108
+ status="PASS",
109
+ region=region,
110
+ resource_id=resource_id,
111
+ actual_value=f"WAF Web ACL associated: {web_acl_name}",
112
+ remediation="No action needed"
113
+ ))
114
+ else:
115
+ self.findings.append(self.create_finding(
116
+ status="FAIL",
117
+ region=region,
118
+ resource_id=resource_id,
119
+ actual_value="No WAF Web ACL associated",
120
+ remediation="Associate a WAF Web ACL with this API Gateway stage using the AWS Console, CLI, or API"
121
+ ))
122
+
123
+ return self.findings
@@ -0,0 +1,94 @@
1
+ from typing import Dict, List, Any
2
+ from sraverify.services.waf.base import WAFCheck
3
+
4
+ class SRA_WAF_04(WAFCheck):
5
+ def __init__(self):
6
+ super().__init__()
7
+ self.resource_type = "AWS::AppSync::GraphQLApi"
8
+ self.check_id = "SRA-WAF-04"
9
+ self.check_name = "AppSync GraphQL APIs should be associated with AWS WAF"
10
+ self.description = "Ensures that all AppSync GraphQL APIs are protected by AWS WAF web ACLs to filter malicious traffic"
11
+ self.severity = "HIGH"
12
+ self.check_logic = "Lists all AppSync GraphQL APIs and verifies each has a WAF web ACL associated"
13
+
14
+ def execute(self) -> List[Dict[str, Any]]:
15
+ for region in self.regions:
16
+ graphql_apis_response = self.get_graphql_apis(region)
17
+
18
+ if "Error" in graphql_apis_response:
19
+ self.findings.append(self.create_finding(
20
+ status="ERROR",
21
+ region=region,
22
+ resource_id=None,
23
+ actual_value=graphql_apis_response["Error"].get("Message", "Unknown error"),
24
+ remediation="Check IAM permissions for AppSync and WAF API access"
25
+ ))
26
+ continue
27
+
28
+ graphql_apis = graphql_apis_response.get("graphqlApis", [])
29
+
30
+ if not graphql_apis:
31
+ self.findings.append(self.create_finding(
32
+ status="PASS",
33
+ region=region,
34
+ resource_id="No GraphQL APIs",
35
+ actual_value="No AppSync GraphQL APIs found",
36
+ remediation="No action needed"
37
+ ))
38
+ continue
39
+
40
+ for api in graphql_apis:
41
+ api_arn = api.get("arn")
42
+ api_name = api.get("name")
43
+ api_id = api.get("apiId")
44
+
45
+ # Check if WAF is already associated (wafWebAclArn field)
46
+ waf_web_acl_arn = api.get("wafWebAclArn")
47
+
48
+ if waf_web_acl_arn:
49
+ self.findings.append(self.create_finding(
50
+ status="PASS",
51
+ region=region,
52
+ resource_id=api_name or api_id,
53
+ actual_value=f"WAF Web ACL associated: {waf_web_acl_arn}",
54
+ remediation="No action needed"
55
+ ))
56
+ else:
57
+ # Double-check using WAF API
58
+ client = self.get_client(region)
59
+ if not client:
60
+ continue
61
+
62
+ web_acl_response = client.get_web_acl_for_resource(api_arn)
63
+
64
+ if "Error" in web_acl_response:
65
+ self.findings.append(self.create_finding(
66
+ status="FAIL",
67
+ region=region,
68
+ resource_id=api_name or api_id,
69
+ actual_value="No WAF Web ACL associated",
70
+ remediation="Associate a WAF Web ACL with this AppSync GraphQL API using the AWS Console, CLI, or API"
71
+ ))
72
+ continue
73
+
74
+ web_acl = web_acl_response.get("WebACL")
75
+
76
+ if web_acl:
77
+ web_acl_name = web_acl.get("Name", "Unknown")
78
+ self.findings.append(self.create_finding(
79
+ status="PASS",
80
+ region=region,
81
+ resource_id=api_name or api_id,
82
+ actual_value=f"WAF Web ACL associated: {web_acl_name}",
83
+ remediation="No action needed"
84
+ ))
85
+ else:
86
+ self.findings.append(self.create_finding(
87
+ status="FAIL",
88
+ region=region,
89
+ resource_id=api_name or api_id,
90
+ actual_value="No WAF Web ACL associated",
91
+ remediation="Associate a WAF Web ACL with this AppSync GraphQL API using the AWS Console, CLI, or API"
92
+ ))
93
+
94
+ return self.findings
@@ -0,0 +1,94 @@
1
+ from typing import Dict, List, Any
2
+ from sraverify.services.waf.base import WAFCheck
3
+
4
+ class SRA_WAF_05(WAFCheck):
5
+ def __init__(self):
6
+ super().__init__()
7
+ self.resource_type = "AWS::Cognito::UserPool"
8
+ self.check_id = "SRA-WAF-05"
9
+ self.check_name = "Cognito user pools should be associated with AWS WAF"
10
+ self.description = "Ensures that all Cognito user pools are protected by AWS WAF web ACLs to filter malicious traffic"
11
+ self.severity = "HIGH"
12
+ self.check_logic = "Lists all Cognito user pools and verifies each has a WAF web ACL associated"
13
+
14
+ def execute(self) -> List[Dict[str, Any]]:
15
+ for region in self.regions:
16
+ user_pools_response = self.get_user_pools(region)
17
+
18
+ if "Error" in user_pools_response:
19
+ self.findings.append(self.create_finding(
20
+ status="ERROR",
21
+ region=region,
22
+ resource_id=None,
23
+ actual_value=user_pools_response["Error"].get("Message", "Unknown error"),
24
+ remediation="Check IAM permissions for Cognito and WAF API access"
25
+ ))
26
+ continue
27
+
28
+ user_pools = user_pools_response.get("UserPools", [])
29
+
30
+ if not user_pools:
31
+ self.findings.append(self.create_finding(
32
+ status="PASS",
33
+ region=region,
34
+ resource_id="No user pools",
35
+ actual_value="No Cognito user pools found",
36
+ remediation="No action needed"
37
+ ))
38
+ continue
39
+
40
+ for pool in user_pools:
41
+ pool_id = pool.get("Id")
42
+ pool_name = pool.get("Name")
43
+
44
+ # Construct the Cognito user pool ARN for WAF association check
45
+ # Format: arn:partition:cognito-idp:region:account-id:userpool/user-pool-id
46
+ pool_arn = f"arn:aws:cognito-idp:{region}:{self.account_id}:userpool/{pool_id}"
47
+
48
+ client = self.get_client(region)
49
+ if not client:
50
+ continue
51
+
52
+ web_acl_response = client.get_web_acl_for_resource(pool_arn)
53
+
54
+ if "Error" in web_acl_response:
55
+ error_code = web_acl_response["Error"].get("Code")
56
+ if error_code == "AccessDeniedException":
57
+ self.findings.append(self.create_finding(
58
+ status="ERROR",
59
+ region=region,
60
+ resource_id=pool_name or pool_id,
61
+ actual_value=web_acl_response["Error"].get("Message", "Access denied"),
62
+ remediation="Check IAM permissions for wafv2:GetWebACLForResource"
63
+ ))
64
+ else:
65
+ self.findings.append(self.create_finding(
66
+ status="FAIL",
67
+ region=region,
68
+ resource_id=pool_name or pool_id,
69
+ actual_value="No WAF Web ACL associated",
70
+ remediation="Associate a WAF Web ACL with this Cognito user pool using the AWS Console, CLI, or API"
71
+ ))
72
+ continue
73
+
74
+ web_acl = web_acl_response.get("WebACL")
75
+
76
+ if web_acl:
77
+ web_acl_name = web_acl.get("Name", "Unknown")
78
+ self.findings.append(self.create_finding(
79
+ status="PASS",
80
+ region=region,
81
+ resource_id=pool_name or pool_id,
82
+ actual_value=f"WAF Web ACL associated: {web_acl_name}",
83
+ remediation="No action needed"
84
+ ))
85
+ else:
86
+ self.findings.append(self.create_finding(
87
+ status="FAIL",
88
+ region=region,
89
+ resource_id=pool_name or pool_id,
90
+ actual_value="No WAF Web ACL associated",
91
+ remediation="Associate a WAF Web ACL with this Cognito user pool using the AWS Console, CLI, or API"
92
+ ))
93
+
94
+ return self.findings
@@ -0,0 +1,91 @@
1
+ from typing import Dict, List, Any
2
+ from sraverify.services.waf.base import WAFCheck
3
+
4
+ class SRA_WAF_06(WAFCheck):
5
+ def __init__(self):
6
+ super().__init__()
7
+ self.resource_type = "AWS::AppRunner::Service"
8
+ self.check_id = "SRA-WAF-06"
9
+ self.check_name = "App Runner services should be associated with AWS WAF"
10
+ self.description = "Ensures that all App Runner services are protected by AWS WAF web ACLs to filter malicious traffic"
11
+ self.severity = "HIGH"
12
+ self.check_logic = "Lists all App Runner services and verifies each has a WAF web ACL associated"
13
+
14
+ def execute(self) -> List[Dict[str, Any]]:
15
+ for region in self.regions:
16
+ services_response = self.get_apprunner_services(region)
17
+
18
+ if "Error" in services_response:
19
+ self.findings.append(self.create_finding(
20
+ status="ERROR",
21
+ region=region,
22
+ resource_id=None,
23
+ actual_value=services_response["Error"].get("Message", "Unknown error"),
24
+ remediation="Check IAM permissions for App Runner and WAF API access"
25
+ ))
26
+ continue
27
+
28
+ services = services_response.get("ServiceSummaryList", [])
29
+
30
+ if not services:
31
+ self.findings.append(self.create_finding(
32
+ status="PASS",
33
+ region=region,
34
+ resource_id="No App Runner services",
35
+ actual_value="No App Runner services found",
36
+ remediation="No action needed"
37
+ ))
38
+ continue
39
+
40
+ for service in services:
41
+ service_arn = service.get("ServiceArn")
42
+ service_name = service.get("ServiceName")
43
+ service_id = service.get("ServiceId")
44
+
45
+ client = self.get_client(region)
46
+ if not client:
47
+ continue
48
+
49
+ web_acl_response = client.get_web_acl_for_resource(service_arn)
50
+
51
+ if "Error" in web_acl_response:
52
+ error_code = web_acl_response["Error"].get("Code")
53
+ if error_code == "AccessDeniedException":
54
+ self.findings.append(self.create_finding(
55
+ status="ERROR",
56
+ region=region,
57
+ resource_id=service_name or service_id,
58
+ actual_value=web_acl_response["Error"].get("Message", "Access denied"),
59
+ remediation="Check IAM permissions for wafv2:GetWebACLForResource and apprunner:DescribeWebAclForService"
60
+ ))
61
+ else:
62
+ self.findings.append(self.create_finding(
63
+ status="FAIL",
64
+ region=region,
65
+ resource_id=service_name or service_id,
66
+ actual_value="No WAF Web ACL associated",
67
+ remediation="Associate a WAF Web ACL with this App Runner service using the AWS Console, CLI, or API"
68
+ ))
69
+ continue
70
+
71
+ web_acl = web_acl_response.get("WebACL")
72
+
73
+ if web_acl:
74
+ web_acl_name = web_acl.get("Name", "Unknown")
75
+ self.findings.append(self.create_finding(
76
+ status="PASS",
77
+ region=region,
78
+ resource_id=service_name or service_id,
79
+ actual_value=f"WAF Web ACL associated: {web_acl_name}",
80
+ remediation="No action needed"
81
+ ))
82
+ else:
83
+ self.findings.append(self.create_finding(
84
+ status="FAIL",
85
+ region=region,
86
+ resource_id=service_name or service_id,
87
+ actual_value="No WAF Web ACL associated",
88
+ remediation="Associate a WAF Web ACL with this App Runner service using the AWS Console, CLI, or API"
89
+ ))
90
+
91
+ return self.findings
@@ -0,0 +1,94 @@
1
+ from typing import Dict, List, Any
2
+ from sraverify.services.waf.base import WAFCheck
3
+
4
+ class SRA_WAF_07(WAFCheck):
5
+ def __init__(self):
6
+ super().__init__()
7
+ self.resource_type = "AWS::EC2::VerifiedAccessInstance"
8
+ self.check_id = "SRA-WAF-07"
9
+ self.check_name = "Verified Access instances should be associated with AWS WAF"
10
+ self.description = "Ensures that all Verified Access instances are protected by AWS WAF web ACLs to filter malicious traffic"
11
+ self.severity = "HIGH"
12
+ self.check_logic = "Lists all Verified Access instances and verifies each has a WAF web ACL associated"
13
+
14
+ def execute(self) -> List[Dict[str, Any]]:
15
+ for region in self.regions:
16
+ instances_response = self.get_verified_access_instances(region)
17
+
18
+ if "Error" in instances_response:
19
+ self.findings.append(self.create_finding(
20
+ status="ERROR",
21
+ region=region,
22
+ resource_id=None,
23
+ actual_value=instances_response["Error"].get("Message", "Unknown error"),
24
+ remediation="Check IAM permissions for EC2 and WAF API access"
25
+ ))
26
+ continue
27
+
28
+ instances = instances_response.get("VerifiedAccessInstances", [])
29
+
30
+ if not instances:
31
+ self.findings.append(self.create_finding(
32
+ status="PASS",
33
+ region=region,
34
+ resource_id="No Verified Access instances",
35
+ actual_value="No Verified Access instances found",
36
+ remediation="No action needed"
37
+ ))
38
+ continue
39
+
40
+ for instance in instances:
41
+ instance_id = instance.get("VerifiedAccessInstanceId")
42
+ description = instance.get("Description", "")
43
+
44
+ # Construct the Verified Access instance ARN for WAF association check
45
+ # Format: arn:partition:ec2:region:account-id:verified-access-instance/instance-id
46
+ instance_arn = f"arn:aws:ec2:{region}:{self.account_id}:verified-access-instance/{instance_id}"
47
+
48
+ client = self.get_client(region)
49
+ if not client:
50
+ continue
51
+
52
+ web_acl_response = client.get_web_acl_for_resource(instance_arn)
53
+
54
+ if "Error" in web_acl_response:
55
+ error_code = web_acl_response["Error"].get("Code")
56
+ if error_code == "AccessDeniedException":
57
+ self.findings.append(self.create_finding(
58
+ status="ERROR",
59
+ region=region,
60
+ resource_id=instance_id,
61
+ actual_value=web_acl_response["Error"].get("Message", "Access denied"),
62
+ remediation="Check IAM permissions for wafv2:GetWebACLForResource and ec2:GetVerifiedAccessInstanceWebAcl"
63
+ ))
64
+ else:
65
+ self.findings.append(self.create_finding(
66
+ status="FAIL",
67
+ region=region,
68
+ resource_id=instance_id,
69
+ actual_value="No WAF Web ACL associated",
70
+ remediation="Associate a WAF Web ACL with this Verified Access instance using the AWS Console, CLI, or API"
71
+ ))
72
+ continue
73
+
74
+ web_acl = web_acl_response.get("WebACL")
75
+
76
+ if web_acl:
77
+ web_acl_name = web_acl.get("Name", "Unknown")
78
+ self.findings.append(self.create_finding(
79
+ status="PASS",
80
+ region=region,
81
+ resource_id=instance_id,
82
+ actual_value=f"WAF Web ACL associated: {web_acl_name}",
83
+ remediation="No action needed"
84
+ ))
85
+ else:
86
+ self.findings.append(self.create_finding(
87
+ status="FAIL",
88
+ region=region,
89
+ resource_id=instance_id,
90
+ actual_value="No WAF Web ACL associated",
91
+ remediation="Associate a WAF Web ACL with this Verified Access instance using the AWS Console, CLI, or API"
92
+ ))
93
+
94
+ return self.findings
@@ -0,0 +1,66 @@
1
+ from typing import Dict, List, Any
2
+ from sraverify.services.waf.base import WAFCheck
3
+
4
+ class SRA_WAF_08(WAFCheck):
5
+ def __init__(self):
6
+ super().__init__()
7
+ self.resource_type = "AWS::Amplify::App"
8
+ self.check_id = "SRA-WAF-08"
9
+ self.check_name = "Amplify applications should be associated with AWS WAF"
10
+ self.description = "Ensures that all Amplify applications are protected by AWS WAF web ACLs to filter malicious traffic"
11
+ self.severity = "HIGH"
12
+ self.check_logic = "Lists all Amplify applications and verifies each has a WAF web ACL associated"
13
+
14
+ def execute(self) -> List[Dict[str, Any]]:
15
+ for region in self.regions:
16
+ apps_response = self.get_amplify_apps(region)
17
+
18
+ if "Error" in apps_response:
19
+ self.findings.append(self.create_finding(
20
+ status="ERROR",
21
+ region=region,
22
+ resource_id=None,
23
+ actual_value=apps_response["Error"].get("Message", "Unknown error"),
24
+ remediation="Check IAM permissions for Amplify and WAF API access"
25
+ ))
26
+ continue
27
+
28
+ apps = apps_response.get("apps", [])
29
+
30
+ if not apps:
31
+ self.findings.append(self.create_finding(
32
+ status="PASS",
33
+ region=region,
34
+ resource_id="No Amplify apps",
35
+ actual_value="No Amplify applications found",
36
+ remediation="No action needed"
37
+ ))
38
+ continue
39
+
40
+ for app in apps:
41
+ app_id = app.get("appId")
42
+ app_name = app.get("name")
43
+ waf_config = app.get("wafConfiguration", {})
44
+
45
+ # Check WAF configuration from the app response
46
+ waf_status = waf_config.get("wafStatus")
47
+ web_acl_arn = waf_config.get("webAclArn")
48
+
49
+ if waf_status == "ENABLED" and web_acl_arn:
50
+ self.findings.append(self.create_finding(
51
+ status="PASS",
52
+ region=region,
53
+ resource_id=app_name or app_id,
54
+ actual_value=f"WAF Web ACL associated: {web_acl_arn}",
55
+ remediation="No action needed"
56
+ ))
57
+ else:
58
+ self.findings.append(self.create_finding(
59
+ status="FAIL",
60
+ region=region,
61
+ resource_id=app_name or app_id,
62
+ actual_value="No WAF Web ACL associated",
63
+ remediation="Associate a WAF Web ACL with this Amplify application using the AWS Console, CLI, or API"
64
+ ))
65
+
66
+ return self.findings