Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically create multiple WAF rules with Terraform

I've got a piece of Terraform code that creates a Web ACL with a set of rules in AWS.

provider "aws" {
  region = "eu-west-2"
}

resource "aws_wafv2_web_acl" "foo" {
    name        = "foo"
    description = "foo"
    scope       = "REGIONAL"
    default_action {
        block {}
    }
    rule {
      name = "AWS-AWSManagedRulesLinuxRuleSet"
      priority = 0
      override_action {
        count {}
      }
      statement {
        managed_rule_group_statement {
          name = "AWS-AWSManagedRulesLinuxRuleSet"
          vendor_name = "AWS"
        }
      }
      visibility_config {
        cloudwatch_metrics_enabled = false 
        metric_name                 = "foo_name"
        sampled_requests_enabled   = false
      }
    }
    rule {
      name = "AWS-AWSManagedRulesSQLiRuleSet"
      priority = 1
      override_action {
        count {}
      }
      statement {
        managed_rule_group_statement {
          name = "AWS-AWSManagedRulesSQLiRuleSet"
          vendor_name = "AWS"
        }
      }
      visibility_config {
        cloudwatch_metrics_enabled = false
        metric_name                = "foo_name"
        sampled_requests_enabled   = false
      }
    }
    tags = {
      Tag1 = "Value1"
    }
    visibility_config {
      metric_name = "foo"
      sampled_requests_enabled = false
      cloudwatch_metrics_enabled = false
    }   
}

This works fine, but adding more rules means that my code starts to turn into somewhat of a monolith.

Is there a way to create multiple rules in Terraform using dynamic_blocks or for_each or something else, in a way that looks cleaner and dry?

like image 363
Hammed Avatar asked Oct 18 '25 01:10

Hammed


1 Answers

You use dynamic in combination with for_each like this:

Define a variable:

variable "rules" {
  type    = list
  default = [
    {
      name = "AWS-AWSManagedRulesLinuxRuleSet"
      priority = 0
      managed_rule_group_statement_name = "AWS-AWSManagedRulesLinuxRuleSet"
      managed_rule_group_statement_vendor_name = "AWS"
      metric_name = "foo_name"
    },
    {
      name = "AWS-AWSManagedRulesSQLiRuleSet"
      priority = 1
      managed_rule_group_statement_name = "AWS-AWSManagedRulesSQLiRuleSet"
      managed_rule_group_statement_vendor_name = "AWS"
      metric_name = "foo_name"
    }
  ]
}

Then use it in the resource:

dynamic "rule" {
  for_each = toset(var.rules)

  content {
    name = rule.value.name
    priority = rule.value.priority
    override_action {
      count {}
    }
    statement {
      managed_rule_group_statement {
        name = rule.value.managed_rule_group_statement_name
        vendor_name = rule.value.managed_rule_group_statement_vendor_name
      }
    }
    visibility_config {
      cloudwatch_metrics_enabled = false
      metric_name                = rule.value.metric_name
      sampled_requests_enabled   = false
    }
  }
}

(Note: Obviously this replaces your previous rule blocks. See also the documentation about Dynamic Blocks for more information.)

like image 115
yvesonline Avatar answered Oct 19 '25 22:10

yvesonline



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!