123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- # trussworks/wafv2/aws has a basic WAF with the AWS Managed Ruleset
- # See https://registry.terraform.io/modules/trussworks/wafv2/aws/latest
- #
- # Attempted to add some sane defaults so we can customize as needed
- #
- # IMPORTANT NOTES:
- # An 'Allow' action stops processing immediately. Avoid them!
- # Goals:
- # - US IPs only - https://docs.aws.amazon.com/waf/latest/developerguide/waf-rule-statement-type-geo-match.html
- resource "aws_wafv2_ip_set" "blocked" {
- name = "blocked_ips"
- scope = "REGIONAL"
- ip_address_version = "IPV4"
- addresses = toset(concat(var.additional_blocked_ips, local.blocked_ips))
- }
- resource "aws_wafv2_ip_set" "allowed" {
- name = "allowed_ips"
- scope = "REGIONAL"
- ip_address_version = "IPV4"
- addresses = var.allowed_ips
- }
- resource "aws_wafv2_rule_group" "xdr_custom_rules" {
- name = "xdr_custom_rules"
- scope = "REGIONAL"
- capacity = 1
- # Note, there is visibilty config for the group and for the rule
- visibility_config {
- cloudwatch_metrics_enabled = true
- metric_name = "xdr_custom_rules"
- sampled_requests_enabled = true
- }
- rule {
- name = "Block_Nonpermitted_Countries"
- priority = 100
- action {
- block {}
- }
- statement {
- not_statement {
- statement {
- geo_match_statement {
- country_codes = [
- "US",
- "DE",
- ]
- }
- }
- }
- }
- visibility_config {
- cloudwatch_metrics_enabled = true
- metric_name = "Block_Nonpermitted_Countries"
- sampled_requests_enabled = true
- }
- }
- # Add additional custom rules here
- }
- module "wafv2" {
- source = "trussworks/wafv2/aws"
- version = "= 2.4.0"
- name = replace(var.fqdns[0], ".", "_")
- scope = "REGIONAL"
- alb_arn = var.resource_arn
- associate_alb = true
- default_action = "block" # Note: The final action is actually to 'allow', provided the host header is correct
- filtered_header_rule = {
- header_types = var.fqdns
- header_value = "host"
- priority = 900
- action = "allow"
- }
- # IP based rules are processed first.
- # If an IP is blocked, it is blocked no matter what.
- # If an IP is allowed, it is allowed only if it's not blocked, but no other WAF rules are processed.
- ip_sets_rule = [
- {
- name = "blocked_ips"
- action = "block"
- priority = 10
- ip_set_arn = aws_wafv2_ip_set.blocked.arn
- },
- {
- name = "allowed_ips"
- action = "allow"
- priority = 20
- ip_set_arn = aws_wafv2_ip_set.allowed.arn
- }
- ]
- # Custom Rules are defined above
- group_rules = [
- {
- name = aws_wafv2_rule_group.xdr_custom_rules.name
- arn = aws_wafv2_rule_group.xdr_custom_rules.arn
- priority = 100
- override_action = "none"
- excluded_rules = []
- }
- ]
- # 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
- ip_rate_based_rule = {
- name = "Rate_Limit"
- priority = 200
- limit = 900 # 900 requests per 5 minutes= 3 requests/second (sustained for 5 minutes)
- action = "block"
- }
- # AWS managed rulesets
- # Baseline was from trussworks/wafv2/aws, but copied here to be customized for our use and renumbered.
- managed_rules = [
- {
- "excluded_rules": [
- "SizeRestrictions_BODY" # Breaks too many things
- ],
- "name": "AWSManagedRulesCommonRuleSet",
- "override_action": "none",
- "priority": 510
- },
- {
- "excluded_rules": [],
- "name": "AWSManagedRulesAmazonIpReputationList",
- "override_action": "none",
- "priority": 520
- },
- {
- "excluded_rules": [],
- "name": "AWSManagedRulesKnownBadInputsRuleSet",
- "override_action": "none",
- "priority": 530
- },
- {
- "excluded_rules": [],
- "name": "AWSManagedRulesSQLiRuleSet",
- "override_action": "none",
- "priority": 540
- },
- {
- "excluded_rules": [],
- "name": "AWSManagedRulesLinuxRuleSet",
- "override_action": "none",
- "priority": 550
- },
- {
- "excluded_rules": [],
- "name": "AWSManagedRulesUnixRuleSet",
- "override_action": "none",
- "priority": 560
- }
- ]
- tags = var.tags
- }
- resource "aws_wafv2_web_acl_logging_configuration" "waf_logs" {
- log_destination_configs = [ "arn:${var.aws_partition}:firehose:${var.aws_region}:${var.aws_account_id}:deliverystream/aws-waf-logs-splunk" ]
- resource_arn = module.wafv2.web_acl_id
- # logging_filter {
- # default_behavior = "KEEP"
- #
- # filter {
- # behavior = "DROP"
- #
- # condition {
- # action_condition {
- # action = "COUNT"
- # }
- # }
- #
- # condition {
- # label_name_condition {
- # label_name = "awswaf:111122223333:rulegroup:testRules:LabelNameZ"
- # }
- # }
- #
- # requirement = "MEETS_ALL"
- # }
- #
- # filter {
- # behavior = "KEEP"
- #
- # condition {
- # action_condition {
- # action = "ALLOW"
- # }
- # }
- #
- # requirement = "MEETS_ANY"
- # }
- # }
- }
|