Access control is one of the pillars of any IAM (Identity and Access Management) strategy. For a long time, assigning a role was sufficient. Today, hybrid environments, widespread remote work, and Zero Trust requirements have made this logic insufficient. This article is aimed at cloud administrators and engineers who manage identities in Microsoft Entra ID and who want to understand — and implement — a modern authorization approach.
RBAC: the universal foundation of access control
RBAC (Role-Based Access Control) is the most widespread authorization model in Microsoft environments. The principle is straightforward: you assign a user a role, and that role carries a set of predefined permissions.
In Microsoft Entra ID, this translates concretely into:
- Built-in roles such as
Global Administrator,User AdministratororSecurity Reader - Custom roles created to restrict to the exact scope necessary
- Azure RBAC roles for ARM resources (Azure Resource Manager), distinct from Entra ID roles
The strength of RBAC is its readability: it is easy to audit who has access to what, to revoke access in bulk by role, and to delegate administration to teams.
Its limitation? It answers the question "who can access?" but not "under what conditions?". A compromised account with the right role obtains exactly the same rights as a legitimate user.
ABAC: authorization through context
ABAC (Attribute-Based Access Control) extends the model by evaluating attributes at the time of access request. Instead of limiting itself to identity and role, the authorization engine examines a set of contextual signals.
In the Microsoft ecosystem, these attributes may include:
- Device compliance: is the device managed by Intune and compliant with policies?
- User attributes: department, declared location, contract type
- Network location: IP in a named range, connection from an authorized country
- Risk level: risk score calculated by Microsoft Entra ID Protection (sign-in risk, user risk)
- Time and time slot: access authorized only during business hours
- Authentication method: MFA satisfied, required authentication strength
These signals are evaluated dynamically at each access attempt, which naturally aligns ABAC with Zero Trust principles: never trust implicitly, always verify.
ABAC in Microsoft Entra ID
In the Microsoft ecosystem, ABAC is materialized primarily through Conditional Access policies and, for Azure Storage resources, through ABAC role assignment conditions available in GA since 2023 — allowing you to filter access to blobs based on their index tags.
RBAC and ABAC: complementary models, not competitors
The classic mistake is to oppose them. In practice, they operate at two different levels of the access decision:
| Dimension | RBAC | ABAC |
|---|---|---|
| Question addressed | Who can access? | Under what conditions? |
| Granularity | Role (group of permissions) | Contextual attribute (dynamic signal) |
| Evaluation | Static (at assignment time) | Dynamic (at each request) |
| Management complexity | Low to moderate | Moderate to high |
| Auditability | Excellent | Good (requires structured logs) |
| Zero Trust alignment | Partial | Native |
| Microsoft example | Entra ID role, Azure RBAC | Conditional Access, ABAC Storage |
In production architecture, the decision flow looks like this:
- The user requests access to a resource
- RBAC checks that they have the appropriate role or permission
- ABAC (Conditional Access) evaluates contextual signals and decides whether access is granted, blocked, or conditional (MFA, password change, etc.)
Remove one of the two layers and you get either too permissive a system (RBAC alone) or a system impossible to manage at scale (ABAC alone without role hierarchy).
Implementation
The following example illustrates how to audit, from PowerShell, the key attributes that feed an ABAC decision in Entra ID: roles assigned to a user, compliance status of their devices, and current risk level. These three pieces of information cover the RBAC and ABAC pillars of an access review.
Prerequisites:
- Module:
Microsoft.Graph(v2.x recommended) - Minimum permissions (application or delegated):
User.Read.All,Directory.Read.All,DeviceManagementManagedDevices.Read.All,IdentityRiskyUser.Read.All - Minimum Entra ID role:
Security Reader+Intune Administrator(read-only)
1# Install the module if necessary2# Install-Module Microsoft.Graph -Scope CurrentUser3 4# Connect with required scopes5Connect-MgGraph -Scopes "User.Read.All", "Directory.Read.All", `6 "DeviceManagementManagedDevices.Read.All", `7 "IdentityRiskyUser.Read.All"8 9# Parameter: UPN of the user to audit10$userUpn = "john.doe@contoso.com"11 12# --- 1. Retrieve the user ---13$user = Get-MgUser -Filter "userPrincipalName eq '$userUpn'" `14 -Property Id, DisplayName, UserPrincipalName, Department, JobTitle15 16if (-not $user) {17 Write-Error "User not found: $userUpn"18 return19}20 21Write-Host "`n=== Identity ==="22Write-Host "Name : $($user.DisplayName)"23Write-Host "Department : $($user.Department)"24Write-Host "Job Title : $($user.JobTitle)"25 26# --- 2. Assigned Entra ID roles (RBAC) ---27Write-Host "`n=== Assigned Entra ID roles ==="28$roleAssignments = Get-MgUserMemberOf -UserId $user.Id | `29 Where-Object { $_.AdditionalProperties['@odata.type'] -eq '#microsoft.graph.directoryRole' }30 31if ($roleAssignments) {32 $roleAssignments | ForEach-Object {33 Write-Host " - $($_.AdditionalProperties['displayName'])"34 }35} else {36 Write-Host " No direct Entra ID roles detected."37}38 39# --- 3. Devices and Intune compliance (ABAC signal) ---40Write-Host "`n=== Registered devices and compliance ==="41$devices = Get-MgUserOwnedDevice -UserId $user.Id42 43foreach ($deviceRef in $devices) {44 # Retrieve compliance details via managedDevices endpoint45 $managed = Get-MgDeviceManagementManagedDevice `46 -Filter "azureADDeviceId eq '$($deviceRef.Id)'" `47 -Property DeviceName, ComplianceState, OperatingSystem, LastSyncDateTime `48 -ErrorAction SilentlyContinue49 50 if ($managed) {51 Write-Host " Device : $($managed.DeviceName)"52 Write-Host " OS : $($managed.OperatingSystem)"53 Write-Host " Compliance : $($managed.ComplianceState)"54 Write-Host " Last sync : $($managed.LastSyncDateTime)"55 Write-Host ""56 }57}58 59# --- 4. User risk Entra ID Protection (ABAC signal) ---60Write-Host "=== User risk level ==="61$riskyUser = Get-MgRiskyUser -Filter "userPrincipalName eq '$userUpn'" `62 -Property RiskLevel, RiskState, RiskLastUpdatedDateTime -ErrorAction SilentlyContinue63 64if ($riskyUser) {65 Write-Host " Risk level : $($riskyUser.RiskLevel)"66 Write-Host " State : $($riskyUser.RiskState)"67 Write-Host " Last updated : $($riskyUser.RiskLastUpdatedDateTime)"68} else {69 Write-Host " No risk data available (license or permission missing)."70}71 72Write-Host "`nAudit completed for $userUpn"License required for risk data
The Get-MgRiskyUser cmdlets and Entra ID Protection risk signals require a Microsoft Entra ID P2 license (or Microsoft 365 E5). Without this license, the command returns an empty result without explicit error.
Conditional Access: where ABAC comes to life in Entra ID
Conditional Access policies are the native ABAC evaluation engine of Entra ID. Each policy defines:
- Conditions (who? from what? from where? with what risk?)
- Access controls (block, require MFA, require a compliant device, limit session)
A minimal Zero Trust architecture always combines both layers:
1User → [RBAC: does they have the role?] → [ABAC: Conditional Access passes?] → ResourceThe conditions evaluated by Conditional Access natively cover:
- Device platforms: Windows, iOS, Android, macOS, Linux
- Client applications: browser, modern client, Exchange ActiveSync
- Named IP ranges (Named Locations): IP lists or countries
- Sign-in risk and user risk: levels
low,medium,high - Directory roles: apply enhanced controls to privileged accounts
- Device filter: device attributes such as
extensionAttributeortrustType
Tip: report mode before production
Before activating a Conditional Access policy in On mode, activate it in Report-only mode. You can view the impact in the sign-in logs (Sign-in logs → Conditional Access tab) without blocking anyone. Leave it running for at least 48 hours before moving to production.
Native ABAC for Azure Storage: role assignment conditions
Since 2023, Microsoft has introduced ABAC role assignment conditions for Azure Blob Storage, available in general availability. They allow you to refine an existing RBAC assignment with conditions on resource attributes.
Concrete example: assign the Storage Blob Data Reader role only on blobs whose confidentiality index tag is public.
1# Prerequisites: Az.Resources module2# Required role: User Access Administrator on target scope3 4$condition = `5"((!(ActionMatches{'Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read'})) " + `6"OR (@Resource[Microsoft.Storage/storageAccounts/blobServices/containers/blobs/tags:confidentiality<`$key_case_sensitive`$>] StringEquals 'public'))"7 8New-AzRoleAssignment `9 -ObjectId "<ObjectId-of-group-or-user>" `10 -RoleDefinitionName "Storage Blob Data Reader" `11 -Scope "/subscriptions/<subscription-id>/resourceGroups/<rg-name>/providers/Microsoft.Storage/storageAccounts/<storage-account>" `12 -Condition $condition `13 -ConditionVersion "2.0"This capability is documented on the Azure attribute-based access control overview page in Microsoft Learn.
Troubleshooting common errors
Get-MgRiskyUser returns an empty result without error
→ Check that the Entra ID P2 license is assigned to both the target user AND the tenant. Also verify that the IdentityRiskyUser.Read.All scope is properly consented.
The Conditional Access policy does not apply to a specific user
→ Check the Sign-in logs in the Entra ID portal, Conditional Access tab. Each policy lists its result (Success, Failure, Not applied) with the reason. Group exclusions or service account exclusions are the most common causes.
New-AzRoleAssignment fails with InvalidConditionVersion
→ Make sure -ConditionVersion "2.0" is properly specified. Version 1.0 is deprecated and no longer supports new conditions.
Latency after RBAC role assignment → Entra ID role assignments generally propagate in less than 15 minutes, but can take up to 60 minutes in high-volume tenants. Existing JWT tokens are not revoked immediately: the user may retain their old rights until token expiration (1 hour by default for access tokens).
Immediate access revocation
To revoke access for a compromised account without waiting for token expiration, use Revoke-MgUserSignInSession combined with a blocking Conditional Access policy. Simply removing an RBAC role does not revoke existing active sessions.
1# Immediately revoke all active sessions for a user2# Required permission: User.ReadWrite.All3Revoke-MgUserSignInSession -UserId "john.doe@contoso.com"What you do starting Monday
If your organization still relies exclusively on RBAC without an ABAC layer, here are the three priority actions:
- Audit your RBAC assignments with the provided script — identify high-risk accounts that carry sensitive roles without contextual control.
- Enable Conditional Access in Report-only mode on your critical applications. Start with a policy requiring a compliant device for access to sensitive data.
- Evaluate Entra ID P2 if not already the case: without risk signals, your ABAC layer is blind to abnormal behavior.
If your organization uses Azure Storage for multi-sensitivity data, ABAC role assignment conditions allow you to replace multiplied service accounts with fine-grained access policy on a single role — drastically reducing your exposure surface.
RBAC and ABAC do not replace each other: one defines the scope of rights, the other validates each access request in its context. It is their combination that produces a truly resilient authorization model.



