如何在Terraform中传递for_each创建的资源属性至其他资源?
解决Terraform批量创建Azure Bastion Host时的资源引用问题
你的核心问题是:通过for_each批量创建的子网和公网IP是资源集合(map/set类型),而非单个资源,直接调用.id会触发Terraform错误,必须通过对应的键来索引到集合中的具体资源实例。
关键前提确认
确保以下变量的元素/键完全对应(比如都以Azure区域名称作为标识):
var.bastion_subnet:建议是以区域名为key的map(比如{"eastus" = {...}, "westus" = {...}}),这样每个区域对应一个Bastion子网var.public_ip_location:包含的区域名和var.bastion_subnet的key一致var.location_list:包含的区域名和前两者完全匹配
修改后的Bastion Host配置
resource "azurerm_bastion_host" "bastion" { for_each = toset(var.location_list) name = "bastion-${each.value}" location = each.value resource_group_name = azurerm_resource_group.rg.name ip_configuration { name = "configuration" # 通过each.key(当前区域名)索引到对应区域的Bastion子网 subnet_id = azurerm_subnet.AzureBastionSubnet[each.key].id # 同样通过each.key索引到对应区域的公网IP public_ip_address_id = azurerm_public_ip.bastion_public_ip[each.key].id } # 可选:Terraform会自动推断依赖,这个depends_on可以省略 # depends_on = [azurerm_public_ip.bastion_public_ip] }
原理说明
- 当用
for_each创建资源时,Terraform会生成一个资源集合:azurerm_subnet.AzureBastionSubnet是map类型,key为var.bastion_subnet的每个键(即区域名)azurerm_public_ip.bastion_public_ip是set类型,但由于用区域名作为元素,也可以通过区域名直接索引
- 在Bastion Host的
for_each循环中,each.key(或each.value,因为是set类型两者相同)代表当前循环的区域名,用它作为索引就能精准获取对应区域的子网和公网IP的ID。
额外优化建议
如果你的var.bastion_subnet、var.public_ip_location、var.location_list内容重复,可以合并为一个变量,进一步保证一致性:
variable "bastion_regions" { type = map(object({ subnet_name = string subnet_addresses = list(string) })) default = { "eastus" = { subnet_name = "AzureBastionSubnet" subnet_addresses = ["10.0.1.0/26"] }, "westus" = { subnet_name = "AzureBastionSubnet" subnet_addresses = ["10.0.2.0/26"] } } }
然后所有资源的for_each都指向这个变量:
resource "azurerm_subnet" "AzureBastionSubnet" { for_each = var.bastion_regions name = each.value["subnet_name"] resource_group_name = azurerm_resource_group.rg.name virtual_network_name = azurerm_virtual_network.vnet[each.key].name address_prefixes = each.value["subnet_addresses"] depends_on = [azurerm_virtual_network.vnet] } resource "azurerm_public_ip" "bastion_public_ip" { for_each = var.bastion_regions name = "bastion-public-ip-${each.key}" location = each.key resource_group_name = azurerm_resource_group.rg.name allocation_method = "Static" sku = "Standard" depends_on = [azurerm_subnet.AzureBastionSubnet] } resource "azurerm_bastion_host" "bastion" { for_each = var.bastion_regions name = "bastion-${each.key}" location = each.key resource_group_name = azurerm_resource_group.rg.name ip_configuration { name = "configuration" subnet_id = azurerm_subnet.AzureBastionSubnet[each.key].id public_ip_address_id = azurerm_public_ip.bastion_public_ip[each.key].id } }
内容的提问来源于stack exchange,提问作者blzsadam
相关产品推荐
相关产品推荐

