Azure Functions Access to Restricted Storage Accounts

With requirements for additional security, many customers have started enforcing network restrictions on their Azure storage accounts. This in turn can cause major issues with Azure Functions without the proper configuration, as Azure functions rely heavily on Azure storage for functionality.

Background

Azure storage

There are two core concepts for Azure Functions related to Azure storage.

  1. The first is the AzureWebJobStorage app setting. The setting points to a general-purpose storage account and is used by the Webjob SDK’s host runtime for indexing, state store, and other functionality. This setting utilizes Azure blob. All hosting options require this app setting.
  2. The second is WEBSITE_CONTENTAZUREFILECONNECTIONSTRING. This app setting is required for the consumption and Function premium tiers, but is optional for the Dedicated SKU. The setting specifies where the function code will be hosted within a Azure Files storage account. In the dedicated SKU only, if not specified, the code will be stored in the App service infrastructure’s file system. In general, the recommendation is to not use this setting for the dedicated SKU.

Hosting Options

Consumption Plan
– True serverless that runs on shared compute.
– Does not support VNET integration.
– Code is hosted in Azure files
https://docs.microsoft.com/en-us/azure/azure-functions/consumption-plan

Functions Premium (Elastic premium)
– Hybrid SKU: Supports dedicated VMs with more compute power and dynamic scaling.
– Supports VNET integration
– Code is hosted in Azure Files
https://docs.microsoft.com/en-us/azure/azure-functions/functions-premium-plan?tabs=portal

Dedicated (Standard, premium, premiumV2/V3)
– Similar to your standard App Service SKU.
– Supports VNET integration.
– Code is by default hosted in App Service managed storage accounts. You can also configure the function to use Azure Files as well but it is not recommended.
https://docs.microsoft.com/en-us/azure/azure-functions/dedicated-plan

Why is Virtual Network Integration required for a Function App to communicate with storage that has “Select networks” enabled?

Services deployed in the same region as the storage account use private Azure IP addresses for communication to Azure storage. Thus, you can’t restrict access to specific Azure services based on their public outbound IP address range.
https://docs.microsoft.com/en-us/azure/storage/common/storage-network-security?tabs=azure-portal#grant-access-from-an-internet-ip-range

The next question I usually get is “Why can’t I just check ‘ Allow Trusted Azure Services’”. The answer is trusted Azure Services are limited to services that do not execute custom code or scripts.

https://docs.microsoft.com/en-us/azure/storage/common/storage-network-security?tabs=azure-portal#trusted-access-for-resources-registered-in-your-subscription

So in order to make this communication between the function app and Azure storage behave in a way that one can restrict access to a known endpoint, the function has to be integrated with a VNET/subnet to then allow the subnet on the Azure storage’s firewall. After the VNET integration is completed, the subnet can be allowed on the Azure storage account’s “Select Networks” configuration allowing the communication to flow without issue.

Now that a baseline has been set explaining how functions use storage, the next section will discuss how one can properly integrate the function app with a VNET.

How it works with the two supported SKUs?

Reference: https://docs.microsoft.com/en-us/azure/azure-functions/configure-networking-how-to#restrict-your-storage-account-to-a-virtual-network

I reference service endpoints setup below but the same should work with private endpoints on storage as well.

Dedicated Function

Remember by default, with the recommended configuration, the Azure function app is only using Azure storage (specifically Azure blob) for indexing, state management, and other functionality. The function code is stored in the infrastructure’s storage. Since the code is not in the Azure storage account the function app may start, if the VNET integration has not been enabled, but the webjob/function host will not properly start as it cannot pull metadata from the storage account. You may see errors such as 401 unauthorized if you try and invoke your function inside of the function app, prior to the VNET integration being enabled.

  1. Create a function app in the Azure Portal. A storage account can be created or you can select a storage account with or without “Select Networks” enabled.
  2. Enable the Regional VNET integration on the newly created Azure function.
  3. On the subnet that the function app is integrated with, enable storage Service Endpoints.
  4. Under the storage account firewall, if you have not already, choose “Select Networks” and allow add the subnet you picked in step 2.

Premium Functions/Elastic Premium

The premium function SKU stores both the metadata and code in Azure storage (blob and files respectively). Since the function app requires access to Azure File storage to start the actual function app, if the storage account is locked down to only allow “Selected Networks” and if no integration is enabled, the function app will fail to startup and possibly even deploy, returning a 403 response code.

  1. Create a function app in the Azure Portal selecting a storage account that does not have “Select Networks” enabled. If you need to deploy the function app to a storage account with “Select Networks” enabled you may have to use an automated method such as an ARM template.
  2. Enable the Regional VNET integration on the newly created Azure function.
  3. Add the app setting WEBSITE_CONTENTOVERVNET and set the value to 1. This allows the connection to the storage account to be made through the VNET integration.
  4. On the subnet that the function app is integrated with, enable storage Service Endpoints.
  5. Under the storage account firewall, choose “Select Networks” and allow add the subnet you picked in step 2.

Happy integrating…