azureblog.co.uk
← cd ~/posts

Managed identities vs service principals: which should your workload use?

Both let code authenticate to Azure and Microsoft Graph. One needs you to manage secrets; the other doesn't. A simple guide to choosing.

2 min read⚠ checked 7 Jan 2026Azure · Entra ID · Security
On this page
  1. Service principals
  2. Managed identities
  3. How to choose
  4. How a managed identity gets a token
  5. Gotchas

Every automation, app and pipeline that talks to Azure needs an identity. There are two common choices, and picking the right one removes a whole class of outages and security risks.

Where does the code run?
In AzureManaged identity
Outside Azure, supports OIDCWorkload identity federation
NeitherApp registration with a certificate in Key Vault
Choosing an identity for a workload.

Service principals

An with a authenticates using a client secret or certificate. It works from anywhere: your laptop, another cloud, a SaaS product. The cost is credential management: secrets expire, get pasted into scripts and leak.

Managed identities

A is a service principal that Azure manages for you. There are no credentials to store or rotate. The Azure resource gets tokens directly from the platform.

  • System-assigned: tied to one resource and deleted with it. Good for a single app with its own permissions.
  • User-assigned: a standalone resource you can attach to several resources. Good when multiple resources need the same access, or when you want the identity to outlive the resource.

System-assigned

  • Created with the resource
  • Deleted with the resource
  • One identity per resource

User-assigned

  • A standalone Azure resource
  • Can be shared by several resources
  • Survives redeployments
System-assigned versus user-assigned.

How to choose

  • Code running in Azure (Functions, App Service, VMs, Automation, Container Apps): use a managed identity.
  • Code running outside Azure that supports , such as GitHub Actions or another cloud: use workload identity federation, which also needs no secrets.
  • Only when neither is possible: a service principal with a certificate, stored in , with a short lifetime and a named owner.
powershell
# Give a Function App's system-assigned identity read access to a storage account
$principalId = az functionapp identity assign -g rg-app -n func-app --query principalId -o tsv
az role assignment create --assignee $principalId \
  --role "Storage Blob Data Reader" \
  --scope "/subscriptions/<sub-id>/resourceGroups/rg-data/providers/Microsoft.Storage/storageAccounts/stdata"
Least privilege still applies: no secret doesn't mean no risk. Scope role assignments to the resource, not the subscription.

How a managed identity gets a token

Your codeAzure platformEntra IDStorageAsk local endpoint fora token1Request token for thisresource's identity2Access token3Read blob with token4Check RBAC role
No secret anywhere: Azure vouches for the resource.

In code you rarely call the endpoint directly. The Azure SDKs' DefaultAzureCredential picks up the managed identity automatically, and in PowerShell it's Connect-AzAccount -Identity or Connect-MgGraph -Identity.

Gotchas

  • Role assignments can take a few minutes to apply. Retry before assuming the setup is wrong.
  • Managed identities can be granted application permissions, but not through the portal's API permissions blade; use PowerShell or the Graph API.
  • Deleting a resource deletes its system-assigned identity and its role assignments with it.

This post was last checked against Microsoft's documentation over six months ago. The approach should still hold, but check the linked sources for anything that has changed before you act on it.

Next in Automating Entra and Azure safely · part 2 of 5Unattended Graph PowerShell scripts with certificate authentication →