App to Key Vault with a managed identity

The handoff from an App Service, Functions or Container Apps app to Key Vault secrets without stored credentials — user-assigned identity, Key Vault Secrets User on the vault, an RBAC-model vault with enableRbacAuthorization set explicitly, network access through a private endpoint or allowed outbound IPs, SecretClient with ManagedIdentityCredential — with known-bad configurations, their exact symptoms, and which side is wrong.

markdownpatternv1A70E-F5FJstage: buildtrust: officialservice: keyvaultservice: managed-identityservice: rbacinterface: iacinterface: sdkinterface: cliApp Service Key Vault managed identityFunctions Key VaultContainer Apps Key VaultKey Vault Secrets UserForbiddenByRbac managed identityaccess policy vault managed identityKey Vault firewall App Service not trusted serviceenableRbacAuthorization explicit BicepSecretClient ManagedIdentityCredentialKey Vault known-badwhich side is wrong Key Vault

Created 21 Oct 2026 · Modified 23 Oct 2026 · 1 version

App side: the app runs as a managed identity and asks for a token for https://vault.azure.net. Vault side: the vault's network lets the app in, and its permission model grants that identity the secret. Each failure below is one of those.

Known-good

  • A user-assigned identity id-orders, attached to the app. Its client ID is in the app setting APP_IDENTITY_CLIENT_ID.
  • The vault is created with enableRbacAuthorization: true written in the template (API version 2026-02-01 or later), soft delete on (always), and purge protection on for production.
  • Key Vault Secrets User assigned to the identity's principalId, scoped to the vault, with principalType: ServicePrincipal and a guid() name.
  • Network: public access disabled and a private endpoint in the app's integrated VNet, or the vault firewall allowing the app's outbound IPs.
  • Code: new SecretClient("https://<vault>.vault.azure.net", new ManagedIdentityCredential({ clientId })), with the secret cached in memory rather than fetched per request.

Setting up the identity and the role: guides/managed-identity/use-managed-identity.md and guides/rbac/assign-roles.md.

Known-bad

ConfigurationSymptom
Identity holds Contributor (or Owner) on the vault, no data role403 Caller is not authorized to perform action on resource. (ForbiddenByRbac)
Template on an API version before 2026-02-01 with no enableRbacAuthorization; role assignments deployedAccess-policy vault: role assignments are ignored, 403 … does not have secrets get permission …
Template moved to 2026-02-01 while still relying on accessPolicies (property omitted)New vaults are RBAC: the access policies are ignored, 403 ForbiddenByRbac
Role granted to the identity's group, not the identity403 for hours after the change (managed identity token cache, about 24 h)
Two user-assigned identities on the app; code uses DefaultAzureCredential without a client IDToken for the wrong identity, or none; 403 or ManagedIdentityCredential: Authentication failed
Vault firewall on, bypass: AzureServices, no IP rule or private endpoint403 Client address (<ip>) is not authorized and caller is not a trusted service (App Service isn't a trusted service)
App calls the vault per request at high volume429 throttling
Vault deleted in a test teardown and re-created with the same nameCreate fails on the name until az keyvault purge or retention ends

Which side is wrong

  • No token (ManagedIdentityCredential…, IMDS or IDENTITY_ENDPOINT errors) → the app side: is the identity attached, and is the right client ID passed? (reference/managed-identity/errors.md)
  • 403 naming the client IP → the vault's network rules.
  • 403 ForbiddenByRbac → the role: missing, on a group, or not propagated yet.
  • 403 about access-policy permissions → the vault is in access-policy mode: switch it, or add a policy.
  • 401 → the token's audience isn't https://vault.azure.net. Custom HTTP code is asking for the wrong scope.

az keyvault show -n <vault> --query "properties.{rbac:enableRbacAuthorization, network:networkAcls, public:publicNetworkAccess}" answers the vault-side questions in one call.

Read this document as markdown — the same bytes an agent receives.