Privately connecting to PaaS services using Azure Private Link

Integrating Azure PaaS services with a private network has been a hot topic. The issue that most customers deal with when it comes to Azure PaaS services is that some of those are published using a public network connection. A good example here is SQL Azure: While databases always have been very well guarded, suddenly when moving to an Azure managed service you see them showing up with a public network connections which breaks a lot of the security controls you built up over the years.

Over the years, there have been a couple of additional security mechanisms that were created to connect privately and securely to your PaaS services.

In this post, we’ll walk through the different ways you can connect to Azure PaaS services, and then dive into the newest of those ways: Private Link. Private Link a new functionality that allows you to connect those PaaS services to your VNET using Private IP addresses. The default service still has a public IP address, but using the built-in service firewall you can disable all public connectivity, and connect your PaaS service to your VNET using a private IP in your address space. This will also enable you to connect to your PaaS services over a hybrid network (VPN or Expressroute).

Different ways of connecting to Azure PaaS Services

Before we dive into the details around Private Link itself, it might make sense to spend a couple minutes on explaining the different ways you can connect to Azure PaaS services, as there are a couple ways. In this writing, I’ll be overgeneralizing a little bit. There’s different implementations for different services, and in broad terms what I’ll explain is correct.

The first way you can connect to PaaS services – and let’s not forget this – is simply through their default public IP connectivity. Most PaaS services have a default connectivity through a public IP, so you can simply connect to that public IP.

Some services allow you to connect back-end resources to public PaaS services using a “hybrid agent”. There are a couple of these hybrid agents, think about the Hybrid Connections in App Services or the on-prem data gateway for Azure Analysis Services, Logic Apps, PowerBI, PowerApps and Flow Power Automate. Those “hybrid agents” all work on a similar architecture: you install an agent on a machine within your network (Azure network or even on-premises network), the agent makes an outbound connection to the PaaS service, and that way creates a bi-directional tunnel over SSL. You don’t need to allow any inbound traffic, because from a firewall’s point of view, there’s only outbound HTTPS.

Then there’s other services that are able to integrate into your virtual network through VNET injection. Some of the services that support this are SQL Managed Instances, App Service Environment or HDInsight. With VNET injection, the PaaS service gets fully integrated into your VNET, meaning all instances will get a private IP within your address space.

Then finally, there are those PaaS services that live by default on public IP space. Two years ago at Ignite (2017), Microsoft announced a functionality called “Service Endpoints“. Service Endpoints introduced two technical improvements on how you can connect to those public PaaS services:

  1. The PaaS services supporting Service Endpoints now come with a built-in firewall, allowing you to allow/deny incoming requests and
  2. Service Endpoints allow you to connect your VNET to those PaaS services via a ‘secure back-end tunnel’ on the Microsoft backbone. This essentially boils down to a change in the route table to route traffic to those PaaS services over a service endpoint rather than the default ‘Internet’ path.

The functionality of Private Link builds on these service endpoints. There is however a difference between Private Link and service endpoints – both technically and pricing-wise. As mentioned, Service endpoints create a sort of tunnel between your subnets and the PaaS service on the Azure backbone, while still using Public IP addresses. This means that using service endpoints, you would still connect to the public IP, but instead of exiting through the Azure internet route, you connect through a secure back-end connection. The PaaS service itself will actually see your private IP address when you connect to them, but you use a public IP to connect to.

Private Link is different as it presents a private IP address that will represent your PaaS service in your VNET. This is the biggest advantage of Private Link. This means it will be easier for you to setup routing and security to those endpoints. This will have impact on how you handle DNS, as you’ll need a new DNS entry to map the service name to the private IP address.

Private endpoint overview
PrivateLink creates a private endpoint on your VNET to connect to PaaS resources.

Private Link also support a new scenario to connect to applications: it gives you the ability to route traffic to a service you host yourself via Private Link. If you – or one of your software partners – builds a service that needs to accessed by multiple end-users, with Private Link you can make this service available via Private Link endpoint. This means you don’t need full VNET peering or a VPN, you can make this available with a single endpoint integrated into your end-user’s VNET.

We mentioned pricing earlier. The ‘public’ service endpoint functionality is free of charge, while Private Link is not. The pricing for Private Link is based on two elements:

  • A cost per Private Endpoint of $0.01 per hour ($ 7.3 per month) and
  • A cost per GB of bandwidth (in/out) over Private Link ($0.01 per GB)

With the theory out of the way, let’s go ahead and setup our first Private Link.

Setting up Private Link to Azure Storage

Two years ago I wrote about (public) Service Endpoints for storage. Let’s revisit that article, but see how that works with Private Link.

I am going to setup the following:

  • A storage account,
  • A VM in a VNET,
  • A Private Link endpoint.

Let’s go ahead and build this out:

When creating a storage account, on the networking tab in the portal, there is an immediate guided walk trough of setting up Private Link. It walks you through:

  • Creating the private endpoint,
  • Connecting to a subnet in that VNET,
  • Setting Azure DNS private zones.
The storage account creation wizard contains a guided walk through of setting up Private Link.

I haven’t setup our test VM yet, so we’ll setup the Private Link later. It was however very nice to see that this wizard is available and very functional.

Next up, we’ll create our VM. I decided to create a new VM in a new VNET for this test, as I’ll throw everything away afterwards.

Creating a new VM in a new VNET.

While our VM is creating, let’s upload a file to blob, that we’ll try to download down the line. I uploaded a small text file to blob, and will generate a SAS token to download it from blob.

Uploading a file and setting up a SAS token.

Once the VM is available, let’s login and try to download our file. As we haven’t setup any firewalling, this should work seamlessly. (which it does)

Downloading without any special configuration works perfectly.

Now that we have that, let’s go ahead and create a new subnet in our VNET for our private endpoint. Private endpoints don’t have to be in a separate VNET, but for better visibility, that’s where I like to put them.

Adding a subnet for our private endpoints. Not required, but makes management easier.

Next, we’ll go into our storage account and walk through the full Private Link wizard configuration. This wizard is also accessible from a top level resource called Private Link in its own blade.

First step is naming the Private Link endpoint.

First step is naming the Private Endpoint.

Next up is selecting the service we want to connect to. It’s a bit strange that in the storage blade, I have to re-select storage. One thing that is very apparent is that you have to carefully select a target sub-resource you want to connect to. It appears each endpoint from Azure storage needs a separate private endpoint. For our use case, we’ll simply connect to blob.

Next up, we select which resource we want to connect to.

After that we configure our VNET. Here we provide the VNET and subnet we want to Private Endpoint to live in, and we can optionally configure Azure DNS. As I have a new VNET with no existing DNS configuration, setting up a new zone works well for me. In your use case, you might simply want to create new records in DNS for the private endpoint.

Final step is network configuration.

That was easy, right? Let’s explore what this created:

The wizard created three things to get Private Link to work.

The creation wizard apparently created 3 things:

  1. An update to our subnet
  2. A Private Endpoint
  3. A Private DNS zone.

The Private endpoint that was created contains all the info about our Private Endpoint, including DNS settings.

The Private endpoint blade in the portal

The private DNS looks a bit weird to me at first glance. The zone is called (maybe I should have renamed this?) – and the record itself doesn’t refer to my storage account (which would be but to This seems off, but let’s experiment later on.

The private DNS zone.
The DNS record.

The storage accounts now shows in the Private endpoint connection blade the information about our private endpoint.

The private endpoint information in the storage blade.

One thing that wasn’t changed – which should have been changed – is the Firewall section of the storage account. As we have a Private endpoint, we don’t want public connectivity anymore. Let’s head over to the Firewall blade and turn on the firewall.

Make sure to enable the storage firewall to block incoming traffic from unknown sources.

With everything locked down, let’s head on over to our VM and see if we can download our file.

The download surprisingly succeeded.

This immediately succeeded, which I did not expect (remember the DNS record thing I talked about?). Let’s do an nslookup to see what happened here:

The DNS resolves correctly to the private IP of the private endpoint. There seems to be an additional cname record to point nfpl to nfpl.privatelink. This surprised me a bit, but it works like a charm!


Private Link is a new way to connect privately to your PaaS services. The setup itself is straightforward, with only 1 gotcha: remember to turn on the storage firewall.

And with that, you have a new tool in your tool belt to create secure applications on Azure.

Leave a Reply