pass multiple outputs to a different module in Terraform - terraform

I'm trying to cover each parts as modules rather than keeping it in a single main.tf file.
My intention is to create 1 vnet (TESTVNET), multiple subnets, NIC's for each subnet.
I'm able to reach till creating multiple subnets in my Vnet. What I'm looking for is on how to pass the subnet ID's to NETWORKINTERFACE module. Please find my code below;
Main.tf
resource "azurerm_resource_group" "resource_group" {
name = var.RGname
location = var.RGlocation
}
module "VNET" {
source = "./Modules/NetworkConfig"
name = var.VNETname
address_space = var.address_space
location = var.RGlocation
resource_group_name = azurerm_resource_group.resource_group.name
}
module "SUBNETS" {
source = "./Modules/SubnetConfig"
Subnetlist = var.Subnetlist
virtual_network_name = module.VNET.vnet_name
resource_group_name = azurerm_resource_group.resource_group.name
depends_on = [azurerm_resource_group.resource_group, module.VNET.vnet]
}
module "NETWORKINTERFACE" {
source = "./Modules/NIConfig"
niclist = var.niclist
resource_group_name = azurerm_resource_group.resource_group.name
location = azurerm_resource_group.resource_group.location
SUBNET.tf
resource "azurerm_subnet" "SUBNETS" {
for_each=var.Subnetlist
name=each.value.name
address_prefixes=[each.value.address]
resource_group_name = var.resource_group_name
virtual_network_name = var.virtual_network_name
}
output "subnet_ids" {
value = values(azurerm_subnet.SUBNETS)[*].id
}
NETWORKINTERFACE.tf
resource "azurerm_network_interface" "NETWORKINTERFACE" {
for_each=var.niclist
name = each.value.name
location = var.location
resource_group_name = var.resource_group_name
ip_configuration {
name = "ipconfig1"
subnet_id = # part where I'm confused
private_ip_address_allocation = "Dynamic"
}
}
How can I pass the output values from Subnet module (3 subnet in total=3 id's) to NETWORKINTERFACE module, where it should take each of these id's in for_each=var.niclist loop.
If you find this approach incorrect, let me know
PS. I'm new to terraform
-- update 2
please find my tfvars
RGlocation = "westus"
RGname = "TEST-RG1-TERRAFORM"
VNETname = "TEST-VNET-TERRAFORM"
address_space = "10.0.0.0/16"
Subnetlist = {
"s1" = { name = "TESTSUBNET1-TERRAFORM", address = "10.0.1.0/24" },
"s2" = { name = "TESTSUBNET2-TERRAFORM", address = "10.0.2.0/24" },
"s3" = { name = "TESTSUBNET3-TERRAFORM", address = "10.0.3.0/24" }
}
niclist = {
"s1" = { name = "TESTNIC1-TERRAFORM" },
"s2" = { name = "TESTNIC2-TERRAFORM" },
"s3" = { name = "TESTNIC3-TERRAFORM" }
}
this is how the variable is populated. I have used the suggestion from #martin and modified few commands. It is now creating subnets and NIC's the way I wanted.
Main.tf
module "VNET" {
source = "./Modules/NetworkConfig"
name = var.VNETname
address_space = var.address_space
location = var.RGlocation
resource_group_name = azurerm_resource_group.resource_group.name
}
module "SUBNETS" {
source = "./Modules/SubnetConfig"
Subnetlist = var.Subnetlist
virtual_network_name = module.VNET.vnet_name
resource_group_name = azurerm_resource_group.resource_group.name
depends_on = [azurerm_resource_group.resource_group, module.VNET.vnet]
}
module "NETWORKINTERFACE" {
source = "./Modules/NIConfig"
resource_group_name = azurerm_resource_group.resource_group.name
location = azurerm_resource_group.resource_group.location
nics = tomap({
for k, subnet_id in module.SUBNETS.subnet_ids : k => {
name = var.niclist[k].name
subnet_id = subnet_id
}
})
}
SUBNETS.tf
resource "azurerm_subnet" "SUBNETS" {
for_each=var.Subnetlist
name=each.value.name
address_prefixes=[each.value.address]
resource_group_name = var.resource_group_name
virtual_network_name = var.virtual_network_name
}
output "subnet_ids" {
value = tomap({ for k, s in azurerm_subnet.SUBNETS : k => s.id })
}
NETWORKINTERFACE.tf
resource "azurerm_network_interface" "NETWORKINTERFACE" {
for_each=var.nics
name = each.value.name
location = var.location
resource_group_name = var.resource_group_name
ip_configuration {
name = "ipconfig1"
subnet_id = each.value.subnet_id
private_ip_address_allocation = "Dynamic"
}
}

When using for_each across multiple resources and modules like this it's important to preserve the tracking keys of the objects so that Terraform can see which instances of one resource correlate with instances of another and with the intermediate data structures that you use to pass the data around.
In your case, that would mean changing the shape of the subnet_ids output value to be a map from subnet key to subnet ID, rather than just the subnet IDs alone, so that it's clear which ID belongs to which subnet key:
resource "azurerm_subnet" "all" {
for_each = var.Subnetlist
name = each.value.name
address_prefixes = [each.value.address]
resource_group_name = var.resource_group_name
virtual_network_name = var.virtual_network_name
}
output "subnet_ids" {
value = tomap({ for k, s in azurerm_subnet.all : k => s.id })
}
Your network interface module seems to have an input variable niclist whose declaration you didn't show, but I'm assuming it'll look something like this, and I'm going to rename it to nics because I'm changing it to be a map instead:
variable "nics" {
type = map(
object({
name = string
subnet_id = string
})
)
}
You can then use that variable as the basis for your for_each of network interfaces:
resource "azurerm_network_interface" "all" {
for_each = var.nics
name = each.value.name
location = var.location
resource_group_name = var.resource_group_name
ip_configuration {
name = "ipconfig1"
subnet_id = each.value.subnet_id
private_ip_address_allocation = "Dynamic"
}
}
The remaining problem then is how to build the value of the nics input variable from inside the root module. You haven't shown how the root module's niclist variable is populated, and so I don't know how NICs and subnets are related. Since you showed a configuration which suggests one NIC per subnet, perhaps it would be sufficient to derive the nics variable value directly from the subnets map and remove var.niclist altogether:
module "network_interface" {
source = "./Modules/NIConfig"
resource_group_name = azurerm_resource_group.resource_group.name
location = azurerm_resource_group.resource_group.location
nics = tomap({
for k, subnet_id in module.subnets.subnet_ids : k => {
name = k
subnet_id = subnet_id
}
})
}
NOTE: The naming scheme you're currently using doesn't match usual Terraform idiom and so I changed some of the names in my answer here to use the standard style of all-lowercase names with words separated by underscores. I would suggest following the standard naming scheme so that your configuration will be intuitive to future maintainers who might already have Terraform experience from elsewhere.

Related

get the subnetid from subnets of type map(object)

I need to fetch the subnetid from azurerm_subnet data resource as subnet is used in dynamic block of azurerm_virtual_network as map(object) type
resource "azurerm_virtual_network" "example" {
name = "example-vnet"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
dynamic "subnet" {
for_each = var.subnets
content {
name = subnet.value.name
address_prefix = subnet.value.address_prefix
security_group = azurerm_network_security_group.example[subnet.key].id
}
}
}
Fetch the second subnetid to attach it to storage account
resource "azurerm_storage_account" "example" {
count = length(var.subnets)
name = "storageaccountname"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
account_tier = "Standard"
account_replication_type = "GRS"
network_rules {
default_action = "Deny"
virtual_network_subnet_ids = ["${data.azurerm_subnet.subnetid.id}"]
}
}
Please can any one help to solve as i want to declare subnet in azurerm_virtual_network as dynamic block and get the subnet if from the data resource and please find my terraform.tfvars as below
subnets = {
subnet1 = {
name = "subnet1"
address_prefix = "10.0.0.0/24"
}
subnet2 = {
name = "subnet2"
address_prefix = "10.0.1.0/24"
}
subnet3 = {
name = "subnet3"
address_prefix = "10.0.2.0/24"
}
}
IMPORTANT
count = length(var.subnets) in resource "azurerm_storage_account" "example" {} is still there in your question which is logically incorrect as I have stated in the comments.
Answer
With your comments, I am assuming that you want to use id of subnet2 in network_rules of resource "azurerm_storage_account" "example" {}. With your current approach where creating subnets within the virtual network resource you have to use splat expressions and locals to make a map out of the set object and then can directly refer wherever is required.
While doing referencing even with locals and splat expressions it is still required to use the name of the subnet as it is not possible for terraform to know what you want without any data.
resource "azurerm_virtual_network" "example" {
name = "example-vnet"
address_space = ["10.0.0.0/16"]
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
dynamic "subnet" {
for_each = var.subnets
content {
name = subnet.value.name
address_prefix = subnet.value.address_prefix
# security_group = azurerm_network_security_group.example[subnet.key].id ## I have ignored it as no relevant code is shared###
}
}
}
locals {
subnets = { for subnet in azurerm_virtual_network.example.subnet : subnet.name => subnet }
}
resource "azurerm_storage_account" "example" {
#count = length(var.subnets) ## Removed it too as logically incorrect with the current code ##
name = "storageaccountname"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
account_tier = "Standard"
account_replication_type = "GRS"
network_rules {
default_action = "Deny"
virtual_network_subnet_ids = [local.subnets.subnet2.id]
}
You do not need a data source when referencing the attributes from one resource/module to another resource/module in the root module.
However, I suggest using azurerm_subnet resource for easier reference in spite of creating subnets in the virtual network resource itself because your might need Microsoft.Storage service_endpoints in your subnets for working with storage account with network_rules.

List & String Conversion Issue for Data sources

I am caught in a bit of a loop on this one. Need to provide the azure_windows_virtual_machine with a list of network interface IDs. The network interfaces are created using a separate resource block. In my variable definition for the windows vm, I provide an argument for the name[s] of said network interfaces so that we can correctly associate the nics that we want with each virtual machine. If we have 100 nics and 90 VMs, some of the VMs could get two NICs, so we want to be sure we provide some link between NIC name and VM name.
The network interface names are therefore a list(string).
I have been trying to use the values function to get the list of NIC IDs (given the names), but running into a failure: "The each object can be used only in "module" or "resource" blocks, and only when the "for_each" argument is set."
If I use a data source in the resource block, which seemed most logical, it fails too because I have a list(string) specified for the network_interface_names argument, but the data source cannot take that. It of course needs a single string. But it's never going to be a single string, it's always going to be a list (since we can have more than one NIC per VM).
I think the correct answer is to maybe create the list of IDs beforehand - trick is that it would need to almost be dynamic for each defined VM - because each VM will have a different list of network_interface_names. We therefore need to generate the new list on the fly for each VM.
Variables
variable "resource_groups" {
description = "Resource groups"
type = map(object({
location = string
}))
}
variable "virtual_networks" {
description = "virtual networks and properties"
type = map(object({
resource_group_name = string
address_space = list(string)
}))
}
variable "subnets" {
description = "subnet and their properties"
type = map(object({
resource_group_name = string
virtual_network_name = string
address_prefixes = list(string)
}))
}
variable "nic" {
description = "network interfaces"
type = map(object({
subnet_name = string
resource_group_name = string
}))
}
variable "admin_password" {
type = string
sensitive = true
}
variable "admin_user" {
type = string
sensitive = true
}
variable "windows_vm" {
description = "Windows virtual machine"
type = map(object({
network_interface_names = list(string)
resource_group_name = string
size = string
timezone = string
}))
}
INPUTS
resource_groups = {
rg-eastus-dev1 = {
location = "eastus"
}
}
virtual_networks = {
vnet-dev1 = {
resource_group_name = "rg-eastus-dev1"
address_space = ["10.0.0.0/16"]
}
}
subnets = {
snet-01 = {
resource_group_name = "rg-eastus-dev1"
virtual_network_name = "vnet-dev1"
address_prefixes = ["10.0.1.0/24"]
}
}
nic = {
nic1 = {
subnet_name = "snet-01"
resource_group_name = "rg-eastus-dev1"
}
}
admin_password = "s}8cpH96qa.1BQ"
admin_user = "padmin"
windows_vm = {
winvm1 = {
network_interface_names = ["nic1"]
resource_group_name = "rg-eastus-dev1"
size = "Standard_B2s"
timezone = "Eastern Standard Time"
}
}
MAIN
resource "azurerm_resource_group" "rgs" {
for_each = var.resource_groups
name = each.key
location = each.value["location"]
}
data "azurerm_resource_group" "rgs" {
for_each = var.resource_groups
name = each.key
depends_on = [
azurerm_resource_group.rgs
]
}
resource "azurerm_virtual_network" "vnet" {
for_each = var.virtual_networks
name = each.key
resource_group_name = each.value["resource_group_name"]
address_space = each.value["address_space"]
location = data.azurerm_resource_group.rgs[each.value["resource_group_name"]].location
}
resource "azurerm_subnet" "subnet" {
for_each = var.subnets
name = each.key
resource_group_name = each.value["resource_group_name"]
virtual_network_name = each.value["virtual_network_name"]
address_prefixes = each.value["address_prefixes"]
depends_on = [
azurerm_virtual_network.vnet
]
}
data "azurerm_subnet" "subnet" {
for_each = var.subnets
name = each.key
virtual_network_name = each.value["virtual_network_name"]
resource_group_name = each.value["resource_group_name"]
depends_on = [
azurerm_resource_group.rgs
]
}
resource "azurerm_network_interface" "nics" {
for_each = var.nic
ip_configuration {
name = each.key
subnet_id = data.azurerm_subnet.subnet[each.value["subnet_name"]].id
private_ip_address_allocation = "Dynamic"
}
location = data.azurerm_resource_group.rgs[each.value["resource_group_name"]].location
name = each.key
resource_group_name = each.value["resource_group_name"]
depends_on = [
azurerm_resource_group.rgs,
azurerm_subnet.subnet
]
}
data "azurerm_network_interface" "nics" {
for_each = var.nic
name = each.key
resource_group_name = each.value["resource_group_name"]
depends_on = [
azurerm_resource_group.rgs
]
}
resource "azurerm_windows_virtual_machine" "windows_vm" {
for_each = var.windows_vm
admin_password = var.admin_password
admin_username = var.admin_user
location = data.azurerm_resource_group.rgs[each.value["resource_group_name"]].location
name = each.key
network_interface_ids = values(data.azurerm_network_interface.nics[each.value["network_interface_names"]].id)
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
resource_group_name = each.value["resource_group_name"]
size = each.value["size"]
timezone = each.value["timezone"]
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2019-Datacenter"
version = "latest"
}
}
Current Error on Plan
╷
│ Error: Invalid index
│
│ on main.tf line 75, in resource "azurerm_windows_virtual_machine" "windows_vm":
│ 75: network_interface_ids = values(data.azurerm_network_interface.nics[each.value["network_interface_names"]].id)
│ ├────────────────
│ │ data.azurerm_network_interface.nics is object with 1 attribute "nic1"
│ │ each.value["network_interface_names"] is list of string with 1 element
│
│ The given key does not identify an element in this collection value: string required.
Possible Solution - But Not working
Provide a map, keyed off the VM name, of NIC IDs. Then, in the windows_vm resource, take that map and try to get the list of NIC ID values.
locals {
nic_ids {
[for k, v in var.windows_vm : k => v {data.azurerm_network_interface.nics[v.network_interface_names]}.id]
}
}
resource "azurerm_windows_virtual_machine" "windows_vm" {
for_each = var.windows_vm
admin_password = var.admin_password
admin_username = var.admin_user
location = data.azurerm_resource_group.rgs[each.value["resource_group_name"]].location
name = each.key
network_interface_ids = values(local.nic_ids[each.key])
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
resource_group_name = each.value["resource_group_name"]
size = each.value["size"]
timezone = each.value["timezone"]
source_image_reference {
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2019-Datacenter"
version = "latest"
}
}
First of all, you do not need to call data after creation of each resource. The resource itself will contain all the information that you need. So you should eliminate all data sources in your code and use resource directly.
But returning to the error you provided. One way to generate the list dynamically, would be:
network_interface_ids = [for ni_name in each.value["network_interface_names"]: azurerm_network_interface.nics[ni_name].id]

terraform multiple vm with separate module for nic and separate module for vm .. both NIC get attached to first vm that gets created

I have created separate modules for vnet, NIC and VM.. I am trying to create two vms in the vm module and two nics in the nic module... created an output in the nic module to get the nic.id and this output am referring in the vm module , but only one vm gets created with two nics and second vm fails to create due to unavailability of nic... please find my code below, i need to be able to map the individual nic in the nic module to individual vm in the vm moodule
main.tf
module "nic" {
source = "./Nic"
resource_group_name = module.vnet1mod.rgnameout
location = module.vnet1mod.rglocationout
subnet_id = module.vnet1mod.subnetout
}
module "vnet1mod" {
source = "./vnetmodule"
}
module "virtualmachine" {
source = "./VirtualMachine"
resource_group_name = module.vnet1mod.rgnameout
location = module.vnet1mod.rglocationout
network_interface_ids = module.nic.netinterfaceoutput # this is where its failing !!
}
..............
nic module
resource "azurerm_network_interface" "nic1" {
for_each = var.vmdetails
name = each.value.vmnic
location = var.location
resource_group_name = var.resource_group_name
ip_configuration {
name = "internal"
subnet_id = var.subnet_id
private_ip_address_allocation = "Dynamic"
}
}
output "netinterfaceoutput" {
value = tomap({ for k, s in azurerm_network_interface.nic1 : k => s.id })
}
variable "location" {`enter code here`
type = string
description = "(optional) describe your variable"
}
variable "resource_group_name" {
type = string
description = "(optional) describe your variable"
}
variable "subnet_id" {
type = string
description = "(optional) describe your variable"
}
...........
vm module
resource "azurerm_windows_virtual_machine" "vm1" {
for_each = var.vmdetails
name = each.value.vmname
resource_group_name = var.resource_group_name
location = var.location
size = var.vmsize
admin_username = var.adminusername
admin_password = var.adminpassword
network_interface_ids = var.network_interface_ids
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = var.publisher
offer = var.offer
sku = var.sku
version = var.Osversion
}
}
variable "vmdetails" {
type = map(any)
default = {
"vm1" = {
vmname = "vmA-1"
vmnic = "vmnicA-1"
}
"vm2" = {
vmname = "vmA-2"
vmnic = "vmnicA-2"
}
}
}
........
vnet module
resource "azurerm_virtual_network" "vnet1" {
name = var.vnet_name
location = var.location_name
resource_group_name = var.resourcegroup1_name
address_space = var.vnet_address
}
resource "azurerm_subnet" "subnet1" {
name = var.subnet_name
resource_group_name = var.resourcegroup1_name
virtual_network_name = azurerm_virtual_network.vnet1.name
address_prefixes = var.subnet_address
}
output "rgnameout" {
value = azurerm_virtual_network.vnet1.resource_group_name
}
output "rglocationout" {
value = azurerm_virtual_network.vnet1.location
}
output "subnetout" {
value = azurerm_subnet.subnet1.id
}

Terraform azure output of multiple network interfaces assigning to a single vm

not sure if anyone has come across this issue before, i have multiple network interfaces that i need to attach to a vm in Azure, i am passing in network interface details as a map. i need to use the output of network interfaces and apply it to the network_interface_ids in vm resource. my current code to assign network_interface_ids doesn't seem to be getting the network interface ids from output of azurerm_network_interface. Here is the short snapshot of the code i have:
resource "azurerm_network_interface" "vmNic" {
for_each = var.network_interfaces
name = each.value.name
resource_group_name = var.resource_group_name
location = var.resource_group_location
ip_configuration {
name = "${each.value.name}-ip"
subnet_id = each.value.subnet_id
private_ip_address_allocation = "Static"
private_ip_address = each.value.private_ip
}
}
resource "azurerm_virtual_machine" "vm" {
count = length(azurerm_network_interface.vmNic)
name = var.vm_name
location = var.resource_group_location
resource_group_name = var.resource_group_name
network_interface_ids = try(azurerm_network_interface.vmNic.*.id[count.index], null)
any ideas what i am doing wrong here in assigning the network_interface_ids?
It seems you want to create multiple NICs and attach them to a single VM, and the variable network_interfaces looks like a list with object elements. So if I'm right. You can change the code like this:
resource "azurerm_network_interface" "vmNic" {
count = length(var.network_interfaces)
name = element(var.network_interfaces, count.index)["name"]
resource_group_name = var.resource_group_name
location = var.resource_group_location
ip_configuration {
name = "${element(var.network_interfaces, count.index)["name"]}-ip"
subnet_id = element(var.network_interfaces, count.index)["subnet_id"]
private_ip_address_allocation = "Static"
private_ip_address = element(var.network_interfaces, count.index)["private_ip"]
}
}
resource "azurerm_virtual_machine" "vm" {
count = length(azurerm_network_interface.vmNic)
name = var.vm_name
location = var.resource_group_location
resource_group_name = var.resource_group_name
network_interface_ids = azurerm_network_interface.vmNic.*.id
The variable network_interfaces here looks like this:
variable "network_interfaces" {
default = [
{
name = "test1",
subnet_id = "xxxxxx",
private_ip = "x.x.x.x"
},
{
name = "test2",
subnet_id = "xxxxxx",
private_ip = "x.x.x.x"
}
]
}

how to reference objects in terraform

I am creating an Azure VNet using terraform, and creating a couple subnets in it. Later on , I want to create a network interface, and want to put it in one of the subnets already created for VNet. I do not know how to reference that subnet.
I tried below but it is now working:
subnet_id = "${azurerm_virtual_network.virtual-network.subnet.ServersSubnet.id}"
resource "azurerm_virtual_network" "virtual-network" {
name = "${var.ClientShortName}-az-network"
address_space = ["${local.AzureInfraNetwork}"]
location = "${var.resource-location}"
resource_group_name = "${azurerm_resource_group.test-resource-group.name}"
subnet {
name = "ServersSubnet"
address_prefix = "${local.ServersSubnet}"
}
subnet {
name = "GatewaySubnet"
address_prefix = "${local.GatewaySubnet}"
}
}
Error: Cannot index a set value
on main.tf line 120, in resource "azurerm_network_interface" "DCNIC":
120: subnet_id = "${azurerm_virtual_network.virtual-network.subnet.ServersSubnet.id}"
Block type "subnet" is represented by a set of objects, and set elements do
not have addressable keys. To find elements matching specific criteria, use a
"for" expression with an "if" clause.
Below is the complete solution.
If the subnets are created as blocks, you can reference a given subnet's resource ID as follows:
resource "azurerm_resource_group" "main" {
name = "vnet-rg"
location = "eastus"
}
resource "azurerm_virtual_network" "main" {
name = "my-vnet"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
address_space = ["10.0.0.0/16"]
subnet {
name = "subnet1"
address_prefix = "10.0.1.0/24"
}
subnet {
name = "subnet2"
address_prefix = "10.0.2.0/24"
}
subnet {
name = "subnet3"
address_prefix = "10.0.3.0/24"
}
}
output "subnet1_id" {
value = azurerm_virtual_network.main.subnet.*.id[0]
}
output "subnet2_id" {
value = azurerm_virtual_network.main.subnet.*.id[1]
}
output "subnet3_id" {
value = azurerm_virtual_network.main.subnet.*.id[2]
}
When creating subnets as blocks you must reference them using the list syntax, e.g.:
foo = azurerm_virtual_network.virtual-network.subnet[0].id
bar = azurerm_virtual_network.virtual-network.subnet[1].id
This is useful if the subnets form a pool of redundant resources and you don't care about referencing any subnet in particular.
I don't believe that's your case, so you might consider creating your subnets as separated resources, e.g:
resource "azurerm_virtual_network" "main" {
name = "${var.ClientShortName}-az-network"
address_space = [local.AzureInfraNetwork]
location = var.resource-location
resource_group_name = azurerm_resource_group.test-resource-group.name
}
resource "azurerm_subnet" "server" {
virtual_network_name = azurerm_virtual_network.main.name
name = "ServersSubnet"
address_prefix = local.ServersSubnet
}
resource "azurerm_subnet" "gateway" {
virtual_network_name = azurerm_virtual_network.main.name
name = "GatewaySubnet"
address_prefix = local.ServersSubnet
}
Then you could reference one of your subnets using the regular object attribute syntax:
foo = azurerm_subnet.server.id
Also note that I'm using terraform => 0.12 syntax, so I can write foo.bar instead of "${foo.bar}" when I don't need string interpolation.
If anyone else needs the answer to this use this:
"${element(azuread_application.events_backend.app_role[*].id,0)}"
You can break this out into creating the virtual network and the subnet as separate resources. Advantage of this is that you can return your subnets as a map rather than a list, making it easier to retrieve by name later on, it also makes it stable if you need to add/remove subnets at a later stage.
locals {
subnets = {
Servers = "10.0.1.0/24",
Gateway = "10.0.2.0/24"
}
}
resource "azurerm_resource_group" "main" {
name = "vnet-rg"
location = "eastus"
}
resource "azurerm_virtual_network" "main" {
name = "my-vnet"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
address_space = [ local.AzureInfraNetwork ]
}
resource "azurerm_subnet" "main" {
for_each = var.subnets
name = "${each.key}-subnet"
resource_group_name = azurerm_resource_group.main.name
virtual_network_name = azurerm_virtual_network.main.name
address_prefixes = [ each.value ]
}
output "subnets" {
value = azurerm_subnet.main
}

Resources