Every Azure Function instance requires to have a Azure Storage Account for storing sensitive data – sometimes even source code of functions. Out of the box, this storage has enabled public endpoint. With PrivateLink, you can add an extra layer of protection.
What data are stored inside Storage Account
Azure Function App uses two subservices blob and files in the Storage Account.
It always creates a two blob containers, called azure-webjobs-hosts and azure-webjobs-secrets.
In the azure-webjobs-hosts container – there are metadata files used for logging purposes, locks etc.
In the container azure-webjobs-secrets you can find really interesting data:
1. every function has JSON file
2. there is host.json file, containing all function’s keys, including master FunctionApp key, in encrypted form
Function Apps, not using deployment type app package, also stores even functions source code in File shares container, in the site/wwwroot directory.
When you create a new Function App via standard Azure Portal wizard, it creates automatically a Storage Account. This Storage Account has opened public endpoint and the Function App interacts with storage via SAS (Shared Access Signature) via public endpoint.
This is not so dangerous setup as you could read it for first time – all file containers in this Storage Account has Public access level value Private, so you still need to have storage access key for accessing these files.
On other hand, on this setup with a combination of some vulnerability, you could get the content on storage easily compromised and for some workloads you need to reduce the risk with adding extra layer of protection.
This setup is based on limiting access to the Storage Account and requires having a vNET. Public endpoint of Storage Account is disabled and there is created a PrivateLink endpoint of the Storage Account into Function App’s vNET.
The Function App need to have a plan supporting vNET integration for egress traffic (higher App Service tier, or for consumption-based resources you need to have a Premium plan).
Storage Account needs to be provisioned as General purpose V2 account kind (V1 is not supported by PrivateLink).
I am reminding this, because it happened to me, that Azure Portal user wizard created a V1 Storage Account for Function App. When this happens, just create a new V2 Storage Account and point the Function App to the new storage resource.
Steps to protect Azure Function (via Azure Portal)
- Turn off public endpoint on Storage Account
Go to Networking, select Allow access from selected networks and click Save
- Set up a PrivateLink endpoint for Storage Account
a. Go to Networking, select tab Private Endpoint connections and click on +Private Endpoint
b. Follow wizard, as resource select the Storage Account
c. As target sub-resource select blob
- Repeat Step 2, only as target sub-resource select file
- Set up required feature flag for Function App runtime
a. Go to the Function App, select Configuration and select tab Application settings
b. Add a new Application settings called WEBSITE_CONTENTOVERVNET, with value 1
c. Save new settings
- Test the Function App
Now the Storage Account is not accessible from public internet, but reachable from the Function App.