Managed Identity Authentication

Overview

Azure Key Vault supports authentication via Managed Identities, eliminating the need to store credentials in code or configuration. This is the recommended approach for Azure-hosted workloads accessing Key Vault secrets, keys, and certificates.


System-Assigned vs User-Assigned Identity

FeatureSystem-AssignedUser-Assigned
LifecycleTied to the resourceIndependent
SharingOne per resourceCan be shared across resources
Use caseSingle-purpose workloadsMulti-resource scenarios
DeletionDeleted with resourceMust be explicitly deleted

When to Use Each

  • System-assigned: Simple scenarios where one resource needs Key Vault access (e.g., a single App Service).
  • User-assigned: When multiple resources (Functions, App Services, VMs) need the same identity and permissions.

DefaultAzureCredential

The DefaultAzureCredential class from the Azure Identity SDK provides a unified authentication flow that works across local development and production.

Authentication Chain

  1. Environment variables
  2. Workload Identity (Kubernetes)
  3. Managed Identity (system or user-assigned)
  4. Visual Studio credential
  5. Visual Studio Code credential
  6. Azure CLI credential
  7. Azure PowerShell credential
  8. Azure Developer CLI credential
  9. Interactive browser (disabled by default)

.NET Example

using Azure.Identity;
using Azure.Security.KeyVault.Secrets;

var credential = new DefaultAzureCredential();
var client = new SecretClient(
    new Uri("https://my-vault.vault.azure.net/"),
    credential
);

KeyVaultSecret secret = await client.GetSecretAsync("DatabaseConnectionString");
string connectionString = secret.Value;

Python Example

from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient

credential = DefaultAzureCredential()
client = SecretClient(
    vault_url="https://my-vault.vault.azure.net/",
    credential=credential
)

secret = client.get_secret("DatabaseConnectionString")
print(secret.value)

Node.js Example

const { DefaultAzureCredential } = require("@azure/identity");
const { SecretClient } = require("@azure/keyvault-secrets");

const credential = new DefaultAzureCredential();
const client = new SecretClient(
  "https://my-vault.vault.azure.net/",
  credential
);

const secret = await client.getSecret("DatabaseConnectionString");
console.log(secret.value);

Enabling Managed Identity

Azure CLI — System-Assigned

# Enable on App Service
az webapp identity assign --name my-app --resource-group my-rg

# Enable on Azure Function
az functionapp identity assign --name my-func --resource-group my-rg

Azure CLI — User-Assigned

# Create the identity
az identity create --name my-identity --resource-group my-rg

# Assign to App Service
az webapp identity assign \
  --name my-app \
  --resource-group my-rg \
  --identities /subscriptions/{sub}/resourceGroups/my-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/my-identity

Granting Key Vault Access

After enabling managed identity, grant it access to Key Vault:

# Get the principal ID
PRINCIPAL_ID=$(az webapp identity show --name my-app --resource-group my-rg --query principalId -o tsv)

# Assign RBAC role (recommended over access policies)
az role assignment create \
  --role "Key Vault Secrets User" \
  --assignee $PRINCIPAL_ID \
  --scope /subscriptions/{sub}/resourceGroups/my-rg/providers/Microsoft.KeyVault/vaults/my-vault

Specifying User-Assigned Identity in Code

When using a user-assigned identity, pass the client ID explicitly:

var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions
{
    ManagedIdentityClientId = "your-user-assigned-client-id"
});
credential = DefaultAzureCredential(
    managed_identity_client_id="your-user-assigned-client-id"
)

Local Development

For local development, DefaultAzureCredential falls back to Azure CLI or Visual Studio credentials:

# Login with Azure CLI
az login

# Set the subscription context
az account set --subscription "my-subscription"

No code changes needed — the same DefaultAzureCredential works locally and in production.


Common Errors

ErrorCauseFix
ManagedIdentityCredential authentication unavailableIdentity not enabledEnable managed identity on the resource
403 ForbiddenMissing RBAC roleAssign Key Vault Secrets User role
SecretNotFoundWrong vault URL or secret nameVerify vault URL and secret name
CredentialUnavailableErrorNo valid credential in chainEnsure az login locally or identity enabled in Azure

Best Practices

  1. Always use Managed Identity over connection strings or client secrets for Azure-hosted workloads.
  2. Prefer RBAC over vault access policies for granular, auditable permissions.
  3. Use user-assigned identities when multiple services share the same access pattern.
  4. Never log secret values — reference them by name in diagnostics.
  5. Test locally with az login to validate the credential chain before deploying.
  6. Set AZURE_CLIENT_ID environment variable in App Service when using user-assigned identity.

Summary

Managed Identity with DefaultAzureCredential is the zero-secret approach to Key Vault authentication. It works seamlessly across development and production, eliminates credential management overhead, and integrates with Azure RBAC for fine-grained access control.