Azure RBAC Misconfiguration: Subscription-Scope Role Assignments and Service Principal Abuse
Theory
Why This Matters
The 2021 ChaosDB vulnerability in Azure Cosmos DB demonstrated that a misconfigured cross-tenant Jupyter Notebook service had been granted elevated RBAC permissions on customer subscriptions — effectively giving Wiz researchers Contributor access to thousands of Azure databases they did not own. The root cause was not a code vulnerability but an RBAC assignment made with excessive scope. Separately, the 2022 Lapsus$ intrusions repeatedly leveraged overly privileged service principals whose credentials had been harvested from developer machines: once credentials for an Owner-level service principal are stolen, every resource in the subscription is compromised. Azure RBAC misconfiguration is consistently among the top findings in Azure penetration assessments.
Core Concept
Azure Role-Based Access Control (RBAC) controls who can do what to which Azure resources. It is composed of three elements: a security principal (user, group, service principal, or managed identity), a role definition (a collection of allowed actions and not-actions), and a scope (management group, subscription, resource group, or individual resource). The combination of these three elements is called a role assignment.
Azure provides over 200 built-in roles. The three broadest are: Owner (full access including the ability to manage RBAC assignments), Contributor (full access except RBAC management), and Reader (read-only). A custom role is a JSON document that specifies exact Actions, NotActions, DataActions, and NotDataActions — it enables the principle of least privilege but requires careful maintenance.
Scope inheritance is critical: a role assigned at subscription scope is effective on all resource groups and resources within that subscription. Assignment at management group scope cascades to all child subscriptions. Assessors must examine assignments at every scope level, not only at the resource group level.
Service principals are non-human identities used by applications, automation pipelines, and Azure services. They frequently accumulate RBAC assignments over time without review. A service principal with Contributor at subscription scope and a client secret that never expires is one stolen credential away from full subscription compromise.
Technical Deep-Dive
# List all role assignments in the current subscription (requires Reader or higher)
az role assignment list --all
--query '[*].{Principal:principalName,Role:roleDefinitionName,Scope:scope}'
--output table
# Filter for high-privilege roles (Owner, Contributor, User Access Administrator)
az role assignment list --all
--query '[?roleDefinitionName==`Owner` || roleDefinitionName==`Contributor`
|| roleDefinitionName==`User Access Administrator`].
{Principal:principalName,PType:principalType,Role:roleDefinitionName,Scope:scope}'
--output table
# List all role assignments on a specific subscription scope (not just resource groups)
az role assignment list --scope /subscriptions/$(az account show --query id -o tsv)
--query '[*].{Principal:principalName,PType:principalType,Role:roleDefinitionName}'
--output table
# Enumerate service principals with role assignments — focus on non-human principals
az role assignment list --all
--query '[?principalType==`ServicePrincipal`].
{AppId:principalId,Role:roleDefinitionName,Scope:scope}'
--output table
# Get permissions granted to a specific service principal
SP_OBJECT_ID="xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
az role assignment list --assignee "$SP_OBJECT_ID"
--query '[*].{Role:roleDefinitionName,Scope:scope}'
--output table
# List all custom role definitions in the subscription
az role definition list --custom-role-only true
--query '[*].{Name:roleName,Actions:permissions[0].actions}'
--output json | python3 -m json.tool
{
"Name": "Minimal VM Operator",
"IsCustom": true,
"Description": "Start and stop VMs only — no read of secrets or storage",
"Actions": [
"Microsoft.Compute/virtualMachines/start/action",
"Microsoft.Compute/virtualMachines/deallocate/action",
"Microsoft.Compute/virtualMachines/read"
],
"NotActions": [],
"DataActions": [],
"NotDataActions": [],
"AssignableScopes": ["/subscriptions/SUBSCRIPTION_ID/resourceGroups/prod-vms"]
}
Security Assessment Methodology
- Baseline all high-privilege assignments. Run
az role assignment list --alland filter for Owner, Contributor, and User Access Administrator. Any assignment at subscription or management group scope deserves immediate justification — these are the broadest blast radii possible. - Enumerate service principal assignments. Filter
principalType == ServicePrincipal. For each, check if the service principal has a never-expiring client secret:az ad app credential list --id <app-id>. Secrets withendDateTimefar in the future or null are persistent high-value targets. - Check for assignments made directly to users vs groups. Direct-to-user assignments are harder to audit at scale and often bypass the joiner/mover/leaver process. Best practice is to assign roles to groups managed by identity governance, not individuals.
- Identify custom roles with wildcard actions. A custom role containing
"Microsoft.Authorization/*"or"*"is functionally equivalent to Owner. Useaz role definition list --custom-role-only trueand inspect theactionsarray of each. - Test managed identity scope. For Azure VMs and App Services, check the assigned managed identity:
az vm identity show. Then check what RBAC assignments that managed identity holds — a web app with a system-assigned identity at Contributor scope is an escalation path via SSRF or code execution. - Remediate by scoping assignments to the narrowest resource group or individual resource possible, replacing broad roles with custom least-privilege roles, and rotating or disabling service principal secrets. Enforce Conditional Access policies requiring MFA for all human principals assigned privileged roles.
Common Assessment Errors
- Auditing only resource group scope. Subscription-level and management-group-level assignments are not visible when querying a specific resource group. Always use
--allto retrieve assignments across all scopes. - Ignoring classic administrator roles. Legacy Azure "classic" Co-Administrator and Service Administrator roles predate RBAC and are not returned by
az role assignment list. Check the Azure Portal under Subscriptions → Access control (IAM) → Classic administrators for these hidden assignments. - Treating Reader as harmless. Reader can enumerate all resource configurations, connection strings in App Service settings, and Key Vault metadata (though not secret values). An attacker with Reader can build a complete infrastructure map and identify further attack paths.
- Missing cross-tenant service principals. Multi-tenant applications register service principals in every tenant where they are consented to. Enumerate with
az ad sp list --filter "servicePrincipalType eq 'Application'"and check for principals from external tenants. - Overlooking Azure AD (Entra ID) role assignments. Azure RBAC controls resource plane access; Azure AD roles (Global Administrator, Privileged Role Administrator) control the identity plane. A compromise of either is catastrophic.
az role assignment listdoes not show Azure AD role assignments — those requireaz restor Microsoft Graph API calls.
NICE Framework Alignment
| Code | Knowledge/Skill/Task Statement | How This Card Develops It |
|---|---|---|
| K0053 | Knowledge of security risk management processes | Assessing RBAC misconfiguration risk: scope, role type, and principal type each compound the severity of an excessive assignment |
| K0167 | Knowledge of system administration, network, and OS hardening techniques | Applying least-privilege principles to Azure subscription governance through custom roles and narrow scope assignments |
| S0073 | Skill in conducting vulnerability scans and recognizing vulnerabilities | Using az role assignment list to enumerate all assignments and identify over-privileged principals across subscription and management group scopes |
| T0144 | Conduct penetration testing as required for new or updated applications | Enumerating service principal permissions during an Azure penetration test to identify credential theft escalation paths |
| T0395 | Write code to address security vulnerabilities | Authoring custom role definition JSON with scoped actions and assignable scopes to replace over-privileged built-in role assignments |
Further Reading
- Microsoft Azure Security Technologies (AZ-500) Study Guide — Chapter 3: Manage Identity and Access (Microsoft Press)
- Penetration Testing Azure for Ethical Hackers — David Okeyode & Karl Fosaaen, Chapter 4 (Packt Publishing)
- Azure Role-Based Access Control Documentation — Microsoft Learn (docs.microsoft.com/azure/role-based-access-control)
Challenge Lab
Reinforce your learning with a hands-on generated challenge based on this card's competency.