Skip to content

10.3 Network Interfaces

Overview

Network Interfaces (NICs) connect virtual machines to the virtual network. This configuration creates two NICs, one for each VM, and associates them with the load balancer's backend pool.

Public IP Address

Terraform Configuration

resource "azurerm_public_ip" "example" {
  name                = var.public_ip_name
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name
  allocation_method   = "Static"
  sku                 = "Standard"
}

Key Properties

  • name: Configurable via variable (default: "test-public-ip")
  • allocation_method: "Static" - IP address doesn't change
  • sku: "Standard" - Required for Standard Load Balancer

Static vs Dynamic IP

Type Use Case Behavior
Static Production, Load Balancers IP never changes, even when stopped
Dynamic Development, Testing IP may change when VM is deallocated

Why Static?: The load balancer needs a consistent public IP address for DNS and client connections.

Network Interface Creation

Terraform Configuration

resource "azurerm_network_interface" "example" {
  count               = 2
  name                = "${var.network_interface_name}${count.index}"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name

  ip_configuration {
    name                          = "ipconfig${count.index}"
    subnet_id                     = azurerm_subnet.example.id
    private_ip_address_allocation = "Dynamic"
    primary                       = true
  }
}

Understanding the Count Parameter

count = 2

This creates two identical NICs with indices 0 and 1: - test-nic0 (for VM 0) - test-nic1 (for VM 1)

IP Configuration Breakdown

Property Value Description
name ipconfig${count.index} ipconfig0, ipconfig1
subnet_id Reference to subnet Connects to 10.0.1.0/24
private_ip_address_allocation "Dynamic" Azure assigns IP from subnet
primary true This is the primary IP config

Private IP Assignment

With dynamic allocation, Azure automatically assigns IPs from the subnet range: - NIC 0 might get: 10.0.1.4 - NIC 1 might get: 10.0.1.5

(Remember: 10.0.1.0-10.0.1.3 are reserved by Azure)

Backend Pool Association

Terraform Configuration

resource "azurerm_network_interface_backend_address_pool_association" "example" {
  count                   = 2
  network_interface_id    = azurerm_network_interface.example[count.index].id
  ip_configuration_name   = "ipconfig${count.index}"
  backend_address_pool_id = azurerm_lb_backend_address_pool.example.id
}

What This Does

This resource connects each NIC to the load balancer's backend pool:

Load Balancer Backend Pool
        ↓
    ┌───┴───┐
    ↓       ↓
  NIC 0   NIC 1
    ↓       ↓
  VM 0    VM 1

Key Properties

  • count: Creates 2 associations (one per NIC)
  • network_interface_id: References each NIC using array notation [count.index]
  • ip_configuration_name: Must match the IP config name in the NIC
  • backend_address_pool_id: References the load balancer's backend pool

Variables

variable "public_ip_name" {
  type        = string
  default     = "test-public-ip"
  description = "Name of the Public IP."
}

variable "network_interface_name" {
  type        = string
  default     = "test-nic"
  description = "Name of the Network Interface."
}

Network Flow

Inbound Traffic (Internet → VMs)

Internet
    ↓
Public IP (Static)
    ↓
Load Balancer
    ↓
Backend Pool
    ↓
┌───┴───┐
↓       ↓
NIC 0   NIC 1
↓       ↓
VM 0    VM 1

Outbound Traffic (VMs → Internet)

VM 0 / VM 1
    ↓
NIC 0 / NIC 1
    ↓
Subnet
    ↓
Load Balancer (Outbound Rule)
    ↓
Public IP
    ↓
Internet

Resource Dependencies

azurerm_subnet.example
        ↓
azurerm_network_interface.example[0]
azurerm_network_interface.example[1]
        ↓
azurerm_network_interface_backend_address_pool_association.example[0]
azurerm_network_interface_backend_address_pool_association.example[1]

Azure CLI Verification

List Network Interfaces

az network nic list \
  --resource-group <resource-group-name> \
  --output table

Show NIC Details

az network nic show \
  --resource-group <resource-group-name> \
  --name test-nic0 \
  --output json

View IP Configuration

az network nic ip-config list \
  --resource-group <resource-group-name> \
  --nic-name test-nic0 \
  --output table

Check Public IP

az network public-ip show \
  --resource-group <resource-group-name> \
  --name test-public-ip \
  --output json

# Get just the IP address
az network public-ip show \
  --resource-group <resource-group-name> \
  --name test-public-ip \
  --query ipAddress \
  --output tsv

Advanced Configurations

Static Private IP Addresses

If you need specific private IPs:

resource "azurerm_network_interface" "example" {
  count               = 2
  name                = "${var.network_interface_name}${count.index}"
  location            = azurerm_resource_group.example.location
  resource_group_name = azurerm_resource_group.example.name

  ip_configuration {
    name                          = "ipconfig${count.index}"
    subnet_id                     = azurerm_subnet.example.id
    private_ip_address_allocation = "Static"
    private_ip_address            = "10.0.1.${count.index + 10}"  # 10.0.1.10, 10.0.1.11
    primary                       = true
  }
}

Multiple IP Configurations

For multi-homed scenarios:

ip_configuration {
  name                          = "ipconfig-primary"
  subnet_id                     = azurerm_subnet.example.id
  private_ip_address_allocation = "Dynamic"
  primary                       = true
}

ip_configuration {
  name                          = "ipconfig-secondary"
  subnet_id                     = azurerm_subnet.example.id
  private_ip_address_allocation = "Dynamic"
  primary                       = false
}

Accelerated Networking

For better performance (requires supported VM sizes):

resource "azurerm_network_interface" "example" {
  count                         = 2
  name                          = "${var.network_interface_name}${count.index}"
  location                      = azurerm_resource_group.example.location
  resource_group_name           = azurerm_resource_group.example.name
  enable_accelerated_networking = true  # Add this line

  ip_configuration {
    name                          = "ipconfig${count.index}"
    subnet_id                     = azurerm_subnet.example.id
    private_ip_address_allocation = "Dynamic"
    primary                       = true
  }
}

Common Issues and Solutions

Issue: NIC Already Attached

Error: "Network interface is already attached to a virtual machine"

Solution: Detach from VM before modifying or deleting

az vm nic remove \
  --resource-group <resource-group-name> \
  --vm-name <vm-name> \
  --nics <nic-name>

Issue: Backend Pool Association Fails

Error: "Backend address pool not found"

Solution: Ensure load balancer and backend pool are created first. Check dependencies in Terraform.

Issue: IP Address Conflict

Error: "IP address is already in use"

Solution: Use dynamic allocation or choose a different static IP

Best Practices

  1. Use Dynamic IPs: Unless you have a specific reason for static private IPs
  2. Standard SKU: Always use Standard SKU for production load balancers
  3. Naming Convention: Use consistent naming with indices (nic0, nic1)
  4. Accelerated Networking: Enable for production workloads with supported VM sizes
  5. NSG Association: Can be applied at NIC level or subnet level (subnet is simpler)

Security Considerations

  • NICs inherit NSG rules from the subnet
  • Can apply additional NSG directly to NIC for more granular control
  • Public IPs should only be on load balancers, not individual VMs
  • Use Azure Bastion or VPN for management access instead of public IPs on VMs

Next Steps

Proceed to 10.4-Virtual-Machines-Setup.md to configure the virtual machines that will use these network interfaces.