There is a known problem with Azure Function App security configuration. Ootb function app access to storage is configured using shared keys. This is considered as potential vulnerability. Disabling storage account key access breaks the app. This article tells how to reconfigure the app to use Microsoft Entra credentials vs shared keys.
When the function app is created – a Storage Account is created to support function app. By default, storage account has shared keys enabled and function app is configured for shared keys. So we’d need:
- Enable function app managed identity
- Provide access for the function app managed identity to the storage account
- Configure function app to use managed identity
Enabling function app managed identity
It’s done via Azure portal -> function app -> Settings -> Identity:
Providing access for the function app’s managed identity to the storage account
First, you’d navigate to the Azure portal -> Storage Account -> Access Control (IAM)
and Add new role assignment.
then you’d select “Storage Blob Data Owner” role, “Managed identity” your app identity
Configure function app to use managed identity
Responsible app settings are (you can find them under your app Settings -> Environment Variables -> “App settings”:
You can remove “AzureWebJobsStorage” and replace it with “AzureWebJobsStorage__accountName” as per here.
For the WEBSITE_CONTENTAZUREFILECONNECTIONSTRING, unfortunately, it says that this env variable is required for Consumption and Elastic Premium plan apps running on both Windows and Linux… Changing or removing this setting can cause your function app to not start… Azure Files doesn’t support using managed identity when accessing the file share…
Possible error messages
If you have a Function app with Consumption or Elastic Premium plans and completed steps above to disable function storage account key access – your function app will not work. There will be no new invocations. Personally, I was able to observe the following error messages:
“We were not able to load some functions in the list due to errors. Refresh the page to try again. See details” :
Function App with Dedicated Plan
If you have a function app created based on dedicated plan (App Service):
then under function “Environment variables” you’ll see:
e.g. there is a AzureWebJobsStorage (that can be updated) and no WEBSITE_CONTENTAZUREFILECONNECTIONSTRING (than is required).
So, for the function app created with dedicated plan (App Service) – if you followed steps above (provide a role to managed identity, created AzureWebJobsStorage__accountName, removed AzureWebJobsStorage and disabled key access – the function should work.
Function App with Flex Consumption plan
Flex Consumption plan is a new linux-based plan (GA announced Nov 2024), and it looks promising – it’s still consumption, but supports virtual networks and allows fast start (and some more nice features).
What I do not like is it does not support installing dependencies via requirements.ps1 – you have to go with custom modules here (it says: Failure Exception: Failed to install function app dependencies. Error: ‘Managed Dependencies is not supported in Linux Consumption on Legion. Please remove all module references from requirements.psd1 and include the function app dependencies with the function app content).
For our specific needs – disabling storage key access and using function identity to access it’s own storage – I found the following promising: “By default, deployments use the same storage account (AzureWebJobsStorage) and connection string value used by the Functions runtime to maintain your app. The connection string is stored in the DEPLOYMENT_STORAGE_CONNECTION_STRING application setting. However, you can instead designate a blob container in a separate storage account as the deployment source for your code. You can also change the authentication method used to access the container.”
Let us create a function with a hosting option “Flex Consumption plan” (all the other settings are by default) via Azure Portal:
and right away we can see that app is using storage keys by default via environment variables: AzureWebJobsStorage (we know how to deal with) and DEPLOYMENT_STORAGE_CONNECTION_STRING (no description found).
Let us try to create a function app different way (customized as per this). First, we’d create a storage account. When creating a function app – we’d select an existing storage. I did not find any options to select function managed identity and configure the function to use managed identity to access storage account during function app creation wizard.
Let us try to reconfigure the existing app
After this – a system identity was created and the role “Storage Blob Data Contributor” was assigned to this identity to the storage account. Environment variables did not go. Let us disable access keys under storage account – and… and function app stopped working.
Since environment variables are still here – let us blame “AzureWebJobsStorage” and let us do the trick with it – create a new “AzureWebJobsStorage__accountName”, put our storage account name as a value, remove “AzureWebJobsStorage” and restart the app… Drumroll, please! And hooray! The function has started working again!
“Container app environment” – to be tested
tbc…