You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Terraform中合并多文件的AWS Network Firewall stateful_rule

解决AWS Network Firewall规则组拆分规则文件的问题

直接在多个TF文件里写同名的stateful_rule块会被Terraform覆盖,这是因为Terraform对同类型块的处理逻辑是最后定义的覆盖之前的。要实现每个规则单独存文件再合并到同一个规则组,得换个思路——用动态块(dynamic block)结合变量列表的方式,或者用模块拆分规则,下面是具体实现:

方法一:本地变量+动态块快速实现

1. 编写单个规则文件

在项目里新建一个rules目录,每个规则单独存一个.tf文件,用locals定义规则内容:
比如rules/allow_http.tf:

locals {
  allow_http = {
    action = "PASS"
    header = {
      destination      = "10.0.0.0/24"
      destination_port = "80"
      direction        = "FORWARD"
      protocol         = "TCP"
      source           = "0.0.0.0/0"
      source_port      = "*"
    }
    rule_options = [
      {
        keyword = "sid"
        settings = ["1001"]
      }
    ]
  }
}

再比如rules/drop_https.tf:

locals {
  drop_https = {
    action = "DROP"
    header = {
      destination      = "192.168.1.0/24"
      destination_port = "443"
      direction        = "FORWARD"
      protocol         = "TCP"
      source           = "0.0.0.0/0"
      source_port      = "*"
    }
    rule_options = [
      {
        keyword = "sid"
        settings = ["1002"]
      }
    ]
  }
}

2. 收集规则并生成规则组

在根目录的main.tf里,把所有规则收集成列表,然后用dynamic "stateful_rule"块遍历列表生成所有规则:

# 把所有单个规则收集成一个列表
locals {
  all_stateful_rules = [local.allow_http, local.drop_https]
}

resource "aws_networkfirewall_rule_group" "my_rule_group" {
  name     = "my-stateful-rule-group"
  capacity = 100  # 根据规则数量调整容量
  type     = "STATEFUL"

  rule_group {
    rules_source {
      stateful_rules {
        # 动态生成每个stateful_rule块
        dynamic "stateful_rule" {
          for_each = local.all_stateful_rules
          content {
            action = stateful_rule.value.action

            header {
              destination      = stateful_rule.value.header.destination
              destination_port = stateful_rule.value.header.destination_port
              direction        = stateful_rule.value.header.direction
              protocol         = stateful_rule.value.header.protocol
              source           = stateful_rule.value.header.source
              source_port      = stateful_rule.value.header.source_port
            }

            # 动态生成rule_option块(如果规则有多个选项)
            dynamic "rule_option" {
              for_each = stateful_rule.value.rule_options
              content {
                keyword  = rule_option.value.keyword
                settings = rule_option.value.settings
              }
            }
          }
        }
      }
    }
  }

  tags = {
    Name = "MyStatefulRuleGroup"
  }
}

3. 新增规则的方式

要加新规则,只需要在rules目录下新建一个.tf文件,定义一个新的local规则,然后把它加到local.all_stateful_rules列表里就行,比如新增rules/allow_dns.tf后,修改列表:

locals {
  all_stateful_rules = [local.allow_http, local.drop_https, local.allow_dns]
}

方法二:Terraform模块拆分规则(适合大量规则)

如果规则数量很多,用模块的方式更易于维护,每个规则做成一个可复用的小模块:

1. 创建规则模块

新建modules/stateful-rule目录,包含以下文件:

  • variables.tf:定义规则的输入参数
variable "action" {
  type        = string
  description = "Action for the rule (PASS, DROP, ALERT)"
}

variable "header" {
  type = object({
    destination      = string
    destination_port = string
    direction        = string
    protocol         = string
    source           = string
    source_port      = string
  })
  description = "Header details for the stateful rule"
}

variable "rule_options" {
  type = list(object({
    keyword  = string
    settings = optional(list(string))
  }))
  description = "List of rule options (like sid, msg)"
}
  • outputs.tf:输出规则的完整结构
output "rule_definition" {
  type = object({
    action       = string
    header       = object({
      destination      = string
      destination_port = string
      direction        = string
      protocol         = string
      source           = string
      source_port      = string
    })
    rule_options = list(object({
      keyword  = string
      settings = optional(list(string))
    }))
  })
  value = {
    action       = var.action
    header       = var.header
    rule_options = var.rule_options
  }
}

2. 在根模块调用规则模块

在根目录的main.tf里,每个规则单独调用模块:

module "allow_http" {
  source = "./modules/stateful-rule"

  action = "PASS"
  header = {
    destination      = "10.0.0.0/24"
    destination_port = "80"
    direction        = "FORWARD"
    protocol         = "TCP"
    source           = "0.0.0.0/0"
    source_port      = "*"
  }
  rule_options = [
    {
      keyword = "sid"
      settings = ["1001"]
    }
  ]
}

module "drop_https" {
  source = "./modules/stateful-rule"

  action = "DROP"
  header = {
    destination      = "192.168.1.0/24"
    destination_port = "443"
    direction        = "FORWARD"
    protocol         = "TCP"
    source           = "0.0.0.0/0"
    source_port      = "*"
  }
  rule_options = [
    {
      keyword = "sid"
      settings = ["1002"]
    }
  ]
}

# 收集所有模块输出的规则
locals {
  all_stateful_rules = [module.allow_http.rule_definition, module.drop_https.rule_definition]
}

# 生成规则组,和方法一的动态块部分完全一样
resource "aws_networkfirewall_rule_group" "my_rule_group" {
  name     = "my-stateful-rule-group"
  capacity = 100
  type     = "STATEFUL"

  rule_group {
    rules_source {
      stateful_rules {
        dynamic "stateful_rule" {
          for_each = local.all_stateful_rules
          content {
            action = stateful_rule.value.action

            header {
              destination      = stateful_rule.value.header.destination
              destination_port = stateful_rule.value.header.destination_port
              direction        = stateful_rule.value.header.direction
              protocol         = stateful_rule.value.header.protocol
              source           = stateful_rule.value.header.source
              source_port      = stateful_rule.value.header.source_port
            }

            dynamic "rule_option" {
              for_each = stateful_rule.value.rule_options
              content {
                keyword  = rule_option.value.keyword
                settings = rule_option.value.settings
              }
            }
          }
        }
      }
    }
  }

  tags = {
    Name = "MyStatefulRuleGroup"
  }
}

这种方式下,新增规则只需要添加一个module块,不需要修改规则列表(如果用Terraform 0.14+,也可以用flatten([for m in modules : m.rule_definition])自动收集,但手动添加更清晰可控)。


内容的提问来源于stack exchange,提问作者Ariel Davidov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.26 15:33:13