waf.tf 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. # trussworks/wafv2/aws has a basic WAF with the AWS Managed Ruleset
  2. # See https://registry.terraform.io/modules/trussworks/wafv2/aws/latest
  3. #
  4. # Attempted to add some sane defaults so we can customize as needed
  5. #
  6. # IMPORTANT NOTES:
  7. # An 'Allow' action stops processing immediately. Avoid them!
  8. # Goals:
  9. # - US IPs only - https://docs.aws.amazon.com/waf/latest/developerguide/waf-rule-statement-type-geo-match.html
  10. resource "aws_wafv2_ip_set" "blocked" {
  11. name = "blocked_ips"
  12. scope = "REGIONAL"
  13. ip_address_version = "IPV4"
  14. addresses = toset(concat(var.additional_blocked_ips, local.blocked_ips))
  15. }
  16. resource "aws_wafv2_ip_set" "allowed" {
  17. name = "allowed_ips"
  18. scope = "REGIONAL"
  19. ip_address_version = "IPV4"
  20. addresses = var.allowed_ips
  21. }
  22. resource "aws_wafv2_rule_group" "xdr_custom_rules" {
  23. name = "xdr_custom_rules"
  24. scope = "REGIONAL"
  25. capacity = 1
  26. # Note, there is visibilty config for the group and for the rule
  27. visibility_config {
  28. cloudwatch_metrics_enabled = true
  29. metric_name = "xdr_custom_rules"
  30. sampled_requests_enabled = true
  31. }
  32. rule {
  33. name = "Block_Nonpermitted_Countries"
  34. priority = 100
  35. action {
  36. block {}
  37. }
  38. statement {
  39. not_statement {
  40. statement {
  41. geo_match_statement {
  42. country_codes = [
  43. "US",
  44. "DE",
  45. ]
  46. }
  47. }
  48. }
  49. }
  50. visibility_config {
  51. cloudwatch_metrics_enabled = true
  52. metric_name = "Block_Nonpermitted_Countries"
  53. sampled_requests_enabled = true
  54. }
  55. }
  56. # Add additional custom rules here
  57. }
  58. module "wafv2" {
  59. source = "trussworks/wafv2/aws"
  60. version = "= 2.4.0"
  61. name = replace(var.fqdns[0], ".", "_")
  62. scope = "REGIONAL"
  63. alb_arn = var.resource_arn
  64. associate_alb = true
  65. default_action = "block" # Note: The final action is actually to 'allow', provided the host header is correct
  66. filtered_header_rule = {
  67. header_types = var.fqdns
  68. header_value = "host"
  69. priority = 900
  70. action = "allow"
  71. }
  72. # IP based rules are processed first.
  73. # If an IP is blocked, it is blocked no matter what.
  74. # If an IP is allowed, it is allowed only if it's not blocked, but no other WAF rules are processed.
  75. ip_sets_rule = [
  76. {
  77. name = "blocked_ips"
  78. action = "block"
  79. priority = 10
  80. ip_set_arn = aws_wafv2_ip_set.blocked.arn
  81. },
  82. {
  83. name = "allowed_ips"
  84. action = "allow"
  85. priority = 20
  86. ip_set_arn = aws_wafv2_ip_set.allowed.arn
  87. }
  88. ]
  89. # Custom Rules are defined above
  90. group_rules = [
  91. {
  92. name = aws_wafv2_rule_group.xdr_custom_rules.name
  93. arn = aws_wafv2_rule_group.xdr_custom_rules.arn
  94. priority = 100
  95. override_action = "none"
  96. excluded_rules = []
  97. }
  98. ]
  99. # A rate-based rule tracks the rate of requests for each originating IP address, and triggers the rule action when the rate exceeds a limit that you specify on the number of requests in any 5-minute time span
  100. # zscalar needs high rates
  101. ip_rate_based_rule = {
  102. name = "Rate_Limit"
  103. priority = 200
  104. limit = 3000 # 6000 requests per 5 minutes= 10 requests/second (sustained for 5 minutes)
  105. action = "block"
  106. }
  107. # AWS managed rulesets
  108. # Baseline was from trussworks/wafv2/aws, but copied here to be customized for our use and renumbered.
  109. managed_rules = [
  110. {
  111. "excluded_rules": [
  112. "SizeRestrictions_BODY" # Breaks too many things
  113. ],
  114. "name": "AWSManagedRulesCommonRuleSet",
  115. "override_action": "none",
  116. "priority": 510
  117. },
  118. {
  119. "excluded_rules": [],
  120. "name": "AWSManagedRulesAmazonIpReputationList",
  121. "override_action": "none",
  122. "priority": 520
  123. },
  124. {
  125. "excluded_rules": [],
  126. "name": "AWSManagedRulesKnownBadInputsRuleSet",
  127. "override_action": "none",
  128. "priority": 530
  129. },
  130. {
  131. "excluded_rules": [],
  132. "name": "AWSManagedRulesSQLiRuleSet",
  133. "override_action": "none",
  134. "priority": 540
  135. },
  136. {
  137. "excluded_rules": [],
  138. "name": "AWSManagedRulesLinuxRuleSet",
  139. "override_action": "none",
  140. "priority": 550
  141. },
  142. {
  143. "excluded_rules": [],
  144. "name": "AWSManagedRulesUnixRuleSet",
  145. "override_action": "none",
  146. "priority": 560
  147. }
  148. ]
  149. tags = var.tags
  150. }
  151. resource "aws_wafv2_web_acl_logging_configuration" "waf_logs" {
  152. log_destination_configs = [ "arn:${var.aws_partition}:firehose:${var.aws_region}:${var.aws_account_id}:deliverystream/aws-waf-logs-splunk" ]
  153. resource_arn = module.wafv2.web_acl_id
  154. # logging_filter {
  155. # default_behavior = "KEEP"
  156. #
  157. # filter {
  158. # behavior = "DROP"
  159. #
  160. # condition {
  161. # action_condition {
  162. # action = "COUNT"
  163. # }
  164. # }
  165. #
  166. # condition {
  167. # label_name_condition {
  168. # label_name = "awswaf:111122223333:rulegroup:testRules:LabelNameZ"
  169. # }
  170. # }
  171. #
  172. # requirement = "MEETS_ALL"
  173. # }
  174. #
  175. # filter {
  176. # behavior = "KEEP"
  177. #
  178. # condition {
  179. # action_condition {
  180. # action = "ALLOW"
  181. # }
  182. # }
  183. #
  184. # requirement = "MEETS_ANY"
  185. # }
  186. # }
  187. }