Deploy Azure Network Address Translation (NAT) Gateway

6 Min. Read

In this article, I will show you how to use the Azure Virtual Network NAT service to create a Network Address Translation (NAT) gateway to provide outbound connectivity for your Azure virtual machines.

Introduction

If you have a VM in Azure that has its own instance public IP when it wants to do outbound communication to the Internet, it will actually use its instance-level public IP, then it gets to the Internet and gets the responses. So, if you have a public IP, it’s going to use that not just to offer services to the Internet, but to get to the Internet as well, because it’s a one-to-one mapping of that public IP.

Now, If you have a load balancer and the load balancer is a standard SKU and has a public IP, then it’s used to receive things from the Internet primarily, but again, virtual machines behind a load balancer will use that to go and get to the Internet.

What about if you just have a VM and it doesn’t have a public IP? Well, then Azure just behind the scenes kind of allocates an IP address and it enables the outbound flow, but you have no control over that. We don’t know what IP it’s going to use, it’ll be hard for us to whitelist a particular service knowing it’s coming from this public IP address. And if you have multiple virtual machines, they all may use that same Public IP that’s just been automatically handled by Azure, so we’ve really no control of that whatsoever.

What if we want a bit more control?

Let’s say, you want to offer services to the Internet from maybe an instance-level public IP or a load balancer with a public IP, but you want to separate the outgoing flow. Now if you use a standard load balancer SKU, there are outbound flows. We do have some control over that, but it’s still a distinct object, and if we use a standard load balancer, we have to plan for scaling, we have to explicitly join the virtual machines to a backend pool, there’s additional work that we have to do, and eventually it will cost me some money.

There is another solution!

To get more control for outgoing flow with zero-touch manageability, there’s a NAT gateway resource. You can use a Virtual Network NAT (network address translation) to simplify outbound-only Internet connectivity for virtual networks. When configured on a subnet, all outbound connectivity uses your specified static public IP addresses or public IP prefixes. Outbound connectivity is possible without a load balancer or public IP addresses directly attached to virtual machines.

NAT gateway is designed to provide outbound functionality only and once I create the NAT gateway, it has either a public IP with standard SKU, or it’s going to be an IP prefix (a set of contiguous public IP addresses).

Then you can use the NAT gateway to link it to a subnet. You can have multiple subnets and link them as well. When you do that, this will now override how things go out to the Internet. So even though you’ve got an instance-level public IP, or you’re behind a standard load balancer as shown in the diagram below, it will NOT use that for outbound connectivity anymore.

Azure Network Address Translation (NAT) Gateway Diagram

Virtual machines will use instance-level public IP or load balancer to receive traffic, but for its outbound flow, it will send it to the NAT gateway. The good thing that the NAT gateway is fully managed and highly resilient so you don’t need to worry about designing the NAT gateway with high availability in mind.

So let’s look at how to automate the deployment of Azure NAT gateway with an ARM template. Please note that you can accomplish the same steps with the Azure Portal, Azure CLI, and Azure PowerShell.

Prerequisites

To follow this article, you need to have the following:

  1. Azure subscription – If you don’t have an Azure subscription, you can create a free one here.
  2. At least one virtual network(s) is deployed with their appropriate IP subnets. Please check the following quickstart guide to create a virtual network.
  3. At least one Azure virtual machine is deployed in the virtual network. Please check the following quickstart guide to create a Windows virtual machine.
  4. Please note that the NAT gateway is not compatible with non-standard SKUs. In other words, if you want to use a load balancer or instance-level public IP with NAT gateway, they should be created with standard SKUs. If you had a basic load balancer, the inbound flow would cease to work, it is not compatible. 

Please note that it’s not required to deploy an Azure load balancer or instance-level public IP, I can use the NAT gateway on its own if I have requirements to control the outbound flow and whitelist a set of public IP(s). Because I know the IP addresses or the IP prefixes for the NAT gateway so I can now go ahead and whitelist these for other services that it may be trying to access.

Deploy Azure NAT gateway

Assume you have all the prerequisites in place, copy the ARM template below, and paste it in the custom deployment template in the Azure Portal:

This ARM template will deploy the following resources for you:

  • Virtual Network with an address space you defined.
  • One virtual subnet with an address prefix you defined.
  • One Public IP (Standard SKU).
  • One Public IP prefix (Standard SKU) with the prefix length of /31 (2 Public IPs).
  • One NAT gateway.
  • Last, it will assign the virtual subnet, public IP, and public IP prefix to the NAT gateway.
{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "vnetName": {
            "type": "string",
            "defaultValue": "vnet-weu-prd01",
            "metadata": {
                "description": "Enter the new virtual network name"
            }
        },
        "vnetAddressSpace": {
            "type": "string",
            "defaultValue": "10.13.0.0/16",
            "metadata": {
                "description": "Enter the new Virtual Network address space"
            }
        },
        "subnetName": {
        	"type": "string",
            "defaultValue": "vsn-weu-prd01",
            "metadata": {
                "description": "Enter the new subnet name"
            }
        },
         "subnetAddressPrefix": {
            "type": "string",
            "defaultValue": "10.13.1.0/24",
            "metadata": {
                "description": "Enter the new Subnet prefix"
            }
        },
        "natGatewayName": {
            "defaultValue": "nat-gtw-weu-prd01",
            "type": "String",
            "metadata": {
                "description": "Enter the name of the NAT gateway"
            }
        },
        "natPublicipName": {
            "defaultValue": "pip-weu-nat-gtw-prd01",
            "type": "String",
            "metadata": {
                "description": "Enter the name of the NAT gateway public IP"
            }
        },
        "natPublicipPrefixName": {
            "defaultValue": "pix-weu-nat-gtw-prd01",
            "type": "String",
            "metadata": {
                "description": "Name of the NAT gateway public IP"
            }
        },
        "nsgName": {
            "defaultValue": "nsg-weu-strict-prd01",
            "type": "String",
            "metadata": {
                "description": "Enter the name of the container access Network Security Group"
            }
        },
        "location": {
            "type": "string",
            "defaultValue": "[resourceGroup().location]",
            "metadata": {
                "description": "Primary location for resources"
            }
        }
    },
    "variables": {
    },
    "resources": [
        {
           "type": "Microsoft.Network/publicIPAddresses",
            "apiVersion": "2020-06-01",
            "name": "[parameters('natPublicipName')]",
            "location": "[parameters('location')]",
            "sku": {
                "name": "Standard"
            },
            "properties": {
                "publicIPAddressVersion": "IPv4",
                "publicIPAllocationMethod": "Static",
                "idleTimeoutInMinutes": 4
                            }
        },
        {
            "type": "Microsoft.Network/publicIPPrefixes",
            "apiVersion": "2020-06-01",
            "name": "[parameters('natPublicipPrefixName')]",
            "location": "[parameters('location')]",
            "sku": {
                "name": "Standard"
            },
            "properties": {
                "prefixLength": 31,
                "publicIPAddressVersion": "IPv4"
            }
        },
        {
            "type": "Microsoft.Network/natGateways",
            "apiVersion": "2020-06-01",
            "name": "[parameters('natGatewayName')]",
            "location": "[parameters('location')]",
            "sku": {
                "name": "Standard"
            },
            "dependsOn": [
                "[resourceId('Microsoft.Network/publicIPAddresses', parameters('natPublicipName'))]",
                "[resourceId('Microsoft.Network/publicIPPrefixes', parameters('natPublicipPrefixName'))]"
            ],
            "properties": {
                "idleTimeoutInMinutes": 4,
                    "publicIpAddresses": [
                    {
                        "id": "[resourceId('Microsoft.Network/publicIPAddresses', parameters('natPublicipName'))]"
                    }
                ],
                    "publicIpPrefixes": [
                    {
                        "id": "[resourceId('Microsoft.Network/publicIPPrefixes', parameters('natPublicipPrefixName'))]"
                    }
                ]
            }
        },
        {
            "comments": "Create new virtual network with one subnet",
            "type": "Microsoft.Network/virtualNetworks",
            "apiVersion": "2020-06-01",
            "name": "[parameters('vnetname')]",
            "location": "[parameters('location')]",
            "dependsOn": [
                "[resourceId('Microsoft.Network/natGateways', parameters('natgatewayname'))]"
            ],
            "properties": {
                "addressSpace": {
                "addressPrefixes": [
                "[parameters('vnetaddressspace')]"
            ]
            },
            "subnets": [
            {
                "name": "[parameters('subnetname')]",
                "properties": {
                    "addressPrefix": "[parameters('subnetAddressPrefix')]",
                    "natGateway": {
                            "id": "[resourceId('Microsoft.Network/natGateways', parameters('natgatewayname'))]"
                        },
                    "privateEndpointNetworkPolicies": "Enabled",
                    "privateLinkServiceNetworkPolicies": "Enabled",
                    "networkSecurityGroup": {
                            "id": "[resourceId('Microsoft.Network/networkSecurityGroups', parameters('nsgName'))]"
                        }
                    }
                }
            ],
            "enableDdosProtection": false,
            "enableVmProtection": false
        }
        }
    ],
    "outputs": {
          "vnetName": {
            "type": "string",
            "value": "[parameters('vnetName')]"
        },
        "vnetAddressSpace": {
            "type": "string",
            "value": "[parameters('vnetAddressSpace')]"
        },
        "subnetName": {
            "type": "string",
            "value": "[parameters('subnetName')]"
        },
        "subnetAddressPrefix": {
            "type": "string",
            "value": "[parameters('subnetAddressPrefix')]"
        },
        "publicIPAddress": {
            "type": "string",
            "value": "[reference(parameters('natPublicipName')).ipAddress]"
        },
        "publicIPAddressPrefix": {
            "type": "string",
            "value": "[reference(parameters('natPublicipPrefixName')).ipPrefix]"
        }
    }
}

Update the instance details below according to your networking environment with the proper naming convention. Then click Review + create to validate your input, and finally click Create. The deployment will take less than 30 seconds.

Azure NAT Gateway ARM Instance details

Once the deployment is completed, you can validate its output from the template outputs sections as shown in the figure below:

Azure NAT Gateway ARM Output

Switch to the resource group and validate that all the resources are created.

Azure NAT Gateway ARM Resources

If you open NAT gateway, under Settings > Subnets, you can see that the new subnet is associated with the gateway. You can add and assign multiple subnets as well.

Azure NAT Gateway ARM Subnets

Under Settings > Outbound IP, you can see both public IP and public IP prefixes are associated. Please note that you can use one of them and reduce public IP costs. It’s not required to use both at the same time.

Azure NAT Gateway ARM Public IP addresses and prefixes

Finally, log in to one of your Azure virtual machines attached to this subnet with Azure Bastion, and verify your outbound public IP by running the following PowerShell command:

$PIP = Invoke-RestMethod 'http://ipinfo.io/json' | Select-Object -ExpandProperty ip
Write-Output "Your Public IP Address is: $PIP"

Test Azure NAT Gateway VM Public IP address

If you run the command again, you will see that the last octet of the public IP will change to the next one (in this example, I have two public IPs from the prefix: 20.50.153.96 and 20.50.153.97).

Summary

In this article, I showed you how simple it is to deploy and use Azure Virtual Network (NAT ) service. NAT gateway is designed to provide outbound functionality for virtual machines in Azure.

That’s it there you have it. Happy Azure Networking!

__
Thank you for reading my blog.

If you have any questions or feedback, please leave a comment.

-Charbel Nemnom-

Related Posts

Previous

Passed AZ-600 Exam: Microsoft Certified Azure Stack Hub Operator Associate

PowerCLI An Aspiring Automator’s Free eBook

Next

Let me know what you think, or ask a question...

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Subscribe to Stay in Touch

Never miss out on your favorite posts and our latest announcements!

The content of this website is copyrighted from being plagiarized!

You can copy from the 'Code Blocks' in 'Black' by selecting the Code.

Please send your feedback to the author using this form for any 'Code' you like.

Thank you for visiting!