terraform: add public IP to only one azure VM - azure

I'm creating 4 vms through count in azurerm_virtual_machine but i want to create only one public IP and associate it with the first VM ? is that possible if so how ?
below is my template file
resource "azurerm_network_interface" "nics" {
count = 4
name = ...
location = ...
resource_group_name = ...
ip_configuration {
subnet_id = ...
private_ip_address_allocation = "Static"
private_ip_address = ...
}
}
resource "azurerm_public_ip" "public_ip" {
name = ...
location = ...
resource_group_name = ...
}
resource "azurerm_virtual_machine" "vms" {
count = 4
network_interface_ids = [element(azurerm_network_interface.nics.*.id, count.index)]
}
i have already gone through below questions but they are create multiple public ip's & add them to all vms.
multiple-vms-with-public-ip
set-dynamic-ip
attach-public-ip

Public IPs are created using azurerm_public_ip:
resource "azurerm_public_ip" "public_ip" {
name = "acceptanceTestPublicIp1"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
allocation_method = "Dynamic"
}
Having the address in your azurerm_network_interface you could do the following using Conditional Expressions:
resource "azurerm_network_interface" "nics" {
count = 4
name = ...
location = ...
resource_group_name = ...
ip_configuration {
subnet_id = ...
private_ip_address_allocation = "Static"
private_ip_address = ...
public_ip_address_id = count.index == 1 ? azurerm_public_ip.public_ip.id : null
}
}

Related

How can I reference azurerm_subnet which in not declared in the root module?

I have a virtual network with 2 subnets
Virtual network: vNetVPN-Dev
Subnet: snet-vgp-dev
Subnet: snet-internal-vm
resource "azurerm_virtual_network" "virtual_network" {
name = "vNetVPN-Dev"
location = var.resource_group_location_north_europe
resource_group_name = var.resource_group_name
address_space = ["10.1.16.0/23", "10.2.0.0/16", "172.16.100.0/24"]
subnet {
name = "snet-vgp-dev"
address_prefix = "10.2.1.0/24"
}
# =================== Virtual network for vm
subnet {
name = "snet-internal-vm"
address_prefix = "10.2.10.0/24"
}
tags = {
environment = var.tag_dev
}
}
and now I want to reference snet-internal-vm in this block of code (below)
resource "azurerm_network_interface" "nic" {
name = "internal-nic-vm"
location = var.resource_group_location_north_europe
resource_group_name = var.resource_group_name
ip_configuration {
name = "internal-vm"
subnet_id = **here_I_want_to_reference**
private_ip_address_allocation = "Dynamic"
}
}
I tried to reproduce the same in my environment to create NIC creation with Subnet reference:
Terraform Code
provider "azurerm" {
features {}
}
resource "azurerm_virtual_network" "virtual_network" {
name = "vNetVPN-Dev"
location = data.azurerm_resource_group.example.location
resource_group_name = data.azurerm_resource_group.example.name
address_space = ["10.1.16.0/23", "10.2.0.0/16", "172.16.100.0/24"]
subnet {
name = "snet-vgp-dev"
address_prefix = "10.2.1.0/24"
}
subnet {
name = "snet-internal-vm"
address_prefix = "10.2.10.0/24"
}
}
#-----NIC Creation-----------
resource "azurerm_network_interface" "nic" {
name = "internal-nic-vm"
location = data.azurerm_resource_group.example.location
resource_group_name = data.azurerm_resource_group.example.name
ip_configuration {
name = "internal-vm"
subnet_id = azurerm_virtual_network.virtual_network.subnet.*.id[1]
private_ip_address_allocation = "Dynamic"
}
}
Terraform Apply.
As mentioned by #sylvainmtz , I could get subnet referred successfully while creating NIC.
Based on your question, I can only assume you should be using data blocks to do this. https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/data-sources/subnet

Is there a way in Terraform to loop through a given range?

I'm fairly new to Terraform and managed to create a firewall, public IP prefix and public IP's. Now I want to attach 8 public IP's to my firewall. I did it with the code given below, but I think that it can be done shorter. Is there a way how I can code it that it will create an ip configuration while looping through [0-7] with a smaller amount of code?
data "azurerm_public_ip" "firewall_public_ip_address" {
count = 8
name = "firewall-public-ip-address-${var.env_name}-test-${var.region}-${count.index}"
resource_group_name = var.common_resource_group_name
}
resource "azurerm_firewall" "test_firewall" {
name = "firewall-${var.env_name}-test-${var.region}"
resource_group_name = "${var.resource_group_name}"
location = "${var.region}"
ip_configuration {
name = "test-azure-firewall-config-0"
subnet_id = "${var.firewall_subnet_id}"
public_ip_address_id = data.azurerm_public_ip.firewall_public_ip_address[0].id
}
ip_configuration {
name = "test-azure-firewall-config-1"
subnet_id = null
public_ip_address_id = data.azurerm_public_ip.firewall_public_ip_address[1].id
}
ip_configuration {
name = "test-azure-firewall-config-2"
subnet_id = null
public_ip_address_id = data.azurerm_public_ip.firewall_public_ip_address[2].id
}
ip_configuration {
name = "test-azure-firewall-config-3"
subnet_id = null
public_ip_address_id = data.azurerm_public_ip.firewall_public_ip_address[3].id
}
ip_configuration {
name = "test-azure-firewall-config-4"
subnet_id = null
public_ip_address_id = data.azurerm_public_ip.firewall_public_ip_address[4].id
}
ip_configuration {
name = "test-azure-firewall-config-5"
subnet_id = null
public_ip_address_id = data.azurerm_public_ip.firewall_public_ip_address[5].id
}
ip_configuration {
name = "test-azure-firewall-config-6"
subnet_id = null
public_ip_address_id = data.azurerm_public_ip.firewall_public_ip_address[6].id
}
ip_configuration {
name = "test-azure-firewall-config-7"
subnet_id = null
public_ip_address_id = data.azurerm_public_ip.firewall_public_ip_address[7].id
}
You can use Terraform dynamic blocks if all the parameters follow the same pattern (e.g. subnet_id is always var.firewall_subnet_id).
resource "azurerm_firewall" "test_firewall" {
name = "firewall-${var.env_name}-test-${var.region}"
resource_group_name = var.resource_group_name
location = var.region
dynamic "ip_configuration" {
for_each = data.azurerm_public_ip.firewall_public_ip_address
content {
name = ip_configuration.value.name
subnet_id = var.firewall_subnet_id
public_ip_address_id = ip_configuration.value.id
}
}
}

terraform assignment of public IPs to VM's using count meta-argument

im trying to build a script that will build VMs based on count. i have managed to get most of it working, but the part im failing on is assigning the created public Ips to the Nic.
the public ips are created but fail on the assignment, im not sure on how to parse correctly. Code and errors.
# Create public IPs
resource "azurerm_public_ip" "myterraformpublicip" {
count = 2
name = "myPublicIP-${count.index + 1}"
location = "westeurope"
resource_group_name = azurerm_resource_group.myterraformgroup.name
allocation_method = "Dynamic"
}
# Create network interface
resource "azurerm_network_interface" "myterraformnic" {
count = 2
name = "myNIC-${count.index + 1}"
location = "westeurope"
resource_group_name = azurerm_resource_group.myterraformgroup.name
ip_configuration {
name = "myNicConfiguration"
subnet_id = azurerm_subnet.myterraformsubnet.id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = "azurerm_network_interface.myterraformpublicip.[count.index + 1].id"
}
}
#The error when running the plan.
Error: Can not parse "ip_configuration.0.public_ip_address_id" as a
resource id: Cannot parse Azure ID: parse
"element(azurerm_network_interface.myterraformpublicip.*.id,
count.index + 1)": invalid URI for request
You can use something like below for your requirement:
provider "azurerm" {
features{}
}
data "azurerm_resource_group" "test" {
name = "yourresourcegroup"
}
resource "azurerm_virtual_network" "vnet" {
name = "ansuman--vnet"
location = data.azurerm_resource_group.test.location
resource_group_name = data.azurerm_resource_group.test.name
address_space = ["10.0.0.0/16"]
}
variable "subnet_prefix" {
type = list
default = [
{
ip = "10.0.1.0/24"
name = "subnet-1"
},
{
ip = "10.0.2.0/24"
name = "subnet-2"
}
]
}
resource "azurerm_subnet" "test_subnet" {
name = "${lookup(element(var.subnet_prefix, count.index), "name")}"
count = "${length(var.subnet_prefix)}"
resource_group_name = data.azurerm_resource_group.test.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefix = "${lookup(element(var.subnet_prefix, count.index), "ip")}"
}
resource "azurerm_public_ip" "myterraformpublicip" {
count = 2
name = "myPublicIP-${count.index + 1}"
location = data.azurerm_resource_group.test.location
resource_group_name = data.azurerm_resource_group.test.name
allocation_method = "Dynamic"
}
# Create network interface
resource "azurerm_network_interface" "myterraformnic" {
count = 2
name = "myNIC-${count.index + 1}"
location = data.azurerm_resource_group.test.location
resource_group_name = data.azurerm_resource_group.test.name
ip_configuration {
name = "myNicConfiguration"
subnet_id = azurerm_subnet.test_subnet[count.index].id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.myterraformpublicip[count.index].id
}
}
Outputs:

How do i connect an azure vm network interface into an azure load balancer address pool?

I have some code which makes multiple vms I'm trying dynamically add them to the load balancer address pool but I'm met with the following error which I have no idea what it means, any help will be appreciated as the error appears to be somewhat obscure
Error: Error: IP Configuration "azure_network_interface_address_pool_association" was not found on Network Interface "client_host_nic-0" (Resource Group "client_rg")
on vm2.tf line 99, in resource "azurerm_network_interface_backend_address_pool_association" "network_interface_backend_address_pool_association":
99: resource "azurerm_network_interface_backend_address_pool_association" "network_interface_backend_address_pool_association" {
vm2.tf file includes
# Create virtual machine
resource "azurerm_network_interface" "client_nics" {
count = var.node_count
name = "client_host_nic-${count.index}"
location = var.resource_group_location
resource_group_name = module.network.azurerm_resource_group_client_name
# network_security_group_id = module.network.bastion_host_network_security_group
ip_configuration {
name = "client_host_nic"
subnet_id = module.network.client_subnet_id
private_ip_address_allocation = "Dynamic"
# public_ip_address_id = module.network.bastion_host_puplic_ip_address #optional field we have a bastion host so no need for public IP also its vnet peered so this adds an extra layer of securit in a way
}
tags = {
environment = "Production"
}
}
# Generate random text for a unique storage account name
resource "random_id" "randomId_Generator" {
keepers = {
# Generate a new ID only when a new resource group is defined
resource_group = var.resource_group_location
}
byte_length = 8
}
# Create storage account for boot diagnostics
resource "azurerm_storage_account" "client_storageaccount" {
name = "diag${random_id.randomId_Generator.hex}"
resource_group_name = module.network.azurerm_resource_group_client_name
location = var.resource_group_location
account_tier = "Standard"
account_replication_type = "LRS"
tags = {
environment = "Production"
}
}
resource "azurerm_virtual_machine" "node" {
count = var.node_count
name = "client-host-${count.index}"
location = var.resource_group_location
resource_group_name = module.network.azurerm_resource_group_client_name
network_interface_ids = ["${element(azurerm_network_interface.client_nics.*.id, count.index)}"]
# Uncomment this line to delete the OS disk automatically when deleting the VM
delete_os_disk_on_termination = true
# Uncomment this line to delete the data disks automatically when deleting the VM
delete_data_disks_on_termination = true
# 1 vCPU, 3.5 Gb of RAM
vm_size = var.machine_type
storage_os_disk {
name = "myOsDisk-${count.index}"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Premium_LRS"
}
storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "18.04-LTS"
version = "latest"
}
os_profile {
computer_name = "Production"
admin_username = "azureuser"
}
os_profile_linux_config {
disable_password_authentication = true
ssh_keys {
path = "/home/azureuser/.ssh/authorized_keys" #This cannot be changed as mentioned in https://www.terraform.io/docs/providers/azurerm/r/virtual_machine.html
key_data = file("~/.ssh/client.pub")
}
}
boot_diagnostics {
enabled = "true"
storage_uri = azurerm_storage_account.client_storageaccount.primary_blob_endpoint
}
tags = {
environment = "Production"
}
}
resource "azurerm_network_interface_backend_address_pool_association" "network_interface_backend_address_pool_association" {
count = var.node_count
network_interface_id = element(azurerm_network_interface.client_nics.*.id, count.index) #fixes interpolation issues
ip_configuration_name = "azure_network_interface_address_pool_association"
backend_address_pool_id = module.loadbalancer.azure_backend_pool_id
}
load balancer module main.tf file
#rember when using this module to call the network module for the resource group name
############## load balancer section ##############
resource "azurerm_public_ip" "azure_load_balancer_IP" {
name = "azure_load_balancer_IP"
location = var.resource_group_location
resource_group_name = var.resource_group_name
allocation_method = "Static"
}
resource "azurerm_lb" "azure_load_balancer" {
name = "TestLoadBalancer"
location = var.resource_group_location
resource_group_name = var.resource_group_name
frontend_ip_configuration {
name = "front_end_IP_configuration_for_azure_load_balancer"
public_ip_address_id = azurerm_public_ip.azure_load_balancer_IP.id
}
}
resource "azurerm_lb_backend_address_pool" "backend_address_pool" {
resource_group_name = var.resource_group_name
loadbalancer_id = azurerm_lb.azure_load_balancer.id
name = "BackEndAddressPool"
}
resource "azurerm_lb_rule" "azure_lb_rule" {
resource_group_name = var.resource_group_name
loadbalancer_id = azurerm_lb.azure_load_balancer.id
name = "LBRule"
protocol = "Tcp"
frontend_port = 80
backend_port = 80
frontend_ip_configuration_name = "front_end_IP_configuration_for_azure_load_balancer"
}
output.tf
output "azure_load_balancer_ip" {
value = azurerm_public_ip.azure_load_balancer_IP.id
}
output "azure_backend_pool_id" {
value = azurerm_lb_backend_address_pool.backend_address_pool.id
}
additional information
* provider.azurerm: version = "~> 2.1"
main.tf
module "loadbalancer" {
source = "./azure_load_balancer_module" #this may need to be a different git repo as we are not referencing branches here only the master
resource_group_name = module.network.azurerm_resource_group_client_name
resource_group_location = var.resource_group_location
}
The error means the Ipconfiguration name you set for the network interface is not the same as you set for the resource azurerm_network_interface_backend_address_pool_association. You can take a look at the description for ip_configuration_name here. And as I see, you want to associate multiple interfaces with the load balancer.
So I recommend you change the network interface and the association like this:
resource "azurerm_network_interface" "client_nics" {
count = var.node_count
name = "client_host_nic-${count.index}"
location = var.resource_group_location
resource_group_name = module.network.azurerm_resource_group_client_name
# network_security_group_id = module.network.bastion_host_network_security_group
ip_configuration {
name = "client_host_nic-${count.index}"
subnet_id = module.network.client_subnet_id
private_ip_address_allocation = "Dynamic"
# public_ip_address_id = module.network.bastion_host_puplic_ip_address #optional field we have a bastion host so no need for public IP also its vnet peered so this adds an extra layer of securit in a way
}
tags = {
environment = "Production"
}
}
resource "azurerm_network_interface_backend_address_pool_association" "network_interface_backend_address_pool_association" {
count = var.node_count
network_interface_id = element(azurerm_network_interface.client_nics.*.id, count.index) #fixes interpolation issues
ip_configuration_name = "client_host_nic-${count.index}"
backend_address_pool_id = module.loadbalancer.azure_backend_pool_id
}
I believe this was a bug with the azure 2.1 terraform provider and seems to have been fixed in version 2.33 according to upstream https://github.com/terraform-providers/terraform-provider-azurerm/issues/3794

Azure Multi regions deployement error for count.index many times

I am trying to have the simplest terraform script to deply 6 linux vm's in 6 different Azure Regions, However, my concept doesnt seem to work, and I am not sure how to go from there.
I get this error at multiple places:
Error: Reference to "count" in non-counted context
on main.tf line 4, in resource "azurerm_resource_group" "mygroup":
4: location = "${var.regions[count.index]}"
The "count" object can be used only in "resource" and "data" blocks, and only
when the "count" argument is set.
If I just put a string in place of the specified location, I just get more errors like this, at other places.
I wrote some terraform code and tried to validate it using terraform executable.
My variables.tf file:
variable “regions” {
description = “Regions to deploy”
type = list
default = [“canadaeast”, “eastus”, “japaneast”, “ukwest”, “southeastasia”, “germanynorth”]
}
variable “name” {
description = “name”
type = list
default = [“albert”, “ben”, “carol”, “denis”, “eric”, “frank”]
}
and my main.tf file:
# Create a resource group
resource "azurerm_resource_group" "mygroup" {
name = "RG-MyVMs"
location = "${var.regions[count.index]}"
}
# Create virtual network
resource "azurerm_virtual_network" "mynetwork" {
name = "myVnet-${var.name[count.index]}"
address_space = ["10.0.0.0/16"]
location = "${var.regions[count.index]}"
resource_group_name = "${azurerm_resource_group.mygroup.name}"
}
# Create subnet
resource "azurerm_subnet" "mysubnet" {
name = "mySubnet-${var.name[count.index]}"
resource_group_name = "${azurerm_resource_group.mygroup.name}"
virtual_network_name = "${azurerm_virtual_network.mynetwork.name}"
address_prefix = "10.0.1.0/24"
}
# Create public IPs
resource "azurerm_public_ip" "mypublicip" {
name = "myPublicIP"
location = "${var.regions[count.index]}"
resource_group_name = "${azurerm_resource_group.mygroup.name}"
allocation_method = "Dynamic"
}
# Create Network Security Group and rule
resource "azurerm_network_security_group" "mynsg" {
name = "myNetworkSecurityGroup"
location = "${var.regions[count.index]}"
resource_group_name = "${azurerm_resource_group.mygroup.name}"
security_rule {
name = "SSH"
priority = 1001
direction = "Inbound"
access = "Allow"
protocol = "Tcp"
source_port_range = "*"
destination_port_range = "22"
source_address_prefix = "*"
destination_address_prefix = "*"
}
}
# Create network interface
resource "azurerm_network_interface" "mynic" {
name = "myNIC"
location = "${var.regions[count.index]}"
resource_group_name = "${azurerm_resource_group.mygroup.name}"
network_security_group_id = "${azurerm_network_security_group.mynsg.id}"
ip_configuration {
name = "myNicConfiguration"
subnet_id = "${azurerm_subnet.mysubnet.id}"
private_ip_address_allocation = "Dynamic"
public_ip_address_id = "${azurerm_public_ip.mypublicip.id}"
}
}
# Create virtual machine
resource "azurerm_virtual_machine" "myvm" {
count = "${length(var.regions)}"
name = "${var.name[count.index]}"
location = "${var.regions[count.index]}"
resource_group_name = "${azurerm_resource_group.mygroup.name}"
network_interface_ids = ["${azurerm_network_interface.mynic.id}"]
vm_size = "Standard_B1ls"
storage_os_disk {
name = "myOsDisk"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}
storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "18.04.0-LTS"
version = "latest"
}
os_profile {
computer_name = "${var.name[count.index]}"
admin_username = "admin"
admin_password = ""
}
os_profile_linux_config {
disable_password_authentication = false
}
}
I am expected to achieve my goals and validate this code before trying to deploy.

Resources