Friday, March 19, 2021

Transitive Routing in Azure VNet Peering using Ubuntu VM IP Forwarder

8 min to read.


Transitive routing requirement is common reality in every “Enterprise Grade” Azure Implementation!

Simplest way to connect two Azure VNet is to use Azure Vnet Peering. If I have 3 VNETs peered with each other; example A <> B <> C. I want Azure VM in A Vnet to talk to Azure VM in C Vnet then it wont work; because A and C VNet are not peered directly to each other; but through B Vnet.

Fact that VM in A vnet not able to reach VM in C Vnet is called as “Transitive Routing Problem”.

How do I solve it?

There are many solutions. Simplest way to solve transitive VNET peering problem would be, to create an “IP Forwarder using Azure Ubuntu VM” in B Vnet.

Let’s start!

Problem statement in detail

As you can see in above diagram I have 3 Azure Virtual Networks named as

1.      ContosoDC VNET

2.      UbuntuFwVNET  - you can also name it as Transit VNET.

3.      ContosoServer VNET

I have provisioned subnets as shown in the diagram. All VNETs are peered bi-directional as described below –

1.      Contoso Dc VNET < peered to> Transit VNET

2.      Contoso Server VNET < peered to> Transit VNET

Azure VNET Peering is bidirectional. Needless to say, if Contoso DC VNET peered to Transit VNET means; Transit VNET will also require peering to Contoso DC VNET to allow them communicate each other.

However, ContosoServer VNET and ContosoDC VNET are not peered with each other.

Note – None of these VNETs are having VNET Gateway or ExpressRoute Gateway in it. So when you peer make sure you choose None for gateway options as shown below [click to get better view].

I have 2 windows VMS and one Ubuntu VM [with Single NIC] in Transit VNET. One of the windows VM has public IP and rest of the two VMs do not have public IP.

Problem statement - I want to allow RDP from ContosoDCVM [] to ContosoServer VM [].

How to go to unknown destination - User Defined Routes - UDR

ContosoDC and Contoso Server VNET are not peered. This means both VNETs do not know each other’s address ranges.

When from an Azure VNET you want to send traffic to another unknown Azure VNET, you use Azure User Defined Route Tables aka UDR and provide the next hop to an appliance/ VM/ NVA/ Firewall/ Router/ or forwarder which will then take care of sending traffic to correct destination.

In our case the NVA is our ubuntu Azure VM. Therefore from both VNETs we need to send the traffic to Ubuntu VM IP. Then ubuntu VM will eventually DNAT [Destination NAT] the incoming traffic to its correct destination.

UDR on Contoso Server Subnet as below – [click to get better view]

UDR on Contoso DC Subnet as below – [click to get better view]

Configure Ubuntu as IP Forwarder

For this there are two settings. One on Network Interface of Ubuntu VM from Azure portal and one inside the OS of Ubuntu itself.

Go to NIC associated to Ubuntu VM and enable “IP Forwarding” as shown below [click to get better view] -  

Take SSH into Ubuntu VM and run below commands to enable the IP forwarding inside OS.

$ sudo vim /etc/sysctl.conf

Uncomment the below line – [remove #] and then press Esc and type :wq to save the file.


Run below command to confirm if the change is correct – 

$ sudo sysctl -p

This completes the configuration of IP forwarding for Ubuntu VM.

NAT the incoming traffic

NATing is of two types.

Source NAT – SNAT – to be used when you want to change the sender’s address.

Destination NAT – DNAT – to be used when you want to change the destination address.

Example, Web application is hosted on behind the firewall. Firewall VM has public IP and actual application runs on web server which has private IP. In this case, incoming web request reaches to public IP of firewall and get forwarded to web server private IP. This is translation from public IP to private IP. This is DNAT.

In our case we need to perform DNAT as destination is not known to each of the VNET. Only Transit VNET knows both VNETs. Also in our case DNAT will be for private IP to private IP, as there is no public IP in picture here.

DNAT can be achieved using iptables in PREROUTING and POSTROUTING chaining. To know more refer this awesome link -

In our case we need below DNAT chaining –

1.      PREROUTING - If source is then DNAT to

2.      PREROUTING - If source is then DNAT to

3.      POSTROUTING - For all DNAT, use IP address of Ubuntu VM as source

The respective commands are as follows – run it on Ubuntu VM –

$ sudo iptables -t nat -A PREROUTING -i eth0 -p tcp -s --dport 3389 -j DNAT --to-destination

$ sudo iptables -t nat -A PREROUTING -i eth0 -p tcp -s --dport 3389 -j DNAT --to-destination

$ sudo iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

These iptables configuration are not persistent over reboots. So we need to use “iptables-persistent” module to make it happen.

Run below commands – 

$ sudo apt-get update

$ sudo apt install iptables-persistent

On running above command you will have to enter “Yes” twice. This completes the installation of iptables-persistent module.

Then read all iptables configuration we perform and pipe [or copy paste] to rules files. Then add this rules files path in rc.local which eventually will make our iptables configuration persistent over reboot of ubuntu machine. Run below commands – 

$ sudo iptables-save > /etc/iptables/rules.v4

$ sudo vim /etc/rc.local

Add below line in /etc/rc.local file and then save the file by pressing Esc -> :wq.

/sbin/iptables-restore < /etc/iptables/rules.v4

Reboot the machine by typing below command – 

$ sudo reboot

This completes the configuration of iptables and NAT on ubuntu machine. 

Confirm the connectivity

Login to Contoso server VM over public IP. You can leverage Azure Bastion, Jump VM, or any other option for this. After login lets confirm if the traffic is flowing to ContosoDc VM through Ubuntu VM. For this I ran tracert command and output shows that the traffic does flow through ubuntu VM as shown below – [click to get better view] –

Similarly I could see return traffic from ContosoDC VM to ContosoServer VM was flowing through ubuntu VM – [click to get better view]

You should be able to take RDP between the VMs. Post RDP I checked the source in event viewer of both windows VM and I could see the source IP as ubuntu IP from which DNAT occurs.

Source IP of RDP can be viewed from below path in Event viewer - Event Viewer > Applications and Services Logs > Microsoft > Windows > TerminalServices-LocalSessionManager > Operational

Screenshot of ContosoDc machines – [click to get better view]

This concludes how an Azure Ubuntu VM can be configured as “IP Forwarder” to achieve Transitive routing in Azure VNET Peering.

What are the other ways to achieve transitive routing in Azure VNet peering?

What we did with Ubuntu is, we built IP forwarding out of it from scratch. This is readily available with leading firewall and routing devices such as PaloAlto, CheckPoint, Barracuda etc. The only difference is those devices will come with licenses cost. Ubuntu VM we built does not incur any licenses cost.

How to achieve Transitive routing in peered VNet using Azure Firewall?

This possible using Azure Firewall.

Deploy Azure firewall in Transit VNET. You just need to allow traffic from ContosoDC to Contoso Server VNET and vice versa as a Firewall Network rule. Configure the UDR on both VNETs with next hop to Firewall private IP and you are done.


Hope this article helped to design IP forwarder using simple Azure Ubuntu VM to solve your Transitive Routing needs.

Happy Peering!!

A humble request!

Internet is creating a lot of digital garbage. If you feel this a quality blog and someone will definitely get benefited, don't hesitate to hit share button present below. Your one share will save many precious hours of a developer. Thank you.

Next Related Posts

Transitive Routing with 4 VNETs and Azure Firewall

Azure Virtual Machines – real world frequently asked questions – not easily answered.

Azure Migration frequently asked questions, not easily answered!

Azure VM disk encryption, what should be my approach!

Bypass onpremises firewall to RDP or SSH into Azure VM