Managed Identity vs Service Principal vs SAS Token¶
TL;DR¶
Managed identity for Azure-to-Azure workloads (zero secrets to manage). Service principal for external integrations or cross-tenant access, preferring federated credentials (OIDC) over secrets. SAS tokens only for legacy or temporary blob access with short expiry.
When this question comes up¶
- Granting an Azure service access to another Azure resource (Key Vault, Storage, SQL).
- Configuring a CI/CD pipeline (GitHub Actions, Azure DevOps) to deploy into Azure.
- Sharing blob data with an external partner or legacy system that cannot authenticate via Entra ID.
- Migrating from connection-string or key-based auth to identity-based auth.
- Designing an IoT device credential strategy.
Decision tree¶
flowchart TD
start["What is authenticating?"] -->|Azure service calling Azure service| q_mi
start -->|External CI/CD or cross-tenant app| q_sp
start -->|Temporary external blob access| rec_sas["**Recommend:** SAS Token<br/>(short expiry)"]
start -->|IoT device| rec_cert["**Recommend:** X.509 certificates<br/>(see IoT migration)"]
start -->|Human user| rec_entra["**Recommend:** Entra ID<br/>+ Conditional Access"]
q_mi{"Multiple resources share<br/>the same identity?"}
q_mi -->|No — single resource| rec_sys["**Recommend:** System-Assigned<br/>Managed Identity"]
q_mi -->|Yes — shared lifecycle| rec_usr["**Recommend:** User-Assigned<br/>Managed Identity"]
q_sp{"Can the external IdP<br/>federate with Entra ID?"}
q_sp -->|Yes — GitHub, GitLab, GCP| rec_fed["**Recommend:** Service Principal<br/>(federated / OIDC)"]
q_sp -->|No — legacy system| rec_sec["**Recommend:** Service Principal<br/>(client secret, short-lived)"] Per-recommendation detail¶
Recommend: System-Assigned Managed Identity¶
When: A single Azure resource (VM, App Service, Function, AKS pod) needs to call other Azure services. Why: Zero secrets; lifecycle tied to the resource; auto-rotated by the platform. Tradeoffs: Blast radius limited to one resource; deleted when the resource is deleted; no reuse across resources; supported only within Azure. Anti-patterns:
- Trying to use managed identity from outside Azure (on-prem, other clouds).
- Creating a system-assigned identity then sharing its object ID across unrelated services.
Linked example: Identity & Secrets Flow
Recommend: User-Assigned Managed Identity¶
When: Multiple Azure resources need the same identity (e.g., a set of microservices sharing RBAC roles). Why: Decouples identity lifecycle from resource lifecycle; single RBAC assignment covers multiple consumers. Tradeoffs: Slightly more management overhead (separate resource to create/track); still zero secrets; still Azure-only. Anti-patterns:
- Creating one user-assigned identity per resource when system-assigned would suffice.
- Granting a single user-assigned identity overly broad permissions across unrelated workloads.
Linked example: Security & Compliance Best Practices
Recommend: Service Principal (federated / OIDC)¶
When: External CI/CD (GitHub Actions, GitLab CI) or cross-tenant apps that support workload identity federation. Why: No stored secrets; short-lived tokens exchanged via OIDC; auditable via Entra sign-in logs. Tradeoffs: Requires IdP that supports federation; initial setup more complex than a client secret; token lifetime typically 1 hour. Anti-patterns:
- Falling back to client secrets when OIDC federation is available.
- Granting the service principal Owner or Contributor at the subscription level.
Linked example: Key Rotation Runbook
Recommend: Service Principal (client secret)¶
When: External system cannot federate and needs programmatic access; no alternative credential type is supported. Why: Widely supported; works with any HTTP client. Tradeoffs: Secret must be stored securely (Key Vault); requires rotation (90-day max recommended); auditable but higher risk if leaked; blast radius can be broad if over-permissioned. Anti-patterns:
- Long-lived secrets (>6 months) with no rotation policy.
- Storing secrets in source code, environment files, or pipeline variables without vault backing.
- Using a single service principal for all environments (dev/staging/prod).
Linked example: Key Rotation Runbook
Recommend: SAS Token¶
When: Sharing blob/container access with external parties that cannot authenticate via Entra ID; legacy integrations. Why: Scoped to specific resource, permission, and time window; no Entra ID enrollment needed for the consumer. Tradeoffs: Bearer token -- anyone with the token has access; no user-level audit trail; rotation requires re-distributing tokens; revocation requires rotating the storage account key or using stored access policies. Anti-patterns:
- Embedding SAS tokens in source code or client-side JavaScript.
- Issuing SAS tokens with multi-year expiry.
- Using account-level SAS when service-level SAS would suffice.
- Choosing SAS over managed identity for Azure-to-Azure communication.
Linked example: Identity & Secrets Flow
Related¶
- Architecture: Identity & Secrets Flow
- Best practices: Security & Compliance
- Runbook: Key Rotation