Terraform使用for_each创建VM模块时如何传递模块输出NSG至外部安全规则
问题根因
404报错和NSG是否正常创建无关,核心是两个引用错误:
- 你把模块引用路径当成普通字符串硬编码在了配置里:
network_security_group_name = "module.fico_app_vm.linux_vm_nsg"、source_address_prefixes = ["module.fico_web_vm.linux_vm_ips"]。只要内容套了双引号,Terraform就会把这串字符当成纯文本,直接传给Azure API当资源标识查询,Azure自然找不到名字为module.fico_app_vm.linux_vm_nsg的NSG。 - 你对
fico_app_vm模块使用了for_each循环,模块的所有输出都是和循环键一一对应的映射集合,不是单个标量值,不能直接引用module.fico_app_vm.linux_vm_nsg拿到具体的NSG名称。
修正步骤
1. 对齐模块内部的输出定义
你贴的模块内NSG资源定义名称是azurerm_network_security_group.network_security_group,但outputs.tf里引用的是azurerm_network_security_group.dwp_network_security_group,两者名称不匹配会导致模块输出为空,需要调整为和实际资源名一致的写法:
# linux_vm模块内的outputs.tf output "linux_vm_ips" { value = azurerm_network_interface.dwp_network_interface.private_ip_address } output "linux_vm_nsg" { # 修正为实际存在的资源引用 value = azurerm_network_security_group.network_security_group.name }
2. 重构外部安全规则的配置逻辑
不要写单个静态的安全规则资源,直接复用模块的循环逻辑,保证每个生成的NSG都能匹配到对应规则,同时去掉硬编码的字符串引用,改成真实的输出值调用:
# 替换原来写死的单条安全规则资源 resource "azurerm_network_security_rule" "fico-app-sr-80" { # 直接复用app VM模块的循环键,和每个NSG一一绑定 for_each = module.fico_app_vm # 规则名称带上每个VM的唯一标识,避免重名冲突 name = "nsr-${var.environment}-${var.directorate}-${var.business_unit}-${var.vm_identifier}${var.instance_number}-${each.key}-http80" priority = 100 direction = "Inbound" access = "Allow" protocol = "*" source_port_range = "*" destination_port_range = "80" # 遍历web模块的输出集合,拿到所有VM的私网IP,不要硬编码字符串 source_address_prefixes = values(module.fico_web_vm)[*].linux_vm_ips destination_address_prefix = "VirtualNetwork" resource_group_name = azurerm_resource_group.rg_fico_app.name # 直接引用每个循环对应的模块输出的NSG名称,不要写带模块路径的字符串 network_security_group_name = each.value.linux_vm_nsg }
关键注意事项
- 所有模块输出的引用都要写在表达式上下文中,不能套双引号硬编码。只有不带引号的
module.xxx.output_name写法,才会被Terraform解析成实际的输出值。 - 对使用了
for_each的模块,所有输出都是以循环传入的集合键为索引的map结构,必须通过each引用、values()、lookup()这类函数才能拿到具体的标量值,不能直接把整个输出属性当单个值使用。 - 安全规则的
for_each直接绑定对应的循环模块,能自动保证规则数量和NSG数量匹配,不会出现规则遗漏或者资源错位的问题。
内容的提问来源于stack exchange,提问作者Lucky7865
相关产品推荐
相关产品推荐

