Email copiado — support@tuurt.com
Cargando experiencia
azure · August 24, 2026 · 7 min

Managed Identity in Azure: getting connection strings out of your code without leaning on a misconfigured Key Vault

Managed Identity solves authentication between Azure resources without storing credentials, but only once you understand system vs. user-assigned identity and the RBAC errors around it.

By Tuurt Team

Managed Identity in Azure: getting connection strings out of your code without leaning on a misconfigured Key Vault

Every time we review a new Azure project, the same pattern shows up: a SQL Server connection string or a Storage Account key sitting in appsettings.json, in an App Service environment variable, or — worst case — hardcoded directly in the source and pushed to the repo in some old commit nobody looked at closely. The usual answer is "let's put everything in Key Vault," which is a correct step, but it leaves the question that actually matters unanswered: what credential does the application use to authenticate against that Key Vault? If the answer is still "a connection string or client secret stored in an environment variable," the problem wasn't eliminated, it was just pushed up one level. Managed Identity is the piece that closes that loop: an Azure AD identity tied directly to the resource running the code, with no credential for anyone to store, rotate, or accidentally leak.

What Managed Identity solves, and what it doesn't

Managed Identity gives an Azure resource — an App Service, a Function App, a VM, an AKS cluster — an identity in Azure AD that other Azure services can recognize and authorize via RBAC. The application requests a token against that identity through the resource's local metadata endpoint, and that token never depends on any secret stored in configuration. This solves authentication between Azure resources: App Service against SQL Database, Function App against Storage, AKS against Key Vault or Service Bus.

What it doesn't solve is authentication against services that aren't Azure resources. An external API, an on-premise database with no Azure AD integration, or a third-party SaaS still need some form of stored credential, and that's where Key Vault remains the right piece — except now the application authenticates against Key Vault with Managed Identity instead of a secret of its own. The chain of trust ends at an identity Azure manages, not at a secret someone had to write down somewhere.

System-assigned vs. user-assigned identity

Azure offers two variants, and the difference between them isn't just syntax — it's lifecycle.

A system-assigned identity is created alongside the resource and dies with it. An App Service with this identity enabled has a principalId in Azure AD that exists for as long as the App Service does; delete the resource and the identity disappears automatically, taking with it any RBAC permission that had been granted to it. It's the right choice when the identity only makes sense in the context of that specific resource and doesn't need to be shared with anything else.

az webapp identity assign \
  --name pedidos-api \
  --resource-group prod-rg

A user-assigned identity is an independent Azure resource with its own lifecycle, one that can be attached to one or several resources at once. It makes sense when multiple services need to share the same set of permissions — say, three Function Apps that all need to read from the same Key Vault — because instead of assigning the RBAC role three times, once per system identity, you assign it once to the shared identity and attach that identity to all three resources.

az identity create \
  --name id-pedidos-shared \
  --resource-group prod-rg

az webapp identity assign \
  --name pedidos-api \
  --resource-group prod-rg \
  --identities /subscriptions/.../resourceGroups/prod-rg/providers/Microsoft.ManagedIdentity/userAssignedIdentities/id-pedidos-shared

The tradeoff is that a user-assigned identity outlives the resource that uses it: delete the App Service and forget to also delete the identity, and you're left with a principal holding active RBAC permissions with no real resource behind it — exactly the kind of orphaned resource a security advisor flags months later with nobody remembering where it came from.

Using it from code: DefaultAzureCredential

In .NET, the piece that lets the same code run locally and in Azure without changing a line is DefaultAzureCredential, from Azure.Identity. Internally it walks a chain of authentication mechanisms in order — environment variables, Managed Identity, Visual Studio, Azure CLI, among others — and uses the first one it finds available.

var credential = new DefaultAzureCredential();

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

var secret = await client.GetSecretAsync("connection-string-sql");

In production, inside the App Service, DefaultAzureCredential detects the Managed Identity metadata endpoint and uses it directly, with no secret anywhere in the application's configuration. On each developer's local machine, the same line of code falls through to Azure CLI authentication (az login), provided that person has RBAC permissions assigned on the development Key Vault. That has a practical consequence worth anticipating: every developer needs their own RBAC permission on the development resources — it isn't enough for the application to have permissions in production. When someone new joins the team and their local environment fails with an authorization error against Key Vault, this is almost always why, not a problem with the code.

The RBAC errors that show up every time

The most common error isn't authentication but authorization: the identity authenticates correctly against Azure AD and gets a valid token, but the target resource responds with 403 Forbidden because nobody assigned it the RBAC role it needs on that specific resource. Enabling Managed Identity on an App Service doesn't grant any permission by itself — it only creates the identity. The permission is a separate step, and it's the step people forget most:

az role assignment create \
  --assignee <principalId-of-the-managed-identity> \
  --role "Key Vault Secrets User" \
  --scope /subscriptions/.../resourceGroups/prod-rg/providers/Microsoft.KeyVault/vaults/kv-pedidos-prod

A second frequent mistake is assigning the role to the identity's clientId instead of its principalId (objectId): they're two different values even though both show up in the output of az identity show, and using the wrong one produces a "principal not found" error when creating the assignment, so at least it surfaces quickly.

The third is about propagation, not configuration: a freshly created RBAC role assignment can take a few minutes to propagate through Azure AD before the identity's token reflects the new permission. A pipeline that assigns the role and, seconds later, tries to use the protected resource can fail with an intermittent 403 — not because the configuration is wrong, but because it hasn't propagated yet. The fix isn't to assume the role is misassigned; it's to allow a reasonable margin, or to separate the permission assignment from the deployment that consumes it.

The fourth, specific to Key Vault, is confusing the legacy access-policy model with RBAC. A Key Vault can be configured to use either model, and assigning an RBAC role on a vault that's still on access policies has no effect: the identity keeps getting 403 until someone migrates the vault to the Azure RBAC permission model or adds the identity as an explicit access policy. It's worth confirming with az keyvault show which of the two models the vault actually has active before debugging the role assignment.

The particular case of AKS

In an AKS cluster, the node's managed identity — the one the cluster itself uses to talk to the load balancer or the managed disk — is different from the identity a pod needs to reach Key Vault or Storage. Using the node's identity directly from a pod would expose those permissions to any other pod running on the same node, breaking the isolation expected between different workloads in the same cluster.

The current solution is Workload Identity Federation: you create a user-assigned identity, configure a federated credential between that identity and a specific Kubernetes service account, and only pods using that service account — identified by its namespace and name — can obtain tokens with that identity. Two pods on the same node, using different service accounts, end up with access to completely different Azure resources, which is the isolation the node identity alone can't provide.

What's still left out

Managed Identity doesn't remove the need to think about secrets, it just reduces the number of places where a real secret has to exist. Credentials for services outside Azure, and any sensitive data that isn't itself an Azure resource, still need an explicit secrets-management mechanism, with Key Vault as the central piece and Managed Identity as the way to reach it without adding one more secret to the chain.

azure managed-identity rbac devops
← Back to blog