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

Terraform如何传入两个for_each输出实现Azure子网与NSG关联

Azure Terraform 子网与NSG关联实现方案

问题场景

部署Azure资源时需要创建VNET、子网、NSG三类资源,已通过for_each元参数实现多子网、多NSG的批量创建,但无法通过azurerm_subnet_network_security_group_association资源完成子网与NSG的关联绑定。当前已将子网ID、NSG ID配置为map类型的模块输出,但未找到建立子网ID与对应NSG ID关联关系的实现方案。
匹配规则要求按资源名称前缀绑定:public_subnet关联public_nsg,private_subnet关联private_nsg,无对应NSG的子网跳过绑定。


现有配置代码

子模块 main.tf

resource "azurerm_virtual_network" "vnet" {
  name                = format("%s-%s-vnet", var.owner_custom, var.purpose_custom)
  location            = var.location
  resource_group_name = format("rg-%s-%s", var.owner_custom, var.purpose_custom)
  address_space       = var.address_space

}


resource "azurerm_subnet" "subnet" {
  for_each = var.subnets
  name = each.value["name"]
  address_prefixes = each.value["address_space"]
  resource_group_name = format("rg-%s-%s", var.owner_custom, var.purpose_custom)
  virtual_network_name = azurerm_virtual_network.vnet.name
}


resource "azurerm_network_security_group" "nsg" {
  for_each = var.nsg
  name = each.value["name"]
  location = var.location
  resource_group_name = format("rg-%s-%s", var.owner_custom, var.purpose_custom)
}


resource "azurerm_subnet_network_security_group_association" "nsg_association" {
  subnet_id = # 待补充
  network_security_group_id = # 待补充
}

子模块 variables.tf

variable "owner_custom" {
    description = "Short name of owner"
}

variable "purpose_custom" {
    description = "Custom purpose"
}
variable "location" {
  description = "Location where resource is to be created"
  
}
variable "address_space" {
  type = list
  description = "VNET CIDR Range"
}

variable "subnets" {
  description = "A map to create multiple subnets"
  type = map(object({
    name = string
    address_space = list(string)
  })) 
}

variable "nsg" {
  description = "A map of NSGs"
  type = map(object({
    name = string
  }))
  
}

子模块 output.tf

output "vnet_id" {
    value = azurerm_virtual_network.vnet.id
}

output "subnet_id" {
    value = tomap({
        for k, s in azurerm_subnet.subnet : k => s.id
    })
  
}

output "nsg_id" {
    value = tomap({
        for k,s in azurerm_network_security_group.nsg: k => s.id
    })
  
}

tfvars 变量赋值文件

#Referenced common across modules
owner_custom = "raghav"
purpose_custom = "demo"

#Referenced in resource-group module
owner = "test@test.com"
purpose = "test"
location = "australiaeast"
org = "org"

#Referenced in network module
address_space = ["10.10.0.0/21"]

subnets = {
    subnet1 = {
        name = "public_subnet"
        address_space = ["10.10.1.0/26"]
        }

    subnet2 = {
        name = "private_subnet"
        address_space = ["10.10.1.64/26"]
        }

    subnet3 = {
        name = "privatelink_subnet"
        address_space = ["10.10.1.128/26"]
        }
    
    subnet4 = {
        name = "AzureFirewallSubnet"
        address_space = ["10.10.1.192/26"]
        }
}

nsg = {
    public_nsg = {
        name = "public_nsg"
        }

    private_nsg = {
        name = "private_nsg"
        }
    }

实现代码

直接在子模块main.tf中添加本地值映射,替换原有空的关联资源块即可,不需要调整现有变量、输出和tfvars结构:

# 构造按NSG资源名称索引的映射表,方便名称匹配
locals {
  nsg_by_name = {
    for nsg_item in azurerm_network_security_group.nsg : nsg_item.name => nsg_item
  }
  # 筛选需要绑定NSG的子网:名称符合xxx_subnet格式、且存在对应xxx_nsg的才纳入关联范围
  subnet_nsg_bind_map = {
    for subnet_item in azurerm_subnet.subnet : subnet_item.name => subnet_item
    if can(regex("^(.*)_subnet$", subnet_item.name))
    && contains(keys(local.nsg_by_name), "${regex("^(.*)_subnet$", subnet_item.name)[1]}_nsg")
  }
}

resource "azurerm_subnet_network_security_group_association" "nsg_association" {
  for_each                  = local.subnet_nsg_bind_map
  subnet_id                 = each.value.id
  network_security_group_id = local.nsg_by_name["${regex("^(.*)_subnet$", each.value.name)[1]}_nsg"].id
}

逻辑说明

  • 按NSG实际资源名构造索引,不依赖tfvars中map的key值,适配当前tfvars中subnet key为subnet1/subnet2、NSG key为public_nsg/private_nsg的结构
  • 自动过滤不需要绑定NSG的子网:名称不符合xxx_subnet格式、或没有对应前缀NSG的子网(比如示例中的privatelink_subnet、AzureFirewallSubnet)会被直接跳过,不会触发资源不存在的报错
  • 如果后续调整命名规则,只需要修改正则匹配和名称拼接逻辑即可,不需要改动其他资源代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 06:03:37