Use multiple public IP addresses in Azure VM
Sometimes multiple external IP address on an Azure Virtual Machine (VM) are needed for a deployed application or script. We will setup a multi NIC VM with one public IP per interface and route some traffic through different interfaces.
Table of Contents
- Arm Template
- Use multiple NICs with Ubuntu
Azure has support for multiple network interface cards (NICs) as well as multiple public IP address resources for quite some time now. The number of NICs that can be attached to a VM depends on the SKU aka size aka badge of the VM. As we will deploy a template with 4 NICs, we will use a DS3v2 from the DSv2-series, as this is one of the sizes, where you can attach 4 NICs to a VM with 4 cores and have enough compute power. The limitations regarding the number of NICs are listed on the Microsoft Docs for the corresponding SKU, here are the ones for the DSv2-series:
|Size||vCPU||Memory: GiB||…||Max NICs / Expected network bandwidth (Mbps)|
|Standard_DS1_v2||1||3.5||…||2 / 750|
|Standard_DS2_v2||2||7||…||2 / 1500|
|Standard_DS3_v2||4||14||…||4 / 3000|
|Standard_DS4_v2||8||28||…||8 / 6000|
|Standard_DS5_v2||16||56||…||8 / 12000|
We will create the following resources using our ARM template:
- A new VNET (you can of course use your own existing one, just see the ARM quickstart repo for references)
- n public IP addresses
- n network interface
- A virtual machine that uses all the above resources
Let’s start with the basics. We need some parameters and some variables. For the sake of simplicity, we will not parameterize things like VNET reference or subnet prefix.
The variables are quite simplistic. We create the name of the VNET from the
vmName parameter and create the variables for the most current version of Ubuntu 19.04 from the Azure marketplace.
If you want to know how to find the designated version or offer, Azure Docs has you covered!
As we want to be able to change how many NICs are deployed, we will use the
copy object of ARM templates. This object helps us to deploy multiple instances of a specific resource without duplicating the resource block. A resource, using the
copy property looks like this:
Here, we use the
copyIndex() function to access the current index of enumeration to generate the name of the public IP address.
We will use resource iteration with the copy object for public IP addresses and network interfaces.
In the below example, we use the
copyIndex() function to generate the
ipConfigurations property for the NICs.
With multiple NICs attached to a VM, there has to be one network interface that is marked as primary. To take this into consideration, we compare the current
copyIndex with 0 and if the index is greater than 0, the value is set to true. In other words, the first NIC is the primary one, all following will be set as secondary.
The copy object becomes really useful, when used at a property level. So if we want to have multiple data disks deployed with a VM or like in our example multiple NICs attached, we can also use the
There is just one very important difference, we have to create a new “nested” copy object and refence to it by using the name as a parameter in the
In line 2 we create a new copy object, but this time as an array object. The parameters
count are the same as before and in addition the
input property contains the block of ARM code that needs to be iterated.
As mentioned before, we have to use the name of the
copy object, when getting the current iteration. This happens with
copyIndex('networkInterfaces') in line 7 and 9.
If we want to use the multiple IP addresses for internet access, we have to adjust the routing a little bit. We basically set multiple standard gateways with different priorities and let the application that uses the network decide which interface to use. By default the one with the lowest priority will be used. I have configured the routes as follows:
ip route add default via 10.0.0.1 dev eth1 metric 101
The routes should look something like this afterwards:
root@proxyVm:/home/proxyVmadm# ip route show
After a VM restart, the routes will reset. To persist the routes, add them to the
/etc/network/interfaces file (Ubuntu) or
Now let’s see, if all external interfaces are operational by using curl and ipify.org to determine our current external ip address:
To reduce complexity, this template does not contain a Network Security Group (NSG). Keep in mind that the VM will be reachable over all public ip from the internet. If you don’t want inbound connectivity at all or just for one interface, create and configure a nsg. Never leave a VM exposed to the public internet without a good reason (ADFS, honeypot, etc.).
You can find the full ARM template example on Github (truncated preview):
I hope this post helped explaining the possibilities of the copy object and how to use multiple external IPs in Azure. Like always, share the post if you like it and feel free to update and use the snippets in you own scripts 😉