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

如何为google-terraform-network创建的VPC动态设置默认防火墙规则

问题描述

我需要使用terraform-google-modules/network/google模块创建VPC网络,同时为firewall_rules参数配置用户自定义规则或默认防火墙规则。核心难点在于:默认规则的源范围需要限制为动态解析的本地IP,因此无法直接在variables.tf中设置默认值——以下写法会直接报错:

variable "rules" {
    description = "List of rule definitions"
    default     = [
        {
        name                    = "allow-ssh-ingress"
        direction               = "INGRESS"
        ranges                  = [format("%s/%s", data.external.my_ip_addr.result["internet_ip"], 32)]
// ...
        }
    ]
}

报错信息:

Error: Function calls not allowed

已尝试的无效解决方案

方法1:变量默认值设为null,使用try函数

变量定义:

variable "rules" {
    description = "List of rule definitions"
    default =    null
}

模块配置:

firewall_rules = try(var.rules, [{
  name                    = "allow-ssh-ingress"
  direction               = "INGRESS"
  ranges                  = [format("%s/%s", data.external.my_ip_addr.result["internet_ip"], 32)]
  allow = [{
    protocol = "tcp"
    ports    = ["22"]
  }]
  deny = []
}])

报错信息:

A null value cannot be used as the collection in a 'for' expression.

方法2:变量默认值设为null,使用三元运算符

模块配置:

firewall_rules = var.rules != null ? var.rules : [{
  name                    = "allow-ssh-ingress"
  direction               = "INGRESS"
  ranges                  = [format("%s/%s", data.external.my_ip_addr.result["internet_ip"], 32)]
  allow = [{
    protocol = "tcp"
    ports    = ["22"]
  }]
  deny = []
}]

报错信息:

The true and false result expressions must have consistent types. The 'true' value is list of object, but the 'false' value is tuple.

方法3:显式转换为列表

模块配置:

firewall_rules = var.rules != null ? var.rules : tolist([{
  name                    = "allow-ssh-ingress"
  direction               = "INGRESS"
  ranges                  = [format("%s/%s", data.external.my_ip_addr.result["internet_ip"], 32)]
  allow = [{
    protocol = "tcp"
    ports    = ["22"]
  }]
  deny = []
}])

报错信息:

The true and false result expressions must have consistent types. Mismatched list element types: Type mismatch for object attribute "allow": The 'true' value is list of object, but the 'false' value is tuple.

核心疑问

当用户未传入自定义规则时,如何为firewall_rules提供包含动态元素(如动态解析的本地IP)的默认值?

补充信息

rules变量完整定义:

variable "rules" {
    description = "List of rule definitions"
    default =    null
    type = list(object({
        name                    = string
        description             = optional(string)
        direction               = optional(string)
        priority                = optional(number)
        ranges                  = optional(list(string))
        source_tags             = optional(list(string))
        source_service_accounts = optional(list(string))
        target_tags             = optional(list(string))
        target_service_accounts = optional(list(string))
        allow = optional(list(object({
            protocol = string
            ports    = optional(list(string))
        })))
        deny = optional(list(object({
            protocol = string
            ports    = optional(list(string))
        })))
        log_config = optional(object({
            metadata = string
        }))
    }))
}

main.tf相关代码:

module "vpc" {
    source  = "terraform-google-modules/network/google"
    version = "~> 7.0"

    project_id   = var.project
    network_name = var.network_name
    routing_mode = "GLOBAL"

    subnets = [
        {
            subnet_name   = var.subnet_name
            subnet_ip     = var.subnet_ip
            subnet_region = var.region
        },
    ]

    firewall_rules = var.rules != null ? var.rules : tolist([{
      name                    = "allow-ssh-ingress"
      direction               = "INGRESS"
      ranges                  = [format("%s/%s", data.external.my_ip_addr.result["internet_ip"], 32)]
      allow = tolist([{
        protocol = "tcp"
        ports    = ["22"]
      }])
      deny = []
    }])
}

解决方案

问题根源是Terraform对类型匹配要求严格:默认规则的嵌套结构(比如allow字段)被解析为tuple,但变量定义要求的是list(object(...)),导致类型不兼容。解决思路是通过locals提前构建符合类型要求的默认规则,再结合三元运算符赋值。

步骤1:定义本地默认规则

在locals.tf中创建完全匹配变量类型的默认规则:

locals {
  default_firewall_rules = [
    {
      name                    = "allow-ssh-ingress"
      direction               = "INGRESS"
      ranges                  = [format("%s/32", data.external.my_ip_addr.result["internet_ip"])]
      allow = [
        {
          protocol = "tcp"
          ports    = ["22"]
        }
      ]
      deny = []
      # 显式声明所有可选字段为null,匹配变量的optional属性
      description             = null
      priority                = null
      source_tags             = null
      source_service_accounts = null
      target_tags             = null
      target_service_accounts = null
      log_config              = null
    }
  ]
}

步骤2:在模块中引用本地变量

修改main.tf中的firewall_rules赋值:

module "vpc" {
    source  = "terraform-google-modules/network/google"
    version = "~> 7.0"

    project_id   = var.project
    network_name = var.network_name
    routing_mode = "GLOBAL"

    subnets = [
        {
            subnet_name   = var.subnet_name
            subnet_ip     = var.subnet_ip
            subnet_region = var.region
        },
    ]

    firewall_rules = var.rules != null ? var.rules : local.default_firewall_rules
}

关键说明

  1. 类型一致性:通过显式声明所有可选字段为null,确保默认规则的结构完全匹配variable "rules"定义的list(object(...))类型,避免tuple与list的类型冲突。
  2. 动态值处理:locals块支持使用函数和数据源,完美解决动态IP无法直接写在变量默认值的问题。
  3. 兼容性:既保留用户自定义规则的灵活性,又确保默认规则符合模块的类型要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 21:24:55