Unable to create vnet peering on azure using terraform and csv data

144 Views Asked by At
Dear Friends,

We are unable to create a Virtual network gateway using the below configuration.
1. We are able to create vnet,subnets and pering using the csv file,but when we try to create multiple subnets using csv data it was showing duplicate error.2. Because of the duplicate error we have created a new two Gateway subnet  manually using azure portal.

3.After this we have tried using the data block and refernce its subnet id inside the resource "azurerm_virtual_network_gateway" block but its failing with error and after removing the data block we are seeing below error. 4.While using data it was saying its not a value.

Can someone please post your suggestions here.

 Error: Invalid index
│
│   on main.tf line 152, in resource "azurerm_virtual_network_gateway" "vnet-gateway-name":
│  152:     subnet_id                     = azurerm_subnet.subnet[each.value.GatewaySubnet].id #data.azurerm_subnet.GatewaySubnet.id #azurerm_subnet.subnet[each.value.GatewaySubnet].id
│     ├────────────────
│     │ azurerm_subnet.subnet is object with 2 attributes
│     │ each.value.GatewaySubnet is "GatewaySubnet"
│
│ The given key does not identify an element in this collection value.
   
 csv file:

#cat rg_name.csv
azureuser@aztfserver:~/newcsv$ cat rg_name.csv
resource_group_name,location,vnet_name,vnet_address_space,subnet_name,subnet_address_space,remote_vnet,natpip_name,natgateway_name,vnetgatewaypip_name,vnetgateway_name,GatewaySubnet
rg-ScriptTest-eus-001,East US,vnet-ScriptTest-eus-001,10.0.0.0/16,subnet1,10.0.1.0/26,vnet-ScriptTest-wus-001,pip-natgw-eus-001,gw-NAT-test-eus-001,pip-vpngw-test-eus-001,vpngw-test-eus-001,GatewaySubnet
rg-ScriptTest-wus-001,West US,vnet-ScriptTest-wus-001,11.0.0.0/16,subnet2,11.0.1.0/26,vnet-ScriptTest-eus-001,pip-natgw-wus-001,gw-NAT-test-wus-001,pip-vpngw-test-wus-001,vpngw-test-wus-001,GatewaySubnet

Terraform code :

   locals {
  vnet_config = csvdecode(file("${path.module}/rg_name.csv"))
}


resource "azurerm_resource_group" "rg" {
  for_each = { for v in local.vnet_config : v.resource_group_name => v }
  name     = each.value.resource_group_name
  location = each.value.location
}

resource "azurerm_virtual_network" "vnet" {
  for_each            = { for v in local.vnet_config : v.vnet_name => v }
  name                = each.value.vnet_name
  location            = each.value.location
  resource_group_name = each.value.resource_group_name
  address_space       = [each.value.vnet_address_space]
  depends_on          = [azurerm_resource_group.rg]
}

resource "azurerm_subnet" "subnet" {
  for_each            = { for v in local.vnet_config : "${v.vnet_name}-${v.subnet_name}" => v }
  name                = each.value.subnet_name
  resource_group_name = each.value.resource_group_name
  virtual_network_name = each.value.vnet_name
  address_prefixes     = [each.value.subnet_address_space]
  depends_on          = [azurerm_virtual_network.vnet]
}
/*
data "azurerm_subnet"  "GatewaySubnet" {
   name = "GatewaySubnet"
   resource_group_name =  azurerm_resource_group.rg[each.key]
   virtual_network_name = azurerm_virtual_network.vnet[each.key]
}
*/



# Assuming that the remote_vnet column in your CSV contains the name of the remote vnet
# and that the remote vnets are within the same subscription and resource group as the local vnets.
resource "azurerm_virtual_network_peering" "vnet_peering" {
  for_each = { for v in local.vnet_config : "${v.vnet_name}-${v.remote_vnet}" => v }

  name                      = "peer-${each.key}"
  resource_group_name       = each.value.resource_group_name
  virtual_network_name      = each.value.vnet_name
  remote_virtual_network_id = azurerm_virtual_network.vnet[each.value.remote_vnet].id

  allow_virtual_network_access = true
  allow_forwarded_traffic      = true
  depends_on = [
    azurerm_virtual_network.vnet,
    azurerm_subnet.subnet
  ]

}

#Public IP

resource "azurerm_public_ip" "natpipname" {
  for_each            = { for v in local.vnet_config : v.natpip_name => v }
  name                = each.value.natpip_name
  resource_group_name    = each.value.resource_group_name
  location               = each.value.location
  allocation_method   = "Static"
  sku                 = "Standard"
  depends_on          = [azurerm_nat_gateway.natgateway,]
}


#Natgateway
resource "azurerm_nat_gateway" "natgateway" {
  for_each            = { for v in local.vnet_config : v.natgateway_name => v }
  name                    = each.value.natgateway_name
  location                = each.value.location
  resource_group_name     = each.value.resource_group_name
  sku_name                = "Standard"
  idle_timeout_in_minutes = 10
  depends_on          = [azurerm_resource_group.rg]
}

# Associate NAT Gateway with Public IP
resource "azurerm_nat_gateway_public_ip_association" "natpipassosciation_name" {
  for_each = { for v in local.vnet_config : v.natgateway_name => v }
  nat_gateway_id       = azurerm_nat_gateway.natgateway[each.value.natgateway_name].id
  public_ip_address_id = azurerm_public_ip.natpipname[each.value.natpip_name].id
  depends_on          = [azurerm_nat_gateway.natgateway,azurerm_public_ip.natpipname]
}



# Associate NAT Gateway with Subnet


resource "azurerm_subnet_nat_gateway_association" "subnet_natgateway" {
  for_each            = { for v in local.vnet_config : "${v.vnet_name}-${v.subnet_name}" => v }
  #subnet_id      = azurerm_subnet.subnet[each.key].id
  subnet_id       = azurerm_subnet.subnet["${each.value.vnet_name}-${each.value.subnet_name}"].id
  nat_gateway_id = azurerm_nat_gateway.natgateway[each.value.natgateway_name].id
  depends_on          = [azurerm_nat_gateway.natgateway]
}


#Vnet Gateways:
#Manages a Virtual Network Gateway to establish secure, cross-premises connectivity.
#Please be aware that provisioning a Virtual Network Gateway takes a long time (between 30 minutes and 1 hour)

resource "azurerm_public_ip" "vnetgatewaypipname" {
  for_each            = { for v in local.vnet_config : v.vnetgatewaypip_name => v }
  name                = each.value.vnetgatewaypip_name
  location            = each.value.location
  resource_group_name = each.value.resource_group_name
  allocation_method = "Dynamic"
  depends_on          = [azurerm_resource_group.rg]
}

resource "azurerm_virtual_network_gateway" "vnet-gateway-name" {
  for_each            = { for v in local.vnet_config : v.vnetgateway_name => v }
#  for_each            = { for v in local.vnet_config : "${v.vnet_name}-${v.subnet_name}" => v }
  name                = each.value.vnetgateway_name
  location            = each.value.location
  resource_group_name     = each.value.resource_group_name
  type     = "Vpn"
  vpn_type = "RouteBased"

  active_active = false
  enable_bgp    = false
  sku           = "VpnGw1"

  ip_configuration {
    #for_each            = { for v in local.vnet_config : v.vnetgwconfig => v }
    #name                          = each.value.vnetgwconfig_name
    public_ip_address_id          = azurerm_public_ip.vnetgatewaypipname[each.value.vnetgatewaypip_name].id
    private_ip_address_allocation = "Dynamic"
    subnet_id                     = azurerm_subnet.subnet[each.value.GatewaySubnet].id #data.azurerm_subnet.GatewaySubnet.id #azurerm_subnet.subnet[each.value.GatewaySubnet].id
  }
  depends_on = [azurerm_public_ip.vnetgatewaypipname]
}

enter image description here

1

There are 1 best solutions below

19
Vinay B On BEST ANSWER

I tried to create vnet peering on azure using terraform and csv data and I was able to provision the requirement successfully.

There is a problem with the Azure Virtual Network Peering configuration. The error indicates that the remote_virtual_network_id cannot be located. This could be because the ID that you are using in the azurerm_virtual_network_peering resource is malformed or the remote virtual network does not exist.

You need to follow few steps to achieve this configuration.

  1. Before creating the peering, make sure that the remote virtual networks (vnet-ScriptTest-wus-002 and vnet-ScriptTest-eus-001) are already created. To ensure that the peering resource depends on the remote VNet, you may have to add a depends_on attribute.

  2. You need to fetch the remote_virtual_network_id dynamically instead of hardcoding the subscription ID and using a placeholder for the resource group name. To do this, you can query Azure using the VNet's name and resource group, which should be the same as what you have in your CSV file. This will give you the ID of the remote VNet.

rg_name.csv

subscription_name,subscriptionID,resource_group_name,location,vnet_name,vnet_address_space,subnet_name,subnet_address_space,remote_vnet

Subscription_Name,Subscription_ID,rgvk-ScriptTest-eus-001,East US,vnet-ScriptTest-eus-001,10.0.0.0/16,subnet1,10.0.1.0/26,vnet-ScriptTest-wus-002

Subscription_Name,Subscription_ID,rgvk-ScriptTest-wus-002,West US,vnet-ScriptTest-wus-002,11.0.0.0/16,subnet2,11.0.1.0/26,vnet-ScriptTest-eus-001

My Configuration:

provider "azurerm" {
  features {}
}

locals {
  vnet_config = csvdecode(file("${path.module}/rg_name.csv"))
}

resource "azurerm_resource_group" "rg" {
  for_each = { for v in local.vnet_config : v.resource_group_name => v }
  name     = each.value.resource_group_name
  location = each.value.location
}

resource "azurerm_virtual_network" "vnet" {
  for_each            = { for v in local.vnet_config : v.vnet_name => v }
  name                = each.value.vnet_name
  location            = each.value.location
  resource_group_name = each.value.resource_group_name
  address_space       = [each.value.vnet_address_space]
  depends_on          = [azurerm_resource_group.rg]
}

resource "azurerm_subnet" "subnet" {
  for_each            = { for v in local.vnet_config : "${v.vnet_name}-${v.subnet_name}" => v }
  name                = each.value.subnet_name
  resource_group_name = each.value.resource_group_name
  virtual_network_name = each.value.vnet_name
  address_prefixes     = [each.value.subnet_address_space]
  depends_on          = [azurerm_virtual_network.vnet]
}


# Assuming that the remote_vnet column in your CSV contains the name of the remote vnet
# and that the remote vnets are within the same subscription and resource group as the local vnets.
resource "azurerm_virtual_network_peering" "vnet_peering" {
  for_each = { for v in local.vnet_config : "${v.vnet_name}-${v.remote_vnet}" => v }

  name                      = "peer-${each.key}"
  resource_group_name       = each.value.resource_group_name
  virtual_network_name      = each.value.vnet_name
  remote_virtual_network_id = azurerm_virtual_network.vnet[each.value.remote_vnet].id

  allow_virtual_network_access = true
  allow_forwarded_traffic      = true
  depends_on = [
    azurerm_virtual_network.vnet,
    azurerm_subnet.subnet
  ]


}

Deployment Succeeded:

enter image description here

enter image description here

enter image description here