D1 · Identity and Access

Managed Identities

Eliminates credentials from code. An app or VM gets an identity managed by Azure and can authenticate against other services without passwords or hardcoded secrets.

The problem it solves

❌ Without Managed Identity

# App needs to read a secret from Key Vault
# How does it authenticate?

CLIENT_ID = "abc-123"         # hardcoded
CLIENT_SECRET = "s3cr3t!"    # ← DANGER

credential = ClientSecretCredential(
    tenant_id, CLIENT_ID, CLIENT_SECRET
)
client = SecretClient(vault_url, credential)
secret = client.get_secret("db-password")
  • → Secret hardcoded in code or config
  • → Manual rotation = downtime or stale secrets
  • → If the repo leaks → secret compromised
  • → Auditing: impossible to know which app used the secret

✓ With

# App uses Managed Identity — zero credentials

credential = DefaultAzureCredential()
# Azure injects the token automatically ↑

client = SecretClient(vault_url, credential)
secret = client.get_secret("db-password")
  • → Zero secrets in code, config, or repos
  • → Azure rotates tokens automatically
  • → Access controlled with
  • → Auditing: every access is logged by identity

System-assigned vs User-assigned

DimensionSystem-assignedUser-assigned
LifecycleTied to the resource — created/deleted with itIndependent — persists even if the resource is deleted
ShareableNo — only that resource can use itYes — multiple resources can share it
CreationAutomatic when enabled on the resourceA standalone resource in Azure (type: Managed Identity)
Typical caseA VM that accesses Key Vault only for itselfA fleet of VMs or apps that share the same access
Role managementAssign roles to the resource identity's Object IDAssign roles to the User-assigned MI once, attach it to many resources
Recommended whenA single resource with specific accessMultiple resources need the same permissions

How to configure and use it

Enabling System-assigned on a VM

Portal

VM → Identity → System assigned → Status: On → Save

CLI

az vm identity assign --name myVM --resource-group myRG

PowerShell

Update-AzVM -VM $vm -IdentityType SystemAssigned

Bicep/ARM

identity: { type: "SystemAssigned" } on the resource

Full flow: VM → Key Vault

1.Enable System-assigned MI on the VM → Azure creates a Service Principal in Entra ID
2.Note the MI's Object ID (visible in VM → Identity)
3.In Key Vault → Access policies (or RBAC) → assign the "Key Vault Secrets User" role to the Object ID
4.In the VM's code → use DefaultAzureCredential() — automatically detects the MI
5.Azure injects a valid JWT token via IMDS (Instance Metadata Service: 169.254.169.254)
6.The app uses the token to authenticate against Key Vault — no secrets in code

Use cases — Key Vault and Storage

App Service → Key Vault

  1. 1.App Service: Settings → Identity → System assigned ON
  2. 2. → Access control (IAM) → Add role assignment
  3. 3.Role: Key Vault Secrets User → assign to the App Service
  4. 4.In app.settings: use @Microsoft.KeyVault(SecretUri=...) reference
  5. 5.App Service resolves the secret automatically at runtime

Key Vault References in App Settings avoid even having the value show up in the portal.

VM / Function → Storage Blob

  1. 1.Enable MI on the VM or Function App
  2. 2.Storage Account → Access control (IAM) → Add role
  3. 3.Role: Storage Blob Data Reader or Contributor as needed
  4. 4.Assign to the MI's Object ID
  5. 5.In code: BlobServiceClient(url, DefaultAzureCredential())

Storage Blob Data Contributor allows reading/writing data but not managing the account itself.

Resources compatible with Managed Identity

Azure VMs
App Service
Azure Functions
Container Instances
AKS (pods)
Logic Apps
API Management
Data Factory
Event Grid
Service Bus
Azure Arc
Spring Apps

Managed Identity vs manual Service Principal

AspectService Principal (manual)Managed Identity
CredentialsClient Secret or Certificate — manual managementNone — Azure manages the token
RotationManual (must remember the expiration)Automatic
Use in codeClientSecretCredential(tenant, client_id, secret)DefaultAzureCredential() — no parameters
ApplicationExternal apps, CI/CD pipelines, external scriptsAzure resources (VMs, Apps, Functions)
Leak riskHigh — secret can leak in logs/reposNone — there's no secret to leak
When to use SPGitHub Actions, Terraform, apps outside AzureIf the resource lives in Azure → always prefer MI

Workload Identity Federation — secretless CI/CD

Workload Identity Federation lets external workloads (GitHub Actions, GitLab CI, Kubernetes, Terraform Cloud) obtain Entra ID tokens without needing to store Client Secrets. It uses the OIDC standard.

How it works — GitHub Actions example

1Create an App Registration in Entra ID (or a User-assigned MI)
2In the App: Certificates & Secrets → Federated credentials → Add credential
3Configure: Issuer = https://token.actions.githubusercontent.com, Subject = repo:org/repo:ref:refs/heads/main
4Assign the needed roles to the App Registration in Azure (e.g., Contributor on the Subscription)
5In the GitHub workflow, use the azure/login action with client-id, tenant-id (no secret)
6GitHub issues an OIDC token → Azure verifies it against the configured federated credential → issues an access token

Advantages vs Client Secret

✓ Zero secrets stored in GitHub, GitLab, Terraform Cloud

✓ No secret rotation to manage

✓ If the repository becomes public, there's no secret to steal

✓ Each pipeline/branch can have its own granular identity

✓ The token has a temporary scope — it expires after each job

Supported providers

GitHub Actions
GitLab CI/CD
Kubernetes (any)
Terraform Cloud
Google Cloud
AWS
CircleCI
Custom OIDC

Workload Identity in AKS — per-pod identity

In , the modern approach is Workload Identity (formerly called AAD Pod Identity). It lets individual pods have their own identity in Entra ID, without sharing credentials with other pods on the same node.

Architecture

Node-level MI (old method): The AKS node's VM has a Managed Identity. ALL pods on that node share the same identity. If a pod is compromised, it has access to the same resources as every other pod.

Workload Identity (recommended method):

• Each pod uses an annotated Kubernetes Service Account

• The Service Account is federated with a User-assigned MI or App Registration in Entra ID

• Only that pod obtains the token for that specific identity

• Principle of least privilege at the pod level

Basic configuration

1Enable the OIDC issuer on the cluster: az aks update --enable-oidc-issuer
2Enable Workload Identity: az aks update --enable-workload-identity
3Create a User-assigned MI and annotate it with the Kubernetes namespace/service-account
4Create a federated credential on the MI pointing to the cluster's OIDC issuer + the service account subject
5Assign an Azure role (e.g., Key Vault Secrets User) to the MI
6In the pod spec, reference the annotated service account → the pod receives the token automatically via a projected volume

Pod Identity v1/v2 (deprecated) vs Workload Identity

The AAD Pod Identity addon (v1 and v2) is deprecated. Microsoft recommends migrating to Workload Identity, which uses the OIDC standard. The main difference: Workload Identity doesn't require additional CRDs or daemonsets — it uses the native OIDC federation mechanism.

Did you get this topic?

Test what you just learned

What is the main advantage of using a Managed Identity for a VM to access Azure Key Vault?

Ready to test "Managed Identities"?

Put what you learned to the test with original AZ-104 exam questions.

Start AZ-104 mock exam

Unlimited mock exams with the Pro plan

Log in to track your progress.