Skip to content
HOME / AZURE / AZURE MANAGED IDENTITY BEST 3 weeks AGO

Azure

Azure Managed Identity Best Practices

Azure Managed Identity Best Practices

Last Updated on July 24, 2026 by Arnav Sharma

Most teams adopt managed identities to delete a secret from a config file. That is a worthwhile outcome, but it is the smallest one available. The Azure Managed Identity Best Practices that actually matter are the ones that stop you from replacing a credential sprawl problem with a permission sprawl problem, which is precisely what happens when hundreds of identities are created without a decision framework, an owner, or a cleanup path.

Managed identities for Azure resources is a feature of Microsoft Entra ID that gives an Azure service an identity in the directory, along with a token issued automatically by the platform. In Microsoft Azure, this is the sanctioned mechanism for using managed identities in place of stored credentials, and it is the foundation of modern identity and access management for workloads. There is no client secret to rotate, no certificate to expire, and no credential to leak into source control. That is the marketing. The engineering reality is that you have just created a non-human principal with standing access to your data plane, and the governance obligations that come with it do not disappear because Azure automatically manages the credential lifecycle.

Azure managed identities are the platform’s answer to a problem that identity management has struggled with for a decade: how a workload proves who it is without holding a secret. This guide covers the decision framework for choosing an identity type, the failure modes that only surface at scale, the threat model that managed identities genuinely do not address, and the queries you need to audit what is already deployed.

Why Azure Managed Identity Best Practices Matter More Than the Feature Itself

The feature is straightforward. Enable a managed identity on an Azure virtual machine, grant it a role, and code running on that virtual machine can access Azure resources without a stored credential. Configuring a managed identity for an Azure workload takes a single toggle, and the same pattern applies to almost every Azure service. The Azure Instance Metadata Service endpoint issues the token, the Azure SDK picks it up, and the workload relies on Microsoft Entra ID for authentication transparently. A managed identity is itself an Azure Resource Manager object, which means it can be deployed, tagged, and governed like any other resource.

The governance is not straightforward. Consider what has actually been created:

  • A service principal object in your tenant, consuming directory object quota.
  • One or more Azure RBAC role assignments, consuming subscription role assignment quota.
  • A privilege path from anyone who can execute code on the host resource, through to every resource that identity can reach.
  • An object whose deletion behaviour depends entirely on which of the two types of managed identities you chose, a decision most teams make by clicking whichever radio button was default.

None of that is visible in the portal blade that turned the feature on. Multiply it across a few hundred resources and you have an identity estate nobody designed, nobody owns, and nobody can inventory. The practices below exist to prevent that outcome.

The Two Types of Managed Identities, and What Actually Separates Them

Azure offers system-assigned and user-assigned managed identities. The difference is usually explained as a lifecycle distinction, which is accurate but incomplete. The real distinction is about who owns the identity and when it can be created.

System-Assigned Managed Identities

A system-assigned managed identity is tied to a specific Azure resource. You enable a system-assigned managed identity directly on the resource, and it exists only for that resource. A system assigned managed identity therefore has no independent existence. When the resource is deleted, Azure automatically deletes the identity along with it. The identity is tied to exactly one thing and cannot be shared.

This coupling is the feature, not a limitation. If you need audit logs that attribute an action to a specific virtual machine rather than to a shared identity, a system assigned managed identity is the only option that gives you that. If your compliance position requires that permissions vanish the moment a resource is decommissioned, the automatic deletion is doing real work for you.

The cost of that coupling is sequencing. Because system-assigned identities are created and deleted along with the resource, role assignments cannot be created in advance. Whoever deploys the resource must also hold permission to create role assignments at deployment time, or the deployment fails partway through. In a mature platform team with a separation between infrastructure delivery and identity administration, that is an awkward requirement.

User-Assigned Managed Identities

A user-assigned managed identity is created as a standalone Azure resource. It has its own resource ID, sits in a resource group, and is managed separately from the resources that consume it. You create a user-assigned managed identity once, then assign the managed identity to one or more Azure resources. The same single identity can be used by multiple resources, and its lifecycle is independent of all of them. In effect, user-assigned identities can be used as a shared credential-free principal, and a single user assigned managed identity can serve an entire workload tier.

Microsoft’s own guidance is that user-assigned managed identities are more efficient in a broader range of scenarios than system-assigned managed identities, and the reasoning is worth internalising. Because user-assigned identities are created ahead of the workloads that use them, you can:

  • Create the identity and all of its role assignments in advance, as a distinct change with distinct approvals.
  • Grant deployment engineers only the rights to attach an existing identity, not to create new identities or new role assignments.
  • Share a single identity across replicated workloads so that four servers require two role assignments rather than eight.
  • Avoid the Entra object creation rate limits that appear when you deploy many resources at once, each with its own identity.

The tradeoff is that lifecycle independence cuts both ways. When a consuming resource is deleted, the identity survives. If nobody deletes it, you have accumulated an orphan with live permissions and no owner.

Lifecycle Comparison Table

BehaviourSystem-assignedUser-assigned
CreationCreated with the host resourceCreated as a standalone Azure resource, independently
ScopeBound to a single Azure resourceCan be shared across multiple Azure resources
Role assignment timingCannot be pre-createdCan be created in advance of any workload
DeletionAzure automatically deletes it when the resource is deletedMust be manually deleted, even when no resources are attached
Role assignments on deletionNot automatically removedNot automatically removed
Audit attributionAction attributable to the specific resourceAction attributable to the shared identity, not the caller
PortabilityNoneAttach and detach freely

The row that catches most teams out is the second-last one. Role assignments are not automatically deleted when either system-assigned or user-assigned managed identities are deleted. Even when the identity is gone, the assignment persists. Role assignments associated with deleted managed identities show as “Identity not found” in the portal and continuing to count against your subscription role assignment limit.

A Decision Framework for Choosing the Identity Type

Microsoft publishes a scenario table. It is accurate but it requires you to already know which scenario you are in. The following sequence produces an answer from first principles. Work through it in order and stop at the first question that returns a decisive answer.

The Five Questions

1. Does the resource need access before it finishes deploying? If yes, use a user-assigned identity. A system-assigned identity may not exist in time, and the deployment will fail.

2. Do I need the audit log to name the specific resource that acted? If yes, use a system-assigned identity. A shared identity across multiple resources destroys attribution at the identity layer, and you will be reconstructing the caller from correlation IDs.

3. Must the permissions disappear the instant the resource does? If yes, use a system-assigned identity and accept the sequencing pain. This is the only configuration where the platform enforces the cleanup for you.

4. Will more than one resource need exactly this permission set? If yes, use a single user-assigned identity across all of them. This is the administrative overhead reduction argument, and at any meaningful scale it dominates everything else.

5. Am I creating or destroying resources rapidly? If yes, use a user-assigned identity. Rapid creation of many system-assigned identities can exceed the Entra object creation rate limit and return HTTP 429. Worse, a deleted system-assigned identity continues to count towards your directory limit until it is fully purged after 30 days, so a churning ephemeral compute estate can exhaust quota with identities that no longer serve any purpose.

If you reach the end without a decisive answer, default to user-assigned. The failure mode of a user-assigned identity is an orphan you can detect with a query. The failure mode of a system-assigned identity at scale is a rate limit that fails your deployment pipeline at three in the morning.

Worked Examples

WorkloadAnswerDriver
Autoscaling web tier, twelve identical instancesUser-assignedQuestion 4. One identity, one role assignment set, twelve consumers.
An Azure Logic App orchestrating a regulated payment flowSystem-assignedQuestion 2. Attribution is the control.
Ephemeral build agents, created and destroyed hourlyUser-assignedQuestion 5. System-assigned would exhaust object quota.
A single Azure Functions app reading one Azure Key Vault secretEither, lean system-assignedNo question returns decisively. Simplicity wins on a genuine one-to-one.
A shared data platform where an Azure service must reach several storesUser-assignedQuestion 4, plus Question 1 if the identity is needed at deployment.

What Managed Identities Do Not Fix

This is the section every competing article omits, and it is the one that matters most to a security architect.

Managed identities solve credential management. They do not solve authorisation. The token issued to a managed identity carries whatever privilege you granted it, and it is available to anything running on the host. Removing the secret from the config file does not remove the permission from the workload.

The Blast Radius Problem

When an Azure resource is assigned a managed identity, every permission granted to that identity becomes available to the resource. That means it becomes available to anyone who can execute code on the resource.

Microsoft states this explicitly, and the implication is sharper than it first appears. If a managed identity has read and write access to a storage account, such as a store fronted by an Azure Key Vault secret or a data lake, and is attached to a Logic App, then a user with no direct access to that storage account whatsoever, but with permission to execute code within the Logic App, can read and write to that storage account by running code that uses the identity. The identity is the privilege boundary, not the resource, and not the user’s own role assignments. Anyone who can run code on that host can use the managed identity to access everything it has been granted.

The practical consequences:

  • Every role granted to a managed identity is effectively granted to every principal who can run code on the resources it is attached to.
  • Sharing a user-assigned identity across multiple resources means sharing that privilege across all of them. The convenience and the risk are the same property.
  • Reviewing “who can access this storage account” by listing its direct role assignments will give you an incomplete answer. You must also enumerate the identities with access, then the resources those identities are attached to, then the people who can execute code on those resources.

The Assign Permission Is a Privilege Escalation Path

There is a second, quieter path. If a user has permission to assign the managed identity, they can attach it to a different Azure resource that they control, and inherit every permission that identity holds. The assignment right is therefore a privilege escalation primitive, and it should be governed like one.

This means the Managed Identity Operator role, which grants exactly this ability, is not an innocuous operational role. Treat any grant of it as a grant of the union of all permissions held by the identities in scope. When granting a user administrative access to a resource that can execute code and has a managed identity attached, ask whether the role being assigned lets them install or run code on that resource, and grant it only if they genuinely require it.

Least Privilege in Practice with Azure RBAC

Least privilege is universally recommended and inconsistently applied. Applied to managed identities in Azure, it decomposes into four concrete rules.

Scope to the narrowest resource that works. Azure RBAC lets you assign at management group, subscription, resource group, or individual resource scope. Making a managed identity a Contributor on an Azure subscription when it needs to read a single blob container is the canonical mistake. Grant the specific data plane role on the specific azure storage account, not a control plane role on the subscription. The same logic applies to a secret store like Azure Key Vault, where the vault, not the subscription, is the correct scope.

Choose data plane roles, not control plane roles. Storage Blob Data Reader is a very different grant from Reader. Key Vault Secrets User is a very different grant from Key Vault Contributor. Teams reach for the control plane role because it appears in the top of the picker list and because it works, and in doing so they hand out the ability to modify the resource rather than read from it.

Do not use Entra groups to grant access to azure resources for managed identities. This is the counterintuitive one. Group membership is expressed as claims in the access token, and Azure RBAC evaluates those claims. Managed identity tokens are cached by the backing Azure infrastructure for around 24 hours per resource URI, and there is no supported way to force a refresh. A group membership change can therefore take hours to take effect. Microsoft’s recommendation is to group your Azure resources using a user-assigned managed identity with permissions applied directly to the identity, rather than adding and removing identities from a group. The user assigned identity becomes the grouping construct.

Grant one identity one job. A single identity accumulating permissions across unrelated systems is a lateral movement bridge. If the same principal can reach the CI artefact store and the production database, an attacker who lands on any host holding that identity can reach both.

Failure Modes That Only Appear at Scale

Everything above is a design concern. The following are operational failures that a proof of concept will never surface.

Entra Object Creation Rate Limits

Each system-assigned identity requires the creation of a service principal object in Microsoft Entra ID. Attempting to create many managed identities in a short window, for example deploying a large scale set where each node carries its own system-assigned identity, can exceed the rate limit for Microsoft Entra object creations. The request fails with HTTP 429.

The failure is intermittent and load dependent, which makes it a genuinely miserable class of bug. It appears in production, under scale-out, and never in test. Deploying resources associated with a single user-assigned identity requires only one service principal to exist in Entra ID, which is why user-assigned is the correct answer for ephemeral and replicated compute.

There is a second-order effect worth knowing. While a deleted system-assigned identity is no longer usable by any resource, it counts towards your directory limit until it is fully purged after 30 days. An estate that creates and destroys resources rapidly can therefore exhaust quota with identities that are already dead.

The Token Cache Delay

Covered above as an authorisation constraint, but it needs restating as an operational one. If you revoke a managed identity’s group membership in response to an incident, the workload may continue to hold effective access for hours. Your incident runbook for a compromised host must not assume that removing a group membership is a containment action. Remove the role assignment directly, or detach the identity from the resource, or stop the resource.

Orphaned Role Assignments

Role assignments are not cleaned up when the identity behind them is deleted. This is true for both system-assigned and user-assigned managed identities. The debris accumulates against your subscription’s role assignment limit, and at sufficient volume you will be unable to create new assignments in a subscription that appears, from the portal, to be sparsely configured.

Role assignments no longer associated with a user or a service principal appear with an ObjectType value of Unknown, and Azure PowerShell can find and remove them:

Get-AzRoleAssignment | Where-Object {$_.ObjectType -eq "Unknown"} | Remove-AzRoleAssignment

Run it as a scheduled task. Under a managed identity, naturally, scoped to the subscriptions it needs and holding only the User Access Administrator rights required to remove assignments.

Building an Operating Model

The technical practices fail without an ownership model. The lifecycle of user-assigned identities allows you to separate your resource creation and identity administration responsibilities, and that separation is the point. Most organisations never take it, and end up with application teams minting identities and role assignments on demand, which is functionally identical to letting them mint their own service principal credentials.

A workable split:

ResponsibilityOwnerAzure role
Create a user-assigned managed identityPlatform or identity teamManaged Identity Contributor, scoped to an identity resource group
Grant a role to that identityIdentity or security team, via change approvalUser Access Administrator at the target scope
Attach an existing identity to a workloadApplication or delivery teamManaged Identity Operator on the specific identity
Deploy the workload resourceApplication or delivery teamContributor on the workload resource group
Delete orphaned identities and assignmentsPlatform team, scheduledAutomated, under a managed identity

The critical property of this split is that the delivery team can attach the managed identity to their workload but cannot expand what it can reach. Permission expansion is a separate change, in a separate scope, owned by a separate team. That is achievable with user-assigned identities and structurally impossible with system-assigned ones, because there is no identity to pre-approve.

Two supporting rules make it hold:

  • Name identities after their permission set, not their consumer. id-blobreader-prod-eastus survives the workload it was created for. id-appsvc-01 does not, and its permissions will drift as it is reused.
  • Define the identity in the same infrastructure as code as the role assignment. If the identity and its permissions are created by different pipelines, they will diverge, and the drift will be invisible.

Detecting and Auditing Your Existing Estate

You almost certainly have managed identities you did not plan. Find them before you write a policy about them. The following use the Azure CLI and Azure Resource Graph.

List every user-assigned identity in the current azure subscription:

az identity list --query "[].{name:name, rg:resourceGroup, principalId:principalId, location:location}" -o table

Find every resource in a subscription that has any identity enabled, across every azure service that supports managed identities. This is the single most useful query in this article, because it is the one that shows you the shape of the estate:

resources
| where isnotnull(identity)
| project name, type, resourceGroup,
          identityType = tostring(identity.type),
          userAssigned = tostring(bag_keys(identity.userAssignedIdentities))
| order by type asc

Find user-assigned identities that are attached to nothing, which are the orphans generated by the lifecycle independence described earlier:

resources
| where type =~ "microsoft.managedidentity/userassignedidentities"
| project identityId = tolower(id), name, resourceGroup
| join kind=leftanti (
    resources
    | where isnotnull(identity.userAssignedIdentities)
    | mv-expand assigned = bag_keys(identity.userAssignedIdentities)
    | project identityId = tolower(tostring(assigned))
) on identityId

Then enumerate what a given identity can actually reach, which is the question the blast radius section demands you be able to answer:

az role assignment list --assignee <principalId> --all --include-inherited -o table

Cross-reference the output of the last two. An identity with broad permissions and no attached resource is a standing risk with no business justification. An identity with broad permissions attached to a resource that a large group can execute code on is worse, because it is being actively used.

Migrating Off Service Principals

Where an Azure workload authenticates with a registered application and a client secret, replacing it is nearly always correct. The goal is to create a user-assigned managed identity and assign it in place of the secret. A service principal with a secret gives you a credential to store, a credential to rotate, a credential to leak, and an expiry date that will eventually take down production on a public holiday. Managed identities remove all four.

The migration is mechanical:

  1. Inventory the role assignments held by the existing service principal.
  2. Create a user-assigned managed identity, or enable a system-assigned managed identity on the target resource, per the decision framework above.
  3. Replicate the role assignments onto the new principal. Treat this as an opportunity to narrow them, not to copy them, because the original grant was almost certainly wider than required.
  4. Update the application to use the Azure Identity library rather than a secret. In most SDKs this is a change of credential class, not a change of code shape.
  5. Run both in parallel, confirm the new identity is authenticating via Microsoft Entra authentication, then disable the old credential before deleting it.
  6. Delete the application registration, and remove its now-orphaned role assignments.

Two cases where a service principal is still the right answer: workloads outside Azure that cannot reach the metadata endpoint, and federated scenarios where an external system needs to authenticate to Azure. For the latter, workload identity federation lets an external identity provider exchange a token for Azure access without a stored secret, which is closer to the managed identity model than to a classic secret. Do not use the Azure CLI or Azure PowerShell to hand-create long-lived secrets simply because the tooling makes it easy.

Arnav Sharma
Arnav Sharma Microsoft MVPMCT
Microsoft Certified Trainer · Cloud · Cybersecurity · AI

I help organisations secure their cloud infrastructure and stay ahead of evolving cyber threats. Microsoft MVP and Certified Trainer, author of Mastering Azure Security, and founder of arnav.au — a platform for practical Cloud, Cybersecurity, DevOps and AI content.

Frequently Asked Questions

KEEP READING

Leave a reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.