Managed Identities vs Service Principals: What's the Actual Difference?

If you've spent any time in Azure, you've probably used these terms interchangeably at some point. When I sat the SC-500 exam, managed identities came up frequently, which tells you it's a distinction worth actually understanding, not just waving your hands at. Getting it wrong isn't just semantics either, it affects how secure your automation and applications actually are.

Why it matters

A developer commits a script to a public GitHub repo. Buried in a config file is a client secret for a service principal with Contributor access to a subscription. It gets scraped by a bot within hours, and someone has access into your Azure environment.

This happens constantly, and it's almost entirely preventable. In a lot of these cases, the app didn't need a service principal with a stored secret at all, it needed a managed identity.

What is a Service Principal?

When you register an application in Entra ID, two objects get created: the App Registration (the global definition of your app) and the Service Principal (the local instance of that app in your tenant, which is what actually gets assigned roles and authenticates). Think of the App Registration as the blueprint, and the Service Principal as the object built from it.

Service principals authenticate using a client secret, a certificate, or a federated credential (more on that below), and whoever owns the app is responsible for creating, rotating, and revoking those credentials. That responsibility is exactly where things tend to go wrong.

What is a Managed Identity?

A managed identity is Azure's answer to "why am I storing secrets for infrastructure that's already running inside my trusted environment?" Instead of you managing credentials, Azure creates an identity tied directly to a resource, a VM, App Service, Function App, and so on, and handles authentication behind the scenes. There's no secret to store, rotate, or accidentally commit to GitHub.

There are two flavours. A system-assigned identity is created and deleted along with the resource it's attached to, in a strict one-to-one relationship, simple, but if the resource gets recreated (common in IaC deployments), the identity and its role assignments get recreated too. A user-assigned identity is a standalone resource that can be attached to multiple resources at once, so it survives redeployments and works well when several resources need the same access.

Wait, aren't these the same thing?

Here's the bit that trips people up: a managed identity is a service principal. It's the exact same object type in Entra ID, just flagged differently, with Azure taking over the credential lifecycle entirely instead of leaving it to you. The real distinction isn't "two different kinds of identity", it's "who's responsible for the credentials." With a standard service principal, you are. With a managed identity, Azure is.

Decision guide

  • App runs on Azure compute (VM, App Service, Function, AKS pod) — use a Managed Identity

  • App runs outside Azure (on-prem, another cloud, local dev) — use a Service Principal

  • Multi-tenant SaaS app installed into other tenants — use a Service Principal (App Registration)

  • Multiple resources need to share one identity — use a User-assigned Managed Identity

  • CI/CD pipeline (GitHub Actions, Azure DevOps) — use a Service Principal with federated credentials

  • Script running on a VM that talks to Key Vault or Storage — use a Managed Identity.

Federated credentials

Managed identities only work for things running inside Azure, so what about pipelines like GitHub Actions that need to authenticate from outside it? Federated credentials solve this: instead of storing a client secret, you configure a trust relationship between the service principal and the external identity provider. GitHub issues a short-lived OIDC token, Entra ID validates it, and your pipeline gets an access token with no secret stored anywhere. If you're still using client secrets in CI/CD, this is worth migrating to.

Common mistakes

Teams often default to creating an app registration with a secret out of habit, even when the workload runs on Azure compute and a managed identity would work with zero credential overhead. Service principals calling Microsoft Graph need API permissions plus admin consent, a different model from managed identities using standard RBAC role assignments, and mixing these up causes plenty of "why can't my identity access this" debugging sessions. Finally, it's worth periodically auditing your tenant for old app registrations with secrets nearing expiry, and converting them to managed identities or federated credentials where possible.

Key takeaways

A managed identity is a service principal, just one where Azure manages the credentials instead of you. Default to managed identities for anything running on Azure compute. Reach for service principals when your workload lives outside Azure or you're building a multi-tenant app. Use federated credentials to eliminate secrets from CI/CD pipelines. And periodically audit your tenant for long-lived secrets — they're a bigger risk than most people realise.

Every secret you don't have to store is a secret that can't leak.

Next
Next

Device compliance and its importance within conditional access policies.