Est.
FeaturesLong read

What Azure Managed Identity Replaces and When to Use It

Eliminates stored credentials for workloads running inside Azure.

Reporter · · 11 min read
Features · September 28, 2026 · 11 min read · 2,506 words

Azure Managed Identity takes the entire category of stored credentials and deletes it, at least for anything running inside Azure. Connection strings, SAS tokens, certificates, service principal secrets: all of it gets replaced by a token system the platform manages on its own. What follows maps what each credential type gets swapped out for, and where the limits sit, because Managed Identity doesn't cover everything, and knowing where it stops matters as much as knowing where it works.

The credential problem that Managed Identity is designed to solve

Anyone who's set up a secrets pipeline knows the loop. An environment variable leaks into a CI/CD log or ends up sitting in Terraform state somewhere it shouldn't. Someone proposes a secret manager to fix it. Then the secret manager needs its own credentials to run, and the loop starts over from the top. That's the default shape of credential management once a team has more than a couple of services talking to each other, not a hypothetical.

Microsoft's own documentation on managed identities states that manual handling of secrets and certificates is a known source of security issues and outages. Not a possible source. A known one.

Managed Identity's answer isn't a better vault or a smarter rotation schedule. It removes the credential from the picture entirely, for any workload actually running inside Azure. The application authenticates as itself, using an identity that Azure manages on its own, and no static string exists anywhere in the codebase or the config. There's nothing to leak because there's nothing sitting there to find.

How Managed Identity works under the hood

The resource itself never holds a password. Instead, it asks for a short-lived token from the Azure Instance Metadata Service, an endpoint at 169.254.169.254 that's only reachable from inside Azure's own infrastructure.

That token is what gets handed to other Azure services for authentication. Nothing is stored on disk, nothing needs manual rotation, and nothing can end up committed to a repository by accident, because there's no string to commit in the first place.

Microsoft says managed identities give code running on an Azure resource access to other resources, without developers needing to handle or put credentials directly into code. That phrase, "code running on an Azure resource," carries real weight in defining the system's boundary. It's the whole boundary of the system.

Which means a laptop sitting on a home network can't reach the Instance Metadata Service. When enabled, Azure creates an identity in Microsoft Entra ID tied to the resource's lifecycle. The constraint matters: a local development machine cannot reach the Instance Metadata Service, so local dev still needs an alternative, either az login or a development-only service principal, and this is addressed honestly so readers aren't surprised later.

Connection strings, SAS tokens, API keys, and certificates

Start with connection strings. A connection string is an all-or-nothing key: whoever holds it gets full rights to the resource, no matter what they actually need to do with it. Token-based auth flips that around. Access gets scoped to the specific apps meant to reach that resource, so least privilege is baked into the model itself, not bolted on as a policy someone has to remember to enforce.

SAS tokens for storage work the same way. Microsoft's documentation describes managed identities as a safer way to grant access to storage data, one that removes the need to pass SAS tokens around with source and target container URLs. That's one less token to generate, expire, and regenerate every time a job runs.

Certificates got the same treatment, and Microsoft didn't leave this one optional. Azure Automation runbooks running on Run As accounts had to migrate to managed identities by September 30, 2023, a forced deadline that Microsoft actually enforced. That's a strong signal about where the platform is headed: identity-first isn't a suggestion, it's becoming the default.

Picture an Azure Function reading messages off Azure Queue Storage and writing results into Cosmos DB. Turn on a system-assigned managed identity for the function, assign it the RBAC roles it actually needs, and that's the whole job. No stored credential anywhere in the function's configuration.

Four different credential types, one shared trait.

The permission gap that Managed Identity does not close on its own

A lot of teams get a false sense of comfort here. Managed identities make a workload credential-free, but credential-free isn't the same thing as secure. The identity still carries whatever permissions someone assigned to it, and if those permissions are too broad, the risk didn't disappear, it just moved.

Microsoft's documentation says this directly: anyone who can install or run code on a resource with a managed identity gets access to everything that identity can reach, even without ever touching the target resources directly. So a broad role assigned to a shared compute resource quietly hands that same access to every team with deploy rights on it. Credentials are no longer the issue. Excess permissions have become harder to see, because they're no longer sitting visibly in a secrets manager where someone might notice them.

The fix is ordinary RBAC discipline, applied honestly. Storage Blob Data Reader instead of Contributor, if a workload only needs to read blobs. Key Vault Secrets User instead of Key Vault Administrator, if all it does is read secrets. Azure RBAC has purpose-built roles for nearly every common case, and using them narrows the blast radius substantially if a workload ever does get compromised.

System-assigned versus user-assigned identity: choosing the right type and naming convention

System-assigned identities live and die with the resource they're attached to. The identity appears when the resource is created. Creating the resource brings the identity with it, and deleting the resource removes it too. Simple, and fine for a one-off case.

It breaks down at scale, though. Twenty App Services all needing read access to the same storage account turns into twenty separate identities and twenty separate role assignments, all of which need to stay in sync by hand. Missing one during an audit leaves a permission drifting somewhere nobody's tracking.

User-assigned identities exist as their own standalone Azure resource, so they can be shared across multiple resources and their lifecycle doesn't depend on any one of them. Microsoft's current recommendation leans this direction for most scenarios beyond the simplest case. It also means permissions can get approved once, ahead of time, and then assigned to new resources as they're provisioned, without running a fresh approval cycle every single time.

Naming matters more than it sounds like it should. Microsoft's best-practice guidance says to name identities after what they're permitted to do, not after whoever happens to be using them right now. Something like id-blobreader-prod-eastus still makes sense in an audit log long after the workload that first used it is gone. Compare that to id-appsvc-01, which tells an auditor nothing about what it can touch, and whose actual permissions tend to drift quietly as teams and projects change over time.

DefaultAzureCredential and the developer workflow across local and cloud environments

DefaultAzureCredential DefaultAzureCredential makes all of this usable day to day, and it ships as part of the Azure Identity SDK across Python, JavaScript, Java,.NET, and Go. It doesn't ask a developer to write different authentication code for a laptop versus a production deployment.

Instead, it works through a chain, trying each credential source in a fixed order: EnvironmentCredential, WorkloadIdentityCredential, ManagedIdentityCredential, SharedTokenCacheCredential, VisualStudioCodeCredential, AzureCliCredential, AzurePowerShellCredential, and AzureDeveloperCliCredential. That order isn't trivia. It tries a sequence in order (EnvironmentCredential, WorkloadIdentityCredential, ManagedIdentityCredential, SharedTokenCacheCredential, VisualStudioCodeCredential, AzureCliCredential, AzurePowerShellCredential, AzureDeveloperCliCredential), and that ordering matters for debugging and is a frequent source of local dev confusion.

On a developer's own machine, it picks up whatever's sitting in an active az login session. Deployed on an Azure resource with Managed Identity turned on, it grabs a token straight from the Instance Metadata Service instead. Same line of code, both places, no branching logic for "am I local or am I in the cloud."

In practice this looks almost too simple: pass a DefaultAzureCredential instance into a BlobServiceClient constructor, and that's the entire authentication setup. No key, no connection string, no conditional logic checking which environment it's running in.

For a brand-new project, wiring in Managed Identity from day one is far less work than retrofitting it into a codebase that already passes credentials around as strings. This isn't an advanced technique reserved for security teams anymore. For new projects, configuring Managed Identity from the beginning is significantly easier than retrofitting it into an existing codebase that passes credentials around as strings, and the pattern is becoming a baseline expectation rather than an advanced configuration.

Cases requiring a service principal instead of Managed Identity

Three situations still call for a service principal, no way around it. External or hybrid apps hosted outside Azure. CI/CD runners, whether that's GitHub Actions, Azure DevOps, or Jenkins, where the machine executing the job isn't an Azure resource at all. And multi-cloud or on-premises applications that still need to reach into Azure.

Structural factors explain it. None of these run on Azure infrastructure, so there's no Instance Metadata Service endpoint for them to reach. Managed Identity depends entirely on that endpoint existing, and outside the Azure boundary, it simply doesn't.

Service principals come with their own baggage: secrets can leak if they're not stored carefully, they need ongoing lifecycle audits and governance, and they tend toward over-provisioned access. Secrets can leak if they're not stored carefully, they need ongoing lifecycle audits and governance, and they tend toward over-provisioned access because it's easier to grant broad permissions once than to revisit them later. None of that disqualifies service principals. It just means they need the same discipline that Managed Identity was built to avoid needing in the first place.

For Azure DevOps specifically, the guidance is straightforward: use a managed identity when the agent itself is Azure-hosted, and where a service principal is unavoidable, favor workload identity federation or a certificate over a plain client secret, whenever the hosting setup supports it.

Workload Identity Federation as the bridge for CI/CD pipelines and external workloads

Workload Identity Federation closes most of the gap that the Azure boundary opens up. It lets a user-assigned managed identity, or an app registration in Microsoft Entra ID, trust tokens issued by an outside identity provider, GitHub or Google among them.

The GitHub Actions version of this looks like: connect a repository to an Azure identity using OpenID Connect, and when the workflow runs, GitHub hands over a short-lived token that Azure checks and then grants access based on. No secret sits in the repository at any point, and there's nothing to rotate later, because there was never a long-lived credential to begin with. Storing service principal secrets for GitHub Actions deployments to Azure isn't the recommended approach anymore, federation is.

Kubernetes runs its own version of the same idea, distinct from resource-level Managed Identity. Pods get identity through OIDC federation, access control gets set per pod rather than per node, and tokens get issued short-lived and on demand. Manual credential rotation just isn't part of the picture anymore.

Put together, this means the credential-elimination idea behind Managed Identity doesn't stop at the edge of Azure. Federation carries the same principle into CI/CD pipelines and Kubernetes clusters, exactly where Managed Identity itself can't reach.

Managed Identity in AI and GPU workloads on AKS

AI infrastructure on AKS leans on this pattern more than most people expect. BlobFuse2 mounts Azure Blob Storage into Ray worker pods as a POSIX-compatible filesystem, and Managed Identity authenticates that mount without any static key in the pod spec. Datasets and model checkpoints move across pods and node pools without a single credential written into the configuration anywhere.

Get the identity or node setup wrong, though, and the failures get expensive fast. Without correct identity and node configuration, GPU workloads may be scheduled on nodes without GPUs and fail, or general-purpose workloads may occupy GPU nodes instead. Managed Identity is one piece of the configuration discipline that keeps that from happening, not the whole fix, but a necessary part of it.

GPU capacity is scarce enough that teams stretch workloads across multiple clusters and regions, using Azure Kubernetes Fleet Manager and Azure Arc to pull in quota from wherever it's available. Identity and access management has to scale right along with that spread, which is another argument for user-assigned identities with permissions pre-approved ahead of time, over spinning up a fresh system-assigned identity for every resource at that scale.

Migrating from Heroku, Render, or Vercel to Azure App Service with Managed Identity

Teams coming from Heroku, Render, or Vercel are used to one particular pattern: secrets injected as environment variables, DATABASE_URL, API_KEY, and the like. It's a model most developers know cold, and it's exactly the model that stops working cleanly once Azure enters the picture.

The move to Azure App Service doesn't have to mean carrying that same pattern over unchanged. Turn on Managed Identity for the App Service, assign RBAC roles to whatever it needs to reach, Azure SQL, Cosmos DB, Blob Storage, Key Vault, and then swap out the old connection-string code for DefaultAzureCredential. The application code barely changes.

That's the real difference worth noticing here. Teams landing on Azure App Service or AKS have the chance to drop the environment-variable secrets pattern entirely, rather than just carrying it over to a new platform under a different name. Call it a migration if you want, but it's really an upgrade in how the whole system handles trust.

A practical decision flow for enabling Managed Identity, choosing its type, and knowing when service principals or federation remain the right tool

Start with one question: does this workload run on Azure infrastructure? If yes, Managed Identity is close to the default answer, and the only real decision left is which flavor to use.

For a single resource with a permission set that belongs to it alone, system-assigned is fine, and it keeps the resource's lifecycle and its identity locked together with no extra bookkeeping. The moment two or more resources need to share the same access, or a permission set needs to get approved once and reused, switch to user-assigned, and name it for what it's allowed to do, not for whatever happens to be consuming it this quarter https://github.com/microsoft/powerplatform-actions/discussions/576.

If the workload sits outside Azure, in a CI/CD runner, a multi-cloud setup, or anything on-premises, Managed Identity is off the table, full stop, because there's no Instance Metadata Service for it to call. Workload Identity Federation is the right next step there: GitHub Actions, Azure DevOps, and most modern CI/CD tooling support it, and it gets rid of long-lived secrets the same way Managed Identity does inside Azure https://github.com/microsoft/powerplatform-actions/discussions/576. Only when federation genuinely isn't supported does a plain service principal become the fallback, and even then, a certificate beats a client secret every time hosting allows it.

The pattern holds across every one of these cases. Wherever a workload runs inside Azure's boundary, there's no good reason left to hold a static credential.

Sources

  1. How to authenticate Azure apps without storing credentials
  2. Managed identity vs. service principal for Azure apps | TechTarget
  3. Managed Identities vs Service Principals in Azure: A Guide
  4. Managed identities for Azure resources - Managed identities for Azure resources
  5. learn.microsoft.com
  6. Managed Identities in Azure: Why Static Credentials Are a Security Liability
  7. medium.com
  8. ssw.com.au

More in Features