基于复杂Map对象使用Terraform创建azurerm_virtual_network_gateway_connection的嵌套for_each循环实现问题
基于复杂Map对象使用Terraform创建azurerm_virtual_network_gateway_connection的嵌套for_each循环实现问题
看起来你已经走对了方向,只是在扁平化数据结构的时候没把本地网关的关联信息带进来,导致没法正确引用对应的azurerm_local_network_gateway实例。我来帮你梳理一下完整的实现步骤:
第一步:重构本地变量,生成带关联信息的扁平连接Map
你需要把每个连接和它所属的本地网关(lng)的key绑定在一起,同时过滤掉未启用的网关和连接,最终生成一个单一的扁平Map(而不是数组嵌套对象),这样才能给for_each使用。
修改你的本地变量定义:
locals { all_connections = merge([ # 遍历每个本地网关,只处理启用的 for lng_key, lng in var.local_network_gateways : if lng.enabled { # 遍历当前网关下的所有连接,只处理启用的 for conn in lng.connections : if conn.enabled # 生成唯一的键,格式为"网关名_连接名" "${lng_key}_${conn.name}" => { lng_key = lng_key # 保存所属本地网关的key,用于后续关联 connection = conn # 保存连接的完整配置 } } ]...) # 三个点是Terraform的展开操作符,把多个小Map合并成一个大Map }
这个本地变量最终会输出类似这样的结构(一个扁平的Map):
{ "vpn1_vpn1-connection1" = { "lng_key" = "vpn1" "connection" = { "connection_type" = "VNet2VNet" "enabled" = true "name" = "vpn1-connection1" "vpn_shared_key" = "somegibetrrish" # 其他连接属性... } }, "vpn1_vpn1-connection2" = { "lng_key" = "vpn1" "connection" = { "connection_type" = "IPsec" "enabled" = true "name" = "vpn1-connection2" "vpn_shared_key" = "somegiberrish" # 其他连接属性... } }, "vpn2_vpn2-connection1" = { "lng_key" = "vpn2" "connection" = { "connection_type" = "IPsec" "enabled" = true "name" = "vpn2-connection1" "vpn_shared_key" = "vpn2_somegibetrrish" # 其他连接属性... } } }
第二步:修改连接资源的for_each配置
现在你可以用这个扁平Map来创建连接资源,并且通过each.value.lng_key关联到正确的本地网关:
resource "azurerm_virtual_network_gateway_connection" "vng_connection" { # 使用我们生成的扁平连接Map作为for_each的数据源 for_each = local.all_connections name = each.value.connection.name location = var.location resource_group_name = var.resource_group_name # 连接类型从当前连接配置中取 type = each.value.connection.connection_type # 关联到你的虚拟网络网关(这里假设你只有一个,所以用[0].id,如果是多个需要调整) virtual_network_gateway_id = azurerm_virtual_network_gateway.vpn[0].id # 通过lng_key关联到对应的本地网关实例 local_network_gateway_id = azurerm_local_network_gateway.lng_prod[each.value.lng_key].id # 共享密钥从连接配置中取 shared_key = each.value.connection.vpn_shared_key # 以下是固定或可选配置,根据你的需求调整,注意处理可能的null值 connection_protocol = "IKEv2" dpd_timeout_seconds = each.value.connection.dpd_timeout_seconds ?? 30 enable_bgp = each.value.connection.vngc_enable_bgp ?? false express_route_gateway_bypass = each.value.connection.vngc_express_route_gateway_bypass ?? false local_azure_ip_address_enabled = each.value.connection.vngc_local_azure_ip_address_enabled ?? false use_policy_based_traffic_selectors = each.value.connection.vngc_use_policy_based_traffic_selectors ?? false routing_weight = 0 # 使用dynamic块处理IPsec策略,避免部分连接没有该配置时出错 dynamic "ipsec_policy" { for_each = each.value.connection.ipsec_policy != null ? [each.value.connection.ipsec_policy] : [] content { dh_group = ipsec_policy.value.dh_group ike_encryption = ipsec_policy.value.ike_encryption ike_integrity = ipsec_policy.value.ike_integrity ipsec_encryption = ipsec_policy.value.ipsec_encryption ipsec_integrity = ipsec_policy.value.ipsec_integrity pfs_group = ipsec_policy.value.pfs_group sa_datasize = ipsec_policy.value.sa_datasize sa_lifetime = ipsec_policy.value.sa_lifetime } } # 标签从连接配置中取 tags = { software = each.value.connection.software environment = each.value.connection.environment customer = each.value.connection.customer special_purpose = each.value.connection.special_purpose } }
关键说明
- 为什么用merge和展开操作符?:你的原始flatten生成的是数组嵌套对象,而
for_each要求是Map或Set类型。通过merge([...])...可以把多个小Map合并成一个大的扁平Map,每个连接都有唯一的键,符合for_each的要求。 - lng_key的作用:保存每个连接所属的本地网关key,这样就能精准引用
azurerm_local_network_gateway.lng_prod中对应的实例,解决了你之前的关联问题。 - 动态块处理IPsec策略:如果部分连接没有配置IPsec策略,
dynamic块会自动跳过,避免Terraform报错,提升配置的灵活性。
这样配置后,Terraform会自动为你创建3个符合要求的azurerm_virtual_network_gateway_connection资源,每个都关联到正确的本地网关。
备注:内容来源于stack exchange,提问作者gbaii
相关产品推荐
相关产品推荐

