Route network traffic with a route table using the Azure CLI

Azure automatically routes traffic between all subnets within a virtual network, by default. You can create your own routes to override Azure's default routing. The ability to create custom routes is helpful if, for example, you want to route traffic between subnets through a network virtual appliance (NVA). In this article, you learn how to:

  • Create a route table
  • Create a route
  • Create a virtual network with multiple subnets
  • Associate a route table to a subnet
  • Create a basic NVA that routes traffic from an Ubuntu VM
  • Deploy virtual machines (VM) into different subnets
  • Route traffic from one subnet to another through an NVA

If you don't have an Azure subscription, create an Azure free account before you begin.

Prerequisites

  • This article requires version 2.0.28 or later of the Azure CLI. If using Azure Cloud Shell, the latest version is already installed.

Create a route table

Before you can create a route table, create a resource group with az group create for all resources created in this article.

# Create a resource group.
az group create \
  --name myResourceGroup \
  --location eastus

Create a route table with az network route-table create. The following example creates a route table named myRouteTablePublic.

# Create a route table
az network route-table create \
  --resource-group myResourceGroup \
  --name myRouteTablePublic

Create a route

Create a route in the route table with az network route-table route create.

az network route-table route create \
  --name ToPrivateSubnet \
  --resource-group myResourceGroup \
  --route-table-name myRouteTablePublic \
  --address-prefix 10.0.1.0/24 \
  --next-hop-type VirtualAppliance \
  --next-hop-ip-address 10.0.2.4

Associate a route table to a subnet

Before you can associate a route table to a subnet, you have to create a virtual network and subnet. Create a virtual network with one subnet with az network vnet create.

az network vnet create \
  --name myVirtualNetwork \
  --resource-group myResourceGroup \
  --address-prefix 10.0.0.0/16 \
  --subnet-name Public \
  --subnet-prefix 10.0.0.0/24

Create two additional subnets with az network vnet subnet create.

# Create a private subnet.
az network vnet subnet create \
  --vnet-name myVirtualNetwork \
  --resource-group myResourceGroup \
  --name Private \
  --address-prefix 10.0.1.0/24

# Create a DMZ subnet.
az network vnet subnet create \
  --vnet-name myVirtualNetwork \
  --resource-group myResourceGroup \
  --name DMZ \
  --address-prefix 10.0.2.0/24

Associate the myRouteTablePublic route table to the Public subnet with az network vnet subnet update.

az network vnet subnet update \
  --vnet-name myVirtualNetwork \
  --name Public \
  --resource-group myResourceGroup \
  --route-table myRouteTablePublic

Create an NVA

An NVA is a VM that performs a network function, such as routing, firewalling, or WAN optimization. We will create a basic NVA from a general purpose Ubuntu VM, for demonstration purposes.

Create a VM to be used as the NVA in the DMZ subnet with az vm create. When you create a VM, Azure creates and assigns a network interface myVmNvaVMNic and a public IP address to the VM, by default. The --public-ip-address "" parameter instructs Azure not to create and assign a public IP address to the VM, since the VM doesn't need to be connected to from the internet. If SSH keys do not already exist in a default key location, the command creates them. To use a specific set of keys, use the --ssh-key-value option.

az vm create \
  --resource-group myResourceGroup \
  --name myVmNva \
  --image Ubuntu2204 \
  --public-ip-address "" \
  --subnet DMZ \
  --vnet-name myVirtualNetwork \
  --generate-ssh-keys

The VM takes a few minutes to create. Do not continue to the next step until Azure finishes creating the VM and returns output about the VM.

For a network interface myVmNvaVMNic to be able to forward network traffic sent to it, that is not destined for its own IP address, IP forwarding must be enabled for the network interface. Enable IP forwarding for the network interface with az network nic update.

az network nic update \
  --name myVmNvaVMNic \
  --resource-group myResourceGroup \
  --ip-forwarding true

Within the VM, the operating system, or an application running within the VM, must also be able to forward network traffic. We will use the sysctl command to enable the Linux kernel to forward packets. To run this command without logging onto the VM, we will use the Custom Script extension az vm extension set:

az vm extension set \
  --resource-group myResourceGroup \
  --vm-name myVmNva \
  --name customScript \
  --publisher Microsoft.Azure.Extensions \
  --settings '{"commandToExecute":"sudo sysctl -w net.ipv4.ip_forward=1"}'

The command may take up to a minute to execute. Note that this change will not persist after a VM reboot, so if the NVA VM is rebooted for any reason, the script will need to be repeated.

Create virtual machines

Create two VMs in the virtual network so you can validate that traffic from the Public subnet is routed to the Private subnet through the NVA in a later step.

Create a VM in the Public subnet with az vm create. The --no-wait parameter enables Azure to execute the command in the background so you can continue to the next command. To streamline this article, a password is used. Keys are typically used in production deployments. If you use keys, you must also configure SSH agent forwarding. For more information, see the documentation for your SSH client. Replace <replace-with-your-password> in the following command with a password of your choosing.

adminPassword="<replace-with-your-password>"

az vm create \
  --resource-group myResourceGroup \
  --name myVmPublic \
  --image Ubuntu2204 \
  --vnet-name myVirtualNetwork \
  --subnet Public \
  --admin-username azureuser \
  --admin-password $adminPassword \
  --no-wait

Create a VM in the Private subnet.

az vm create \
  --resource-group myResourceGroup \
  --name myVmPrivate \
  --image Ubuntu2204 \
  --vnet-name myVirtualNetwork \
  --subnet Private \
  --admin-username azureuser \
  --admin-password $adminPassword

The VM takes a few minutes to create. After the VM is created, the Azure CLI shows information similar to the following example:

{
  "fqdns": "",
  "id": "/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/myResourceGroup/providers/Microsoft.Compute/virtualMachines/myVmPrivate",
  "location": "eastus",
  "macAddress": "00-0D-3A-23-9A-49",
  "powerState": "VM running",
  "privateIpAddress": "10.0.1.4",
  "publicIpAddress": "13.90.242.231",
  "resourceGroup": "myResourceGroup"
}

Take note of the publicIpAddress. This address is used to access the VM from the internet in a later step.

Route traffic through an NVA

Using an SSH client of your choice, connect to the VMs created above. For example, the following command can be used from a command line interface such as WSL to create an SSH session with the myVmPrivate VM. Replace <publicIpAddress> with the public IP address of your VM. In the example above, the IP address is 13.90.242.231.

ssh azureuser@<publicIpAddress>

When prompted for a password, enter the password you selected in Create virtual machines.

Use the following command to install trace route on the myVmPrivate VM:

sudo apt update
sudo apt install traceroute

Use the following command to test routing for network traffic to the myVmPublic VM from the myVmPrivate VM.

traceroute myVmPublic

The response is similar to the following example:

traceroute to myVmPublic (10.0.0.4), 30 hops max, 60 byte packets
1  10.0.0.4 (10.0.0.4)  1.404 ms  1.403 ms  1.398 ms

You can see that traffic is routed directly from the myVmPrivate VM to the myVmPublic VM. Azure's default routes, route traffic directly between subnets.

Use the following command to SSH to the myVmPublic VM from the myVmPrivate VM:

ssh azureuser@myVmPublic

Use the following command to install trace route on the myVmPublic VM:

sudo apt-get install traceroute

Use the following command to test routing for network traffic to the myVmPrivate VM from the myVmPublic VM.

traceroute myVmPrivate

The response is similar to the following example:

traceroute to myVmPrivate (10.0.1.4), 30 hops max, 60 byte packets
1  10.0.2.4 (10.0.2.4)  0.781 ms  0.780 ms  0.775 ms
2  10.0.1.4 (10.0.0.4)  1.404 ms  1.403 ms  1.398 ms

You can see that the first hop is 10.0.2.4, which is the NVA's private IP address. The second hop is 10.0.1.4, the private IP address of the myVmPrivate VM. The route added to the myRouteTablePublic route table and associated to the Public subnet caused Azure to route the traffic through the NVA, rather than directly to the Private subnet.

Close the SSH sessions to both the myVmPublic and myVmPrivate VMs.

Clean up resources

When no longer needed, use az group delete to remove the resource group and all of the resources it contains.

az group delete --name myResourceGroup --yes

Next steps

In this article, you created a route table and associated it to a subnet. You created a simple NVA that routed traffic from a public subnet to a private subnet. Deploy a variety of pre-configured NVAs that perform network functions such as firewall and WAN optimization from the Azure Marketplace. To learn more about routing, see Routing overview and Manage a route table.

While you can deploy many Azure resources within a virtual network, resources for some Azure PaaS services cannot be deployed into a virtual network. You can still restrict access to the resources of some Azure PaaS services to traffic only from a virtual network subnet though. To learn how, see Restrict network access to PaaS resources.