I am attempting to obtain an Azure vnet id from a vnet that was deployed to a module with a for_each loop. The vnet name is the key on the vnets map variable. When attempting to pass the name to obtain the vnet id to the module output, i.e. modulework[vnet_name].vnet_id
, i would expect to get the vnet resource id. Instead terraform is throwing an error, and i cannot figure out why, especially since i can pull the exact vnet name using the key(var.vnets)[0]
in order to get the vnet name and the outputs work, and also hard coding the vnet name works, i,e modulework["vnet1"].vnet_id
.
Error: The given key does not identify an element in this collection value.
variable.tf
variable "vnets" {
type = map(object({
address_space = list(string)
dns_servers = list(string)
subnets = list(object({
subnet_name = string
subnet_address = string
subnet_endpoints = list(string)
private_endpoint_network_policies_enabled = bool
}))
}))
default = {
"vnet1" = {
address_space = ["100.102.248.0/26", "100.102.249.0/24"]
dns_servers = ["10.25.1.5", "10.25.1.6"]
subnets = [
{
subnet_name = "subnet1_name"
subnet_address = "100.102.248.0/27"
subnet_endpoints = ["Microsoft.EventHub", "Microsoft.KeyVault", "Microsoft.Storage", "Microsoft.ServiceBus", "Microsoft.Web"]
private_endpoint_network_policies_enabled = true
},
{
subnet_name = "subnet2_name"
subnet_address = "100.102.248.32/27"
subnet_endpoints = ["Microsoft.EventHub", "Microsoft.KeyVault", "Microsoft.Storage", "Microsoft.ServiceBus", "Microsoft.Web"]
private_endpoint_network_policies_enabled = true
},
{
subnet_name = "subnet3_name"
subnet_address = "100.102.249.0/28"
subnet_endpoints = ["Microsoft.EventHub", "Microsoft.KeyVault", "Microsoft.Storage", "Microsoft.ServiceBus", "Microsoft.Web"]
private_endpoint_network_policies_enabled = true
}
]
}
}
}
Vnet module output
output "vnet_name" {
value = {for k, v in azurerm_virtual_network.vnet: k => v.name}
}
output "vnet_id" {
value = {for k, v in azurerm_virtual_network.vnet: k => v.id}
}
output "vnet_address_space" {
value = {for k, v in azurerm_virtual_network.vnet: k => v.address_space}
}
output "subnet_name" {
value = {for k, v in azurerm_subnet.subnet: k => v.name}
}
output "subnet_id" {
value = {for k, v in azurerm_subnet.subnet: k => v.id}
}
output "subnet_addresses" {
description = "The name of the subnet addresses"
value = {for k, v in azurerm_subnet.subnet: k => v.address_prefixes}
}
Resource using the vnet1 resource id from the module deployment. The syntax seems to be failing on the vnet_id from the module output on 'remote_virtual_network_id'. Interestingly enough, if I hard code the vnet_id in there, the name resolves to the vnet1 I need.
resource "azurerm_virtual_network_peering" "hub-to-vnet-peer" {
name = "${keys(var.vnets)[0]}-PEER"
resource_group_name = local.hub_vnet_rg
virtual_network_name = data.azurerm_virtual_network.hub-vnet.name
**remote_virtual_network_id = modulework["${keys(var.vnets)[0]}"].vnet_id**
allow_virtual_network_access = true
allow_forwarded_traffic = true
allow_gateway_transit = true
provider = azurerm.azure-hub
depends_on = [modulework]
}
Error:
Error: Invalid index
│
│ on vnet.tf line 38, in resource "azurerm_virtual_network_peering" "hub-to-vnet-peer":
│ 38: remote_virtual_network_id = modulework["${keys(var.vnets)[0]}"].vnet_id
│ ├────────────────
│ │ modulework is object with 6 attributes
│ │ var.vnets is map of object with 1 element
│
│ The given key does not identify an element in this collection value.
output
output "vnet1" {
value = keys(var.vnets)[0]
}
output "vnetid" {
value = modulework.*.vnet_id
}
Changes to Outputs:
+ vnet1 = "vnet1"
+ vnetid = [
+ {
+ vnet1 = "/subscriptions/sub_id/resourceGroups/rg/providers/Microsoft.Network/virtualNetworks/vent1"
},
]
I am attempting to obtain an Azure vnet id from a vnet that was deployed to a module with a for_each loop. The vnet name is the key on the vnets map variable. When attempting to pass the name to obtain the vnet id to the module output, i.e. module.network[vnet_name].vnet_id
, i would expect to get the vnet resource id. Instead terraform is throwing an error, and i cannot figure out why, especially since i can pull the exact vnet name using the key(var.vnets)[0]
in order to get the vnet name and the outputs work, and also hard coding the vnet name works, i,e module.network["vnet1"].vnet_id
.
Error: The given key does not identify an element in this collection value.
variable.tf
variable "vnets" {
type = map(object({
address_space = list(string)
dns_servers = list(string)
subnets = list(object({
subnet_name = string
subnet_address = string
subnet_endpoints = list(string)
private_endpoint_network_policies_enabled = bool
}))
}))
default = {
"vnet1" = {
address_space = ["100.102.248.0/26", "100.102.249.0/24"]
dns_servers = ["10.25.1.5", "10.25.1.6"]
subnets = [
{
subnet_name = "subnet1_name"
subnet_address = "100.102.248.0/27"
subnet_endpoints = ["Microsoft.EventHub", "Microsoft.KeyVault", "Microsoft.Storage", "Microsoft.ServiceBus", "Microsoft.Web"]
private_endpoint_network_policies_enabled = true
},
{
subnet_name = "subnet2_name"
subnet_address = "100.102.248.32/27"
subnet_endpoints = ["Microsoft.EventHub", "Microsoft.KeyVault", "Microsoft.Storage", "Microsoft.ServiceBus", "Microsoft.Web"]
private_endpoint_network_policies_enabled = true
},
{
subnet_name = "subnet3_name"
subnet_address = "100.102.249.0/28"
subnet_endpoints = ["Microsoft.EventHub", "Microsoft.KeyVault", "Microsoft.Storage", "Microsoft.ServiceBus", "Microsoft.Web"]
private_endpoint_network_policies_enabled = true
}
]
}
}
}
Vnet module output
output "vnet_name" {
value = {for k, v in azurerm_virtual_network.vnet: k => v.name}
}
output "vnet_id" {
value = {for k, v in azurerm_virtual_network.vnet: k => v.id}
}
output "vnet_address_space" {
value = {for k, v in azurerm_virtual_network.vnet: k => v.address_space}
}
output "subnet_name" {
value = {for k, v in azurerm_subnet.subnet: k => v.name}
}
output "subnet_id" {
value = {for k, v in azurerm_subnet.subnet: k => v.id}
}
output "subnet_addresses" {
description = "The name of the subnet addresses"
value = {for k, v in azurerm_subnet.subnet: k => v.address_prefixes}
}
Resource using the vnet1 resource id from the module deployment. The syntax seems to be failing on the vnet_id from the module output on 'remote_virtual_network_id'. Interestingly enough, if I hard code the vnet_id in there, the name resolves to the vnet1 I need.
resource "azurerm_virtual_network_peering" "hub-to-vnet-peer" {
name = "${keys(var.vnets)[0]}-PEER"
resource_group_name = local.hub_vnet_rg
virtual_network_name = data.azurerm_virtual_network.hub-vnet.name
**remote_virtual_network_id = module.network["${keys(var.vnets)[0]}"].vnet_id**
allow_virtual_network_access = true
allow_forwarded_traffic = true
allow_gateway_transit = true
provider = azurerm.azure-hub
depends_on = [module.network]
}
Error:
Error: Invalid index
│
│ on vnet.tf line 38, in resource "azurerm_virtual_network_peering" "hub-to-vnet-peer":
│ 38: remote_virtual_network_id = module.network["${keys(var.vnets)[0]}"].vnet_id
│ ├────────────────
│ │ module.network is object with 6 attributes
│ │ var.vnets is map of object with 1 element
│
│ The given key does not identify an element in this collection value.
output
output "vnet1" {
value = keys(var.vnets)[0]
}
output "vnetid" {
value = module.network.*.vnet_id
}
Changes to Outputs:
+ vnet1 = "vnet1"
+ vnetid = [
+ {
+ vnet1 = "/subscriptions/sub_id/resourceGroups/rg/providers/Microsoft.Network/virtualNetworks/vent1"
},
]
Terraform is not returning the value of the vnet_id from the output of a module given the variable key
Issue seems to be the way you refering the remote virtual vnet id from the output of the module.
You always need to make sure the for_each
in the module
matches the structure of var.vnets
Use the exact key for referencing module outputs dynamically. Since youre refering doesnt matches the requirement youre facing the error.
Demo configuration:
variable "vnets" {
type = map(object({
address_space = list(string)
dns_servers = list(string)
subnets = list(object({
subnet_name = string
subnet_address = string
subnet_endpoints = list(string)
private_endpoint_network_policies_enabled = bool
}))
}))
default = {
"vnet1" = {
address_space = ["100.102.248.0/26", "100.102.249.0/24"]
dns_servers = ["10.25.1.5", "10.25.1.6"]
subnets = [
{
subnet_name = "subnet1"
subnet_address = "100.102.248.0/27"
subnet_endpoints = ["Microsoft.EventHub", "Microsoft.KeyVault"]
private_endpoint_network_policies_enabled = true
},
{
subnet_name = "subnet2"
subnet_address = "100.102.248.32/27"
subnet_endpoints = ["Microsoft.Storage", "Microsoft.Web"]
private_endpoint_network_policies_enabled = true
}
]
}
}
}
resource "azurerm_resource_group" "example" {
name = "vksb-rg"
location = "East US"
}
module "network" {
source = "./module/network"
for_each = var.vnets
vnet_name = each.key
address_space = each.value.address_space
dns_servers = each.value.dns_servers
subnets = each.value.subnets
resource_group_name = azurerm_resource_group.example.name
}
data "azurerm_resource_group" "hub_vnet" {
name = "vinay-rg"
}
data "azurerm_virtual_network" "hub_vnet" {
name = "hub-vnet"
resource_group_name = data.azurerm_resource_group.hub_vnet.name
}
resource "azurerm_virtual_network_peering" "hub_to_vnet_peer" {
for_each = var.vnets
name = "${each.key}-PEER"
resource_group_name = data.azurerm_resource_group.hub_vnet.name
virtual_network_name = data.azurerm_virtual_network.hub_vnet.name
remote_virtual_network_id = module.network[each.key].vnet_id
allow_virtual_network_access = true
allow_forwarded_traffic = true
allow_gateway_transit = true
}
module/network/main.tf:
resource "azurerm_virtual_network" "vnet" {
name = var.vnet_name
resource_group_name = var.resource_group_name
location = "East US"
address_space = var.address_space
dns_servers = var.dns_servers
}
resource "azurerm_subnet" "subnet" {
for_each = { for idx, subnet in var.subnets : idx => subnet }
name = each.value.subnet_name
resource_group_name = var.resource_group_name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = [each.value.subnet_address]
}
output "vnet_id" {
value = azurerm_virtual_network.vnet.id
}
deployment:
Here the sync issue happen due to the permission i dont have for doing so.
refer:
https://developer.hashicorp.com/terraform/language/meta-arguments/for_each
https://www.thegreatcodeadventure.com/building-dynamic-outputs-with-terraform-for_each-for-and-zipmap/ blog by Sophie DeBenedetto
https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network_peering