azure - Terraform is not returning the value of the vnet_id from the output of a module given the variable key - Stack Overflow

admin2025-04-26  7

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"
        },
    ]
Share Improve this question edited Jan 15 at 12:42 Vinay B 2,9002 gold badges3 silver badges12 bronze badges asked Jan 15 at 3:25 NickPNickP 891 gold badge1 silver badge6 bronze badges 1
  • Try module.network[each.key].vnet_id in peering solution with for_each = var.vnets this will dynamically reference VNet IDs based on the vnets map keys @NickP – Vinay B Commented Jan 15 at 3:39
Add a comment  | 

1 Answer 1

Reset to default 0

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

转载请注明原文地址:http://anycun.com/QandA/1745600880a91022.html