Azure Functions with a Static Outbound IP Address

“So to complete our configuration we just need your outbound static IP…” This is something that pops up again and again, specially if you work integrating legacy systems, like banks, government agencies or other older systems that requires a static IP Address to add to firewall inbound rules.

In the past I had to use on of the subscription tiers from Azure API Management or in some cases deploy the code within a self hosted service in a Virtual Machine. And both of them are valid options if you already have one of those components in place. But in a couple of my last projects, Not only I needed to implement a new component (in this case API Management) just to fulfil this requirement. I also had to change my design a bit, because API Management didn’t support one of the streaming requirements I had (but that is a story for another post).

But I wouldn’t be writing a post just to complain about this (not that this has never happened before) – I actually found another solution – one that I’ve tried and discarded earlier this year, but thanks to some good work from the App Services Engineering team, is finally a viable solution: Azure Functions + VNET Integration + NAT Gateways!

How does it work?

According to Microsoft Docs:

“NAT gateway resources are part of Virtual Network NAT and provide outbound Internet connectivity for one or more subnets of a virtual network. The subnet of the virtual network states which NAT gateway will be used. NAT provides source network address translation (SNAT) for a subnet. NAT gateway resources specify which static IP addresses virtual machines use when creating outbound flows.”

Designing virtual networks with NAT gateway resources

So, the NAT Gateways provides a way to specify a static IP addresses to be used as outbound address to any outbound traffic that is leaving a subnet towards the internet. Sounds like something we would like to do right?

When I first learned about this resource around the end of 2019, I’ve tried to configure the following scenario:

But I got stuck on an issue – NAT Gateway were not compatible with the App Service Plans for either Azure Function Consumption Premium or Dedicated plans. Doing some research I found that the NAT Gateway at that point was not compatible with the basic load balancer and any products that used basic load balancer.

But just this week, the App Services team provided us with some good news:

You can read their blog post here. So whatever incompatibility between the NAT Gateway and the App service plans are now solved! So let’s try to get it working…

Pre-requisites

In order to implement this you will need the following items:

  • An Azure Function configured with an App Service plan that supports VNET integration (Premium Consumption, or one of the following dedicated plans: Standard, Premium V2 or Premium V3),
  • A Virtual Network with at least one available subnet,
  • A standard IP Address and
  • A NAT Gateway.

You can find more information about how to configure the NAT Gateway and associate it to a subnet here. The configuration is pretty simple – just requires the standard IP address and the VNET/Subnet associated.

Notice that a single NAT Gateway can be connected to multiple subnets. So as long as applications requires the same outbound IP addresses, they can be integrated to subnets connected to the same NAT Gateway.

Azure Function Configuration

The configuration for Azure Functions is quite straightforward. First you need to go to Networking (1) and select configuration (2).

After that you need to click on + Add Vnet (1), then select an existing Virtual Network (2), click on select existing (3) and choose one of the available subnets (4) and finally click Ok (5).

Once the VNET configuration is completed, it should look like this:

To confirm that the subnet is configured to connect to the NAT Gateway, you can click on the subnet name, which will bring you to the subnet configuration page. Here, you can confirm that the NAT Gateway is assigned to that subnet.

I’ve noticed (and some other people also noticed) that when you add the VNET integration to the Azure Function (or web app), sometimes the NAT Gateway configuration is removed. I am not sure if that happens all the time, as I couldn’t reproduce it every time. But just bear that in mind – go back to the configuration of the subnet and make sure that it is associated to the NAT Gateway as a precaution. Thanks J.V. for highlighting this in the comments!

Once the configuration is completed in the VNET side, you will need to force all outgoing traffic to go through the VNET – this will force the traffic going to the internet to be routed through public IP address associated to the NAT Gateway. This can be achieved by including a new app setting entry on your configuration. You must include the following entry:

  • WEBSITE_VNET_ROUTE_ALL = 1

To do this, search for Configuration on your side blade (1), click on Configuration (2), click on add to include a new value (3), add WEBSITE_VNET_ROUTE_ALL as the Name and 1 as the Value, then click OK (4). Don’t forget to click save (5) to persist your changes

Testing your configuration

A simple way to test your configuration is to make a http request to a website that would return the IP address of the caller. I’ve used a PowerShell script to do that, taking the advantage of Azure Function support for PowerShell Core. You can find the code in the gist below:

A whole new world…

The ability to have Azure Functions and Web Apps having a static outbound IP is a feature that have been requested for some time now. This will open up a number of scenarios that were not possible today with pure serverless and will simplify a lot the integration with other systems, in special legacy and on-premises systems that still depend on a static IP address to configure inbound access.

That alone would already be fantastic news! But another recent announcement from the Enterprise Integration team combined with this makes those news even more exciting… The new Logic Apps runtime, which is an extension of Azure Functions Runtime, can also leverage from this configuration. So not only core Azure Functions implementations can take advantage of this implementation, but Logic Apps will soon be able to leverage from that as well. Actually, I’ve tested the same configuration on a logic apps (preview) resource and it behave as expected!

I’ve been doing a bit more research on the Logic Apps (preview) and what I found so far is that the managed connectors are still using their own IP addresses. For example, I’ve tried to connect to the an FTP server using the SFTP-SSH connector and it presented an IP from the managed connector in Australia East region. Hopefully this is something that will be addressed as the preview moves close to GA. Otherwise we will have to replace connector functionality with Azure Functions (still better than the original situation, but not ideal).

In Summary

  • App Services can now leverage from the NAT Gateway functionality to expose a static outbound IP address to the internet.
  • Azure Function with either a Premium Consumption or Dedicated app service plan can also leverage from the same functionality.
  • Logic Apps (preview), which are based on the Azure Functions runtime will also benefit from the same type of configuration.
  • This will open up a number of scenarios that were not easily implemented before – in special when integrating with on-premises or legacy systems.

Sharing is caring...

7 thoughts on “Azure Functions with a Static Outbound IP Address”

  1. Hello,
    … great article, thank you …

    I tried it, unfortunately, it does not work for me…
    And I have no idea how to diagnose where the problem is. Could you please point me what and how to check? Thank you.

    [Solved] First problem was that when I created VNet, IP, NAT, Functions in sequence… then when I configured Functions-Network-VNetIntegration – it (silently) unset NAT on subnet. I had to stop Function app, disconnect VNetIntegration, and reconnect it back, and THAN set used subnet on NAT. Now it is shown as used in subnet settings.

    [Solved] After deploy of new version of Function code – the executed version was still the old version. I am not sure whether it did anything, but I add a property specifying appServicePlan to deploy goal. Or may be it just took dozens of minutes to update?

    My set up (order of creating):
    – Resource group
    – App Service Plan – linux (S1)
    – VNet
    – Storage account
    – Static public IP (standard SKU)
    – NAT
    – Functions (+Insights), using dedicated plan, java runtime, HttpTriggered function calling Apache.HttpClient request to ifconfig.me/ip, deployed by maven plugin

    Unfortunately, it is NOT called from expected IP.
    – In function properties, there are props: Virtual IP, Outbound IPs, AdditionalOutboundIPs, but no mention of my dedicated static IP I used in NAT.
    – In subnet (called NAT-subnet) where NAT is activated, “Delegated to” is set to
    “Microsoft.Web/serverfarms” (done by assigning VNet integration).

    It all looks OK, but it does not work. Any idea what to check? Could you post set of CLI commands to help me to diagnose?
    Thank you and have a nice day.

    1. Thanks JV for catching this. I was sure I added that piece, but obviously not! 😉. I’ve updated the post to include this info now.

      I’ve also added a not about your previous comment, as I also noticed that. I will try to follow up with Microsoft to find if it is a bug or something that we would expect it to happen first time you connect the subnet.

  2. I was able to configure function in vnet+nat and everything works fine except the 25 port. We need the static outbound IP to be able to whitelist it on SMTP servers during the connection via 25 port. When I try to initiate new SMTP connection via 25 port it doesn’t work. It works when I set WEBSITE_VNET_ROUTE_ALL = 0 for function.
    We have the Enterprise subscription and port 25 is opened for our resources.
    Any ideas?

    1. The only thing I can think of is if you have any specific NSG rule that don’t allow outbound on that particular range on port 25 (or only allow on particular ports).

    2. Hi Vitalii,
      We have the same problems here. Have you already found a solution for this?

Leave a Reply

Your email address will not be published. Required fields are marked *