Function app to its storage account without keys
The handoff between an Azure Functions host and its storage account (AzureWebJobsStorage, the deployment package and the app's own bindings) using a user-assigned managed identity instead of connection strings — which plan allows it, the settings, the roles per purpose, the network path when the account is firewalled, known-bad configurations with their exact errors, and which side is wrong.
markdownpatternv1PPR1-VX8Qstage: buildtrust: officialservice: functionsservice: storageservice: managed-identityinterface: iacinterface: cliFunctions managed identity storagekeyless AzureWebJobsStorageAzureWebJobsStorage__accountName __credential __clientIdFunctions Shared Key disabledallowSharedKeyAccess false FunctionsFunctions storage firewall private endpoint blob queue tableFlex Consumption deployment storage UserAssignedIdentityStorage Blob Data Owner FunctionsStorage Table Data Contributor FunctionsStorage Queue Data Contributor bindingWEBSITE_CONTENTAZUREFILECONNECTIONSTRING Premium Consumptionaz functionapp create connection stringwhich side is wrong Functions storage
Host side: the Functions host authenticates to its storage account as a managed identity, read from AzureWebJobsStorage__* settings. Storage side: the account lets that identity in on the network and grants it data roles. The app's own bindings are a separate connection with their own settings and roles, even on the same account.
Known-good
- Plan: Flex Consumption or Dedicated (full identity support). Consumption and Elastic Premium still need a key for their Azure Files content share.
- Identity: one user-assigned identity on the app, its client ID in
AzureWebJobsStorage__clientId, withAzureWebJobsStorage__accountNameandAzureWebJobsStorage__credential=managedidentity. NoAzureWebJobsStorageconnection string anywhere, including slot settings. - Roles on the account: Storage Blob Data Owner and Storage Table Data Contributor for the host; Storage Queue Data Contributor (or what the binding table lists) for the app's queues, through settings such as
OrdersQueue__queueServiceUri. - Flex deployment package:
functionAppConfig.deployment.storagewithauthentication.type: 'UserAssignedIdentity'and a container that exists before the app. - Account:
allowSharedKeyAccess: false. If firewalled: VNet integration, and private endpoints forblob,queueandtablewith their private DNS zones linked to the app's VNet. - Created by Bicep, not
az functionapp create(guides/functions/deploy-typescript-function.md).
Known-bad
| Configuration | Symptom |
|---|---|
App created with az functionapp create, then Shared Key turned off | Portal Azure Functions Runtime is unreachable; host logs KeyBasedAuthenticationNotPermitted. The CLI stored a connection string |
__accountName and __credential set, __clientId missing, only a user-assigned identity attached | The host can't get a token (no system-assigned identity to default to) |
| Identity has Storage Blob Data Contributor, not Owner | Host storage errors and failed coordination: Owner is the documented minimum |
| Table role missing | Warnings that diagnostic events can't be written; startup problems become invisible |
App's queue binding reuses AzureWebJobsStorage as its connection | Microsoft says to define a separate connection for non-host components; mixing them couples app permissions to host permissions |
| Elastic Premium with Shared Key off and a content share | The app can't mount its Azure Files share; keep that one connection string in Key Vault or run without Azure Files |
| Account firewalled, app not VNet-integrated (or DNS zones not linked) | AuthorizationFailure from storage, or host start timeouts |
| Two apps with the same 32-character name prefix on one account | AZFD0004 host ID collision; the host stops |
Which side is wrong
- No token /
ManagedIdentityCredentialerrors in host logs → the app: identity attached,__clientIdcorrect (reference/managed-identity/errors.md). KeyBasedAuthenticationNotPermitted→ the app still holds a connection string somewhere (az functionapp config appsettings list -n <app> -g <rg> --query "[].name" -o tsv).- 403
AuthorizationPermissionMismatch→ the roles above, or propagation (10–30 minutes):reference/storage/access-errors.md. - 403
AuthorizationFailureor timeouts → the account's network:reference/storage/network-and-firewall.md.