Terraform private azure load balancer issue - azure

Iam trying to deploy an infrastructure with a private loadbalancer:
.....
resource "azurerm_lb" "private" {
name = "${var.name}-${var.live}-private-lb"
location = data.azurerm_resource_group.rg.location
resource_group_name = data.azurerm_resource_group.rg.name
sku = var.sku
frontend_ip_configuration {
name = "frontend"
subnet_id = var.subnet_id != "" ? var.subnet_id : null
private_ip_address = (var.subnet_id != "" && var.private_ip != "") ? var.private_ip : null
private_ip_address_allocation = var.subnet_id != "" ? (var.subnet_id == "" ? "Static" : "Dynamic") : null
}
}
......
But i got the error message :
..../frontendIPConfigurations/frontend must reference either a Subnet, Public IP Address or Public IP Prefix." Details=[]
Why and how can i tackle this issue ? I don't know which configuration is missing.
thanks

An internal Load Balancer differs from a public Load Balancer, it has been assigned to a subnet and does not have a public IP address. As the error displayed, the frontend should reference either a Subnet, Public IP Address or Public IP Prefix, and the subnet should have existed when you reference. You could use the data source subnet to access information about an existing resource or create your subnet and VNet for your load balancer.
For example, the following can work for me.
data "azurerm_resource_group" "rg" {
name = "mytestrg"
}
variable "sku" {
default = "basic"
}
variable "private_ip" {
default = "172.19.0.100"
}
variable "env" {
default="Static"
}
data "azurerm_subnet" "test" {
name = "default"
virtual_network_name = "vnet1"
resource_group_name = "${data.azurerm_resource_group.rg.name}"
}
resource "azurerm_lb" "test" {
name = "mytestlb"
location = "${data.azurerm_resource_group.rg.location}"
resource_group_name = "${data.azurerm_resource_group.rg.name}"
sku = "${var.sku}"
frontend_ip_configuration {
name = "frontend"
subnet_id = "${data.azurerm_subnet.test.id}"
private_ip_address = "${var.env=="Static"? var.private_ip: null}"
private_ip_address_allocation = "${var.env=="Static"? "Static": "Dynamic"}"
}
}

Related

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
}

Create azure application gateway with static private ip address via terraform

I can't find a way to create an application gateway via terraform with private IP without manually inserting hard coded IP private address.
I tried:
Create a private IP in the application gateway subnet - failed because Azure blocks (attached error from the UI, but terraform raises the same error) it
Create a dynamic private IP in the application gateway subnet - Failed
Only when creating an application gateway with hard coded ip address it works.
This solution is not good enough for me because we handle many environents and we don't want to relay on developers to remember adding a private IP.
Is there a good solution?
Application Gateway v2 SKU supports the static VIP type exclusively, whereas the V1 SKU can be configured to support static or dynamic internal IP address and dynamic public IP address.
Refer: Application Gateway frontend-ip-addresses
Application Gateway V2 currently does not support only private IP mode. The Azure Application Gateway V2 SKU can be configured to support either both static internal IP address and static public IP address, or only static public IP address. It cannot be configured to support only static internal IP address.
Refer: Application gateway v2 with only private-ip
While deploying using terraform, we should define two frontend_ip_configuration blocks, one is used for public IP configuration, another is used for private IP configuration.
Scenario 1: When trying to create a new application gateway with dynamic private IP and dynamic public IP using terraform it gets created for Standard or V1 SKU only.
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 2.65"
    }
  }
  required_version = ">= 0.14.9"
}
provider "azurerm" {
  features {}
}
resource "azurerm_resource_group" "test" {
  name     = "Terraformtest"
  location = "West Europe"
}
resource "azurerm_virtual_network" "test" {
  name                = "terraformvnet"
  resource_group_name = azurerm_resource_group.test.name
  location            = azurerm_resource_group.test.location
  address_space       = ["10.254.0.0/16"]
}
resource "azurerm_subnet" "frontend" {
  name                 = "frontend"
  resource_group_name  = azurerm_resource_group.test.name
  virtual_network_name = azurerm_virtual_network.test.name
  address_prefixes     = ["10.254.0.0/24"]
}
resource "azurerm_subnet" "backend" {
  name                 = "backend"
  resource_group_name  = azurerm_resource_group.test.name
  virtual_network_name = azurerm_virtual_network.test.name
  address_prefixes     = ["10.254.2.0/24"]
}
resource "azurerm_public_ip" "test" {
  name                = "test-pip"
  resource_group_name = azurerm_resource_group.test.name
  location            = azurerm_resource_group.test.location
  allocation_method   = "Dynamic"
}
locals {
  backend_address_pool_name      = "${azurerm_virtual_network.test.name}-beap"
  frontend_port_name             = "${azurerm_virtual_network.test.name}-feport"
  frontend_ip_configuration_name = "${azurerm_virtual_network.test.name}-feip"
  http_setting_name              = "${azurerm_virtual_network.test.name}-be-htst"
  listener_name                  = "${azurerm_virtual_network.test.name}-httplstn"
  request_routing_rule_name      = "${azurerm_virtual_network.test.name}-rqrt"
  redirect_configuration_name    = "${azurerm_virtual_network.test.name}-rdrcfg"
}
resource "azurerm_application_gateway" "network" {
  name                = "test-appgateway"
  resource_group_name = "${azurerm_resource_group.test.name}"
  location            = "${azurerm_resource_group.test.location}"
  sku {
    name     = "Standard_Small"
    tier     = "Standard"
    capacity = 2
  }
  gateway_ip_configuration {
    name      = "my-gateway-ip-configuration"
    subnet_id = "${azurerm_subnet.frontend.id}"
  }
  frontend_port {
    name = "${local.frontend_port_name}"
    port = 80
  }
  frontend_ip_configuration {
    name                 = "${local.frontend_ip_configuration_name}"
    public_ip_address_id = "${azurerm_public_ip.test.id}"
  }
 frontend_ip_configuration {
    name                 = "${local.frontend_ip_configuration_name}-private"
    subnet_id = "${azurerm_subnet.frontend.id}"
    private_ip_address_allocation = "Dynamic"
  }
  backend_address_pool {
    name = "${local.backend_address_pool_name}"
  }
  backend_http_settings {
    name                  = "${local.http_setting_name}"
    cookie_based_affinity = "Disabled"
    path                  = "/path1/"
    port                  = 80
    protocol              = "Http"
    request_timeout       = 1
  }
  http_listener {
    name                           = "${local.listener_name}"
    frontend_ip_configuration_name = "${local.frontend_ip_configuration_name}-private"
    frontend_port_name             = "${local.frontend_port_name}"
    protocol                       = "Http"
  }
  request_routing_rule {
    name                       = "${local.request_routing_rule_name}"
    rule_type                  = "Basic"
    http_listener_name         = "${local.listener_name}"
    backend_address_pool_name  = "${local.backend_address_pool_name}"
    backend_http_settings_name = "${local.http_setting_name}"
  }
}
Scenario 2: While creating a Standard V2 we can create a private IP but it doesn’t support dynamic allocation yet so it must be static, and you must mention the IP address you want to use. and to use that you must select standard sku for public IP and static IP address allocation for public as well.
z
So, after updating private_ip_address_allocation = "Static" and private_ip_address = "10.254.0.10" it will get created successfully.
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 2.65"
}
}
required_version = ">= 0.14.9"
}
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "test" {
name = "Terraformtest"
location = "West Europe"
}
resource "azurerm_virtual_network" "test" {
name = "terraformvnet"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
address_space = ["10.254.0.0/16"]
}
resource "azurerm_subnet" "frontend" {
name = "frontend"
resource_group_name = azurerm_resource_group.test.name
virtual_network_name = azurerm_virtual_network.test.name
address_prefixes = ["10.254.0.0/24"]
}
resource "azurerm_subnet" "backend" {
name = "backend"
resource_group_name = azurerm_resource_group.test.name
virtual_network_name = azurerm_virtual_network.test.name
address_prefixes = ["10.254.2.0/24"]
}
resource "azurerm_public_ip" "test" {
name = "test-pip"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
allocation_method = "Static"
sku = "Standard"
}
locals {
backend_address_pool_name = "${azurerm_virtual_network.test.name}-beap"
frontend_port_name = "${azurerm_virtual_network.test.name}-feport"
frontend_ip_configuration_name = "${azurerm_virtual_network.test.name}-feip"
http_setting_name = "${azurerm_virtual_network.test.name}-be-htst"
listener_name = "${azurerm_virtual_network.test.name}-httplstn"
request_routing_rule_name = "${azurerm_virtual_network.test.name}-rqrt"
redirect_configuration_name = "${azurerm_virtual_network.test.name}-rdrcfg"
}
resource "azurerm_application_gateway" "network" {
name = "test-appgateway"
resource_group_name = "${azurerm_resource_group.test.name}"
location = "${azurerm_resource_group.test.location}"
sku {
name = "Standard_v2"
tier = "Standard_v2"
capacity = 2
}
gateway_ip_configuration {
name = "my-gateway-ip-configuration"
subnet_id = "${azurerm_subnet.frontend.id}"
}
frontend_port {
name = "${local.frontend_port_name}"
port = 80
}
frontend_ip_configuration {
name = "${local.frontend_ip_configuration_name}"
public_ip_address_id = "${azurerm_public_ip.test.id}"
}
frontend_ip_configuration {
name = "${local.frontend_ip_configuration_name}-private"
subnet_id = "${azurerm_subnet.frontend.id}"
private_ip_address_allocation = "Static"
private_ip_address = "10.254.0.10"
}
backend_address_pool {
name = "${local.backend_address_pool_name}"
}
backend_http_settings {
name = "${local.http_setting_name}"
cookie_based_affinity = "Disabled"
path = "/path1/"
port = 80
protocol = "Http"
request_timeout = 1
}
http_listener {
name = "${local.listener_name}"
frontend_ip_configuration_name = "${local.frontend_ip_configuration_name}"
frontend_port_name = "${local.frontend_port_name}"
protocol = "Http"
}
request_routing_rule {
name = "${local.request_routing_rule_name}"
rule_type = "Basic"
http_listener_name = "${local.listener_name}"
backend_address_pool_name = "${local.backend_address_pool_name}"
backend_http_settings_name = "${local.http_setting_name}"
}
}
Note : 2 application gateway cannot use same subnet . So if you are creating a new appgw then you have to create a new subnet.
Can you paste your terraform code?
For the latest terraform version documentation say that block frontend_ip_configuration supports private_ip_address_allocation parameter, which can hold value Dynamic.
Also remember that app gateway has to have a separate network with only application gateway in it. I am not sure, but I suppose that it is gateway per subnet, so 2 gateways in one subnet is impossible.

terraform: add public IP to only one azure VM

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
}
}

Azure The 'resourceTargetId' property of endpoint 'vm1-TF' is invalid or missing

I want to implement traffic manager in Terraform between two vm's from different locations (West Europe and North Europe). I attach my code, but I don't know how to configure "target_resource_id" for each vm, because the vm's were created in a for loop, also the networks. The traffic manager would switch to the secondary vm, in case of failure of the first vm. Any ideas?
My code:
variable "subscription_id" {}
variable "tenant_id" {}
variable "environment" {}
variable "azurerm_resource_group_name" {}
variable "locations" {
type = map(string)
default = {
vm1 = "North Europe"
vm2 = "West Europe"
}
}
# Configure the Azure Provider
provider "azurerm" {
subscription_id = var.subscription_id
tenant_id = var.tenant_id
version = "=2.10.0"
features {}
}
resource "azurerm_virtual_network" "main" {
for_each = var.locations
name = "${each.key}-network"
address_space = ["10.0.0.0/16"]
location = each.value
resource_group_name = var.azurerm_resource_group_name
}
resource "azurerm_subnet" "internal" {
for_each = var.locations
name = "${each.key}-subnet"
resource_group_name = var.azurerm_resource_group_name
virtual_network_name = azurerm_virtual_network.main[each.key].name
address_prefixes = ["10.0.2.0/24"]
}
resource "azurerm_public_ip" "example" {
for_each = var.locations
name = "${each.key}-pip"
location = each.value
resource_group_name = var.azurerm_resource_group_name
allocation_method = "Static"
idle_timeout_in_minutes = 30
tags = {
environment = "dev01"
}
}
resource "azurerm_network_interface" "main" {
for_each = var.locations
name = "${each.key}-nic"
location = each.value
resource_group_name = var.azurerm_resource_group_name
ip_configuration {
name = "testconfiguration1"
subnet_id = azurerm_subnet.internal[each.key].id
private_ip_address_allocation = "Dynamic"
public_ip_address_id = azurerm_public_ip.example[each.key].id
}
}
resource "random_password" "password" {
length = 16
special = true
override_special = "_%#"
}
resource "azurerm_virtual_machine" "main" {
for_each = var.locations
name = "${each.key}t-vm"
location = each.value
resource_group_name = var.azurerm_resource_group_name
network_interface_ids = [azurerm_network_interface.main[each.key].id]
vm_size = "Standard_D2s_v3"
storage_image_reference {
publisher = "Canonical"
offer = "UbuntuServer"
sku = "18.04-LTS"
version = "latest"
}
storage_os_disk {
name = "${each.key}-myosdisk1"
caching = "ReadWrite"
create_option = "FromImage"
managed_disk_type = "Standard_LRS"
}
os_profile {
computer_name = "${each.key}-hostname"
admin_username = "testadmin"
admin_password = random_password.password.result
}
os_profile_linux_config {
disable_password_authentication = false
}
tags = {
environment = "dev01"
}
}
resource "random_id" "server" {
keepers = {
azi_id = 1
}
byte_length = 8
}
resource "azurerm_traffic_manager_profile" "example" {
name = random_id.server.hex
resource_group_name = var.azurerm_resource_group_name
traffic_routing_method = "Priority"
dns_config {
relative_name = random_id.server.hex
ttl = 100
}
monitor_config {
protocol = "http"
port = 80
path = "/"
interval_in_seconds = 30
timeout_in_seconds = 9
tolerated_number_of_failures = 3
}
tags = {
environment = "dev01"
}
}
resource "azurerm_traffic_manager_endpoint" "first-vm" {
for_each = var.locations
name = "${each.key}-TF"
resource_group_name = var.azurerm_resource_group_name
profile_name = "${azurerm_traffic_manager_profile.example.name}"
target_resource_id = "[azurerm_network_interface.main[each.key].id]"
type = "azureEndpoints"
priority = "${[each.key] == "vm1" ? 1 : 2}"
}
My error:
Error: trafficmanager.EndpointsClient#CreateOrUpdate: Failure responding to request: StatusCode=400 -- Original Error: autorest/azure: Service returned an error.
Status=400 Code="BadRequest" Message="The 'resourceTargetId' property of endpoint 'vm1-TF' is invalid or missing.
The property must be specified only for the following endpoint types: AzureEndpoints, NestedEndpoints.
You must have read access to the resource to which it refers."
According to this documentation:
Azure endpoints are used for Azure-based services in Traffic Manager. The following Azure resource types are supported:
PaaS cloud services
Web Apps
Web App Slots
PublicIPAddress resources (which can be connected to VMs either directly or via an Azure Load Balancer). The publicIpAddress must have a DNS name assigned to be used in a Traffic Manager profile.
In your code, you need to change the Target ResourceId to PublicIPAddress. You should not pass the Network Interface ID.
resource "azurerm_traffic_manager_endpoint" "first-vm" {
for_each = var.locations
name = "${each.key}-TF"
resource_group_name = var.azurerm_resource_group_name
profile_name = "${azurerm_traffic_manager_profile.example.name}"
target_resource_id = azurerm_public_ip.example[each.key].id
type = "azureEndpoints"
priority = "${[each.key] == "vm1" ? 1 : 2}"
}
Please Note: The publicIpAddress must have a DNS name assigned to be used in a Traffic Manager profile.
Also you can check this ARM Template which is equivalent to this terraform template.
Hope this helps!

Selecting specific subnet id from virtual network with multiple subnets

I want to reference the id of subnet 2 in another resource block but the subnets don't have an index value. i.e "${azurerm_virtual_network.test.subnet.2.id}" will not work.
resource "azurerm_virtual_network" "test" {
name = "virtualNetwork1"
location = "${azurerm_resource_group.test.location}"
resource_group_name = "${azurerm_resource_group.test.name}"
address_space = ["10.0.0.0/16"]
dns_servers = ["10.0.0.4", "10.0.0.5"]
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"
security_group = "${azurerm_network_security_group.test.id}"
}
}
Solved with the help of Expose ID of an embedded subnet defined in azurerm_virtual_network #1913
...
subnet_id = "${azurerm_virtual_network.test.subnet.*.id[1]}"
...
azurerm_virtual_network.test.subnet.*.id[1]
What has happened here is that * gets all subnets and [1] is pointing to index 2.

Resources