A question I come across a lot is how to secure traffic between services running in Azure. In this multipart-part series, I will look at using two different approaches for securing service traffic in Azure using a Function App and a storage account as my example services.
The test environment
For the purposes of this post, I am going to use a simple function app that communicates with a storage account and retrieves the content of a file. Granted, we could get the content directly from the storage account, but this would not demonstrate the required functionality. Therefore the demo environment will consist of:
- A storage account hosting a CSV file of data,
- A PowerShell function app based on a http trigger that will retrieve the data from the CSV file,
- and I’ll be using an account with contributor rights to the resource group.
When called, our function app will write the contents of the CSV to the browser:
Concerns about the described environment
Now while our communications are over HTTPS and using access keys (for the sake of this demonstration),concerns are sometimes raised that the communication, encrypted or not, is over open internet. In addition, for this communication to occur over the open internet, our data source (the storage account) requires a public endpoint. All it takes is a simple misstep and our data could be exposed to the internet.
So how do we restrict public access to our source and ensure communications occur over a more secure channel?
Microsoft provide two mechanisms to secure the connection for the data source:
In this post, we are going to focus on private endpoints.
Securing the storage account with a private endpoint
Our first step is to secure the storage account from public access by disabling “Public Network Access” in the Firewall and Virtual Networks tab:
With this committed, you can see that our function app no longer returns the content of the data file:
To allow secured access to our data store, we are now going to need to create a private endpoint for the storage account. For this demo, I am going to call the instance “storage-endpoint” and attach it to the blob resource:
and now we need a virtual network to attach the endpoint to. For this demo, I have created a virtual network and added a subnet “privateips” to place private endpoints in:
I am accepting the defaults for DNS:
and then creating the private endpoint. As we accepted the default DNS settings, this will also create a privatelink DNS zone to host the A record for the private endpoint:
We have now successfully secured the blob storage from the internet:
However, as demonstrated earlier, our function app also has no access. I will now show you how to remedy that.
Connecting the function app to the private endpoint
Before we go any further, it is worth noting that the SSL certificate for the storage account is against “apptestrmcn0.blob.core.windows.net” and we have just created a private endpoint with the name “apptestrmcn0.privatelink.blob.core.windows.net“. Any service trying to connect to the private endpoint is going to fail due to a certificate mismatch. Not to worry, if we try resolving the original name of the storage account from an internal host in the same virtual network, you will see that the FQDN also maps to the new private endpoint:
As the storage account has now been isolated to private endpoint traffic only, we need to connect the Function App to the virtual network too. This is achieved via a “VNet integration” which relies on service delegations. Service delegations require a dedicated subnet per delegation type, and we therefore cannot use the same subnet as our private endpoint. For the sake of simplicity, we are going to use a separate subnet call “functionapps” within the same Virtual Network to demonstrate the functionality.
VNET integration is configured via the Networking tab for the function app:
When we select VNET integration, we are going to then select our subnet for function apps:
When we click connect, the service delegation will happen in the background if not already delegated and the function app will get a connection to the subnet. In the next window, as our function app’s sole purpose is to fetch data from the blob, I will disable internet traffic for the function app and apply the change.:
This is the last of the configuration. It should look like this:
And as you can see, our function app is again able to retrieve data the storage account:
In the next part “Securing service traffic in Azure – Part 2” I will look at an alternative to private endpoints.