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

Azure Terraform中能否用Dynamic块在VNet/子网内创建子网、路由表和NSG?

在Azure Terraform配置中使用Dynamic块管理子网、路由表和NSG

首先明确:不能在azurerm_virtual_network或azurerm_subnet资源块内部直接创建路由表(Route Table)或网络安全组(NSG)。因为这些是Azure独立资源,Terraform的AzureRM Provider要求它们以单独资源声明,而非嵌套在子网/VNet的资源块中。不过可以通过Dynamic块配合for_each批量创建子网,再将独立创建的路由表、NSG关联到子网。

你提供代码的问题点

你尝试在azurerm_subnet资源块内嵌套route_table块,这不符合AzureRM Provider的资源结构——azurerm_subnet并没有route_table这个嵌套配置项,正确做法是单独创建azurerm_route_table资源,再通过ID关联到子网。

正确实现示例

1. 变量定义

variable "resource_group_name" {
  type        = string
  description = "资源组名称"
}

variable "virtual_network_name" {
  type        = string
  description = "虚拟网络名称"
}

variable "vnet_address_space" {
  type        = list(string)
  description = "虚拟网络地址空间"
  default     = ["10.0.0.0/16"]
}

variable "subnets" {
  type = map(object({
    address_prefix                     = string
    private_endpoint_network_policies    = bool
    private_link_service_network_policies = bool
    service_endpoints                 = list(string)
    route_table_config = optional(object({
      name                       = string
      disable_bgp_route_propagation = bool
      routes = list(object({
        name             = string
        address_prefix    = string
        next_hop_type      = string
        next_hop_ip_address = optional(string)
      }))
    }))
    nsg_config = optional(object({
      name = string
      security_rules = list(object({
        name                       = string
        priority                   = number
        direction                  = string
        access                     = string
        protocol                   = string
        source_port_range          = string
        destination_port_range     = string
        source_address_prefix      = string
        destination_address_prefix = string
      }))
    }))
  }))
  description = "子网配置映射"
}

2. 创建虚拟网络

resource "azurerm_virtual_network" "main" {
  name                = var.virtual_network_name
  address_space       = var.vnet_address_space
  resource_group_name = var.resource_group_name
}

3. 批量创建网络安全组(NSG)

resource "azurerm_network_security_group" "subnet_nsgs" {
  for_each             = { for k, v in var.subnets : k => v if v.nsg_config != null }
  name                 = each.value.nsg_config.name
  resource_group_name  = var.resource_group_name

  dynamic "security_rule" {
    for_each = each.value.nsg_config.security_rules
    content {
      name                       = security_rule.value.name
      priority                   = security_rule.value.priority
      direction                  = security_rule.value.direction
      access                     = security_rule.value.access
      protocol                   = security_rule.value.protocol
      source_port_range          = security_rule.value.source_port_range
      destination_port_range     = security_rule.value.destination_port_range
      source_address_prefix      = security_rule.value.source_address_prefix
      destination_address_prefix = security_rule.value.destination_address_prefix
    }
  }
}

4. 批量创建路由表

resource "azurerm_route_table" "subnet_route_tables" {
  for_each             = { for k, v in var.subnets : k => v if v.route_table_config != null }
  name                 = each.value.route_table_config.name
  resource_group_name  = var.resource_group_name
  disable_bgp_route_propagation = each.value.route_table_config.disable_bgp_route_propagation

  dynamic "route" {
    for_each = each.value.route_table_config.routes
    content {
      name                = route.value.name
      address_prefix      = route.value.address_prefix
      next_hop_type       = route.value.next_hop_type
      next_hop_ip_address = route.value.next_hop_ip_address
    }
  }
}

5. 批量创建子网并关联NSG和路由表

resource "azurerm_subnet" "main" {
  for_each                                      = var.subnets
  name                                          = each.key
  resource_group_name                           = var.resource_group_name
  address_prefixes                              = [each.value.address_prefix]
  virtual_network_name                          = azurerm_virtual_network.main.name
  private_endpoint_network_policies_enabled     = each.value.private_endpoint_network_policies
  private_link_service_network_policies_enabled = each.value.private_link_service_network_policies
  service_endpoints                             = each.value.service_endpoints

  # 关联NSG(仅当子网配置了NSG时)
  network_security_group_id = try(azurerm_network_security_group.subnet_nsgs[each.key].id, null)

  # 关联路由表(仅当子网配置了路由表时)
  route_table_id = try(azurerm_route_table.subnet_route_tables[each.key].id, null)
}

6. 示例变量值

subnets = {
  "web-subnet" = {
    address_prefix                     = "10.0.1.0/24"
    private_endpoint_network_policies    = true
    private_link_service_network_policies = false
    service_endpoints                 = ["Microsoft.Storage"]
    route_table_config = {
      name                       = "web-route-table"
      disable_bgp_route_propagation = false
      routes = [
        {
          name             = "default-route"
          address_prefix    = "0.0.0.0/0"
          next_hop_type      = "Internet"
          next_hop_ip_address = null
        }
      ]
    }
    nsg_config = {
      name = "web-nsg"
      security_rules = [
        {
          name                       = "allow-http-in"
          priority                   = 100
          direction                  = "Inbound"
          access                     = "Allow"
          protocol                   = "Tcp"
          source_port_range          = "*"
          destination_port_range     = "80"
          source_address_prefix      = "*"
          destination_address_prefix = "*"
        }
      ]
    }
  }
  "db-subnet" = {
    address_prefix                     = "10.0.2.0/24"
    private_endpoint_network_policies    = true
    private_link_service_network_policies = true
    service_endpoints                 = []
    # 该子网不配置路由表和NSG
  }
}

关键说明

  • 资源独立性:NSG和路由表是Azure独立资源,必须单独声明对应的Terraform资源,不能嵌套在子网或VNet块内。
  • Dynamic块用途:Dynamic块用于在单个资源块内批量生成重复的嵌套结构(比如NSG的安全规则、路由表的路由条目),而非创建独立资源。
  • 关联逻辑:通过network_security_group_id和route_table_id字段将子网与对应的NSG、路由表绑定,使用try函数兼容部分子网未配置NSG/路由表的场景。

内容的提问来源于stack exchange,提问作者Mr.cool

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 11:08:28