RBAC vs ABAC in Microsoft Entra ID: How to Set Up Both and Strengthen Your Security
A practical, no-fluff walkthrough of creating Role-Based and Attribute-Based Access Control in Microsoft Entra ID and Azure, with real steps, examples, and the security case for each.
In my last article, I broke down what RBAC and ABAC are conceptually. This time, we’re going hands-on: how do you actually build both inside Microsoft Entra ID (formerly Azure AD) and Azure, and what does each one actually buy you from a security standpoint? Let’s get into it.
- Quick recap: RBAC vs ABAC
- Setting up RBAC in Microsoft Entra ID
- Setting up ABAC in Azure (Entra ID + Azure RBAC Conditions)
- RBAC vs ABAC inside Entra ID: which one applies where
- How this actually strengthens your security posture
- Best practices before you roll this out
- Title, description, tags & keywords
01. Quick Recap: RBAC vs ABAC
Before we touch the portal, a fast refresher so the steps below make sense:
- RBAC (Role-Based Access Control) grants access based on a role assigned to a user, for example “Helpdesk Administrator” or “Billing Reader.” The role carries a fixed set of permissions.
- ABAC (Attribute-Based Access Control) grants access based on attributes of the user, resource, and environment, evaluated at request time, for example “allow read access only if department = Finance and the blob is tagged Project = Cascade.”
Microsoft actually splits this into two separate systems you shouldn’t confuse: Microsoft Entra roles (RBAC for identity-plane resources like users, groups, and apps) and Azure RBAC (roles for Azure resources like VMs, storage, and subscriptions). ABAC in Azure builds on top of Azure RBAC as role assignment conditions, it isn’t a separate role system, it’s a filter on top of one.
02. Setting Up RBAC in Microsoft Entra ID
Entra ID ships with a large set of built-in roles (Global Administrator, User Administrator, Helpdesk Administrator, etc.) that cover most common admin scenarios. When those don’t fit, you create a custom role. Here’s the process end to end.
Step-by-step: Assigning a built-in role
- Sign in to the Microsoft Entra admin center as at least a Privileged Role Administrator.
- Go to Identity → Roles & admins → Roles & admins. You’ll see the full list of built-in and custom roles.
- Pick a role (e.g., “Helpdesk Administrator”) and select
Add assignments. - Choose the user or group you want to assign it to, and optionally set an assignment scope, org-wide or a specific administrative unit.
- Set eligibility via PIM (recommended), instead of a permanent assignment, make it eligible through Privileged Identity Management so the user has to activate it with justification and time-bound access.
Step-by-step: Creating a custom role
Custom roles are useful when a built-in role gives too much or too little access. Creating one is a two-step process: define the role, then assign it.
- Browse to Entra ID → Roles & admins and select
New custom role. - Basics tab: give it a clear name and description (e.g., “App Registration Manager”). You can clone permissions from an existing custom role, but not from a built-in one.
- Permissions tab: search and select only the specific permissions needed. For example, search “credentials” and pick
microsoft.directory/applications/credentials/update, or search “basic” formicrosoft.directory/applications/basic/update. - Review + create: confirm and save the role definition.
- Assign it: go back to the role, select
Add assignments, and choose the scope: org-wide, or a single object such as one application. The same role definition can be reused at different scopes for different people.
Don’t default to Global Administrator because it’s the fastest path. Build the access matrix first (resource → action → role → approver) before you touch the portal, it prevents most of the over-provisioning that turns into an audit headache later.
03. Setting Up ABAC in Azure
Here’s the part that surprises people: Entra ID itself doesn’t have a native “ABAC” toggle for identity-plane resources. Attribute-based access control in the Microsoft ecosystem is implemented as Azure ABAC, role assignment conditions layered on top of Azure RBAC, generally available today for Azure Blob Storage, Azure Data Lake Storage Gen2, and Azure Queues. Entra ID contributes the attribute source through custom security attributes on users.
Part A: Define custom security attributes in Entra ID (the “principal attributes”)
- Go to Entra ID → Custom security attributes (requires the Attribute Assignment Administrator role).
- Create an attribute set, e.g.,
Engineering, then add an attribute likeProjectwith allowed values such asCascade,Atlas. - Assign the attribute value to a user, open the user’s profile → Custom security attributes → add
Project = Cascade.
Part B: Add a role assignment condition (the actual ABAC rule)
- Open the resource (e.g., a storage account or container) →
Access control (IAM). - Add a role assignment, choose a role such as
Storage Blob Data Reader, then pick the user or group. - On the Conditions tab, select “Add condition.” Choose the action to filter, e.g.,
Read a blob. - Build the expression: choose the attribute source (resource tag, principal attribute, or environment), an operator, and a value. For example, restrict access to blobs tagged
Project = Cascade. - Save. Azure now evaluates the role AND the condition together, if the tag doesn’t match, access is denied even though the role assignment exists.
Here’s what that condition looks like under the hood if you’re editing it via CLI, PowerShell, or the code editor in the portal:
(
(
!(ActionMatches{'Microsoft.Storage/storageAccounts/blobServices/containers/blobs/read'}
AND NOT
SubOperationMatches{'Blob.List'})
)
OR
(
@Resource[Microsoft.Storage/storageAccounts/blobServices/containers/blobs/tags:Project<$key_case_sensitive$>]
StringEqualsIgnoreCase 'Cascade'
)
)
You can achieve the same result with Azure CLI:
az role assignment create \
--assignee "user@yourtenant.com" \
--role "Storage Blob Data Reader" \
--scope "/subscriptions/<sub-id>/resourceGroups/<rg>/providers/Microsoft.Storage/storageAccounts/<account>" \
--condition "@Resource[Microsoft.Storage/storageAccounts/blobServices/containers/blobs/tags:Project<\$key_case_sensitive\$>] StringEqualsIgnoreCase 'Cascade'" \
--condition-version "2.0"
Combine both halves and you get real dynamic rules: “A user can read blobs only if their Entra ID custom attribute Project matches the blob’s index tag.” That’s ABAC using Entra ID as the identity/attribute source and Azure RBAC conditions as the enforcement layer.
04. RBAC vs ABAC Inside Entra ID: Which Applies Where
| Layer | Model | Controls access to | Where you configure it |
|---|---|---|---|
| Microsoft Entra roles | RBAC | Users, groups, apps, devices, tenant admin settings | Entra ID → Roles & admins |
| Azure RBAC | RBAC | Azure resources, VMs, storage accounts, resource groups, subscriptions | Azure resource → Access control (IAM) |
| Azure ABAC | ABAC | Fine-grained access within a resource (blobs, queues, DLS Gen2) | Access control (IAM) → Role assignment → Conditions |
| App roles | RBAC | Custom application logic and in-app permissions | App registration → App roles |
05. How This Actually Strengthens Your Security
What RBAC gives you
- Enforces least privilege at scale, instead of ad-hoc permissions, every user’s access traces back to a defined role.
- Cleaner audit trail, “who has access to what” becomes a query against role assignments, not a manual investigation.
- Reduces blast radius, a compromised Helpdesk Administrator account can reset passwords, not exfiltrate all tenant data, because the role is scoped.
- Pairs naturally with PIM, eligible (not permanent) role assignments mean standing privilege is minimized, and every activation is logged and time-bound.
What ABAC adds on top
- Context-aware decisions, access can depend on tags, department, project, time of day, or network location, not just “does this person have the role.”
- Reduces role sprawl, instead of creating a new role per project or per data classification, one role plus a condition handles it.
- Supports data-level segmentation, multiple teams can share the same role (e.g., Storage Blob Data Reader) while only seeing the data tagged for them.
- Strengthens Zero Trust posture, conditions can incorporate environment attributes like private endpoint or subnet, so access isn’t just identity-based, it’s also context-based.
✅ Combined, RBAC + ABAC give you
- Coarse-grained structure (RBAC) + fine-grained filtering (ABAC)
- Fewer roles to maintain long-term
- Access decisions that reflect real business context
- Easier compliance mapping (HIPAA, SOC 2, ISO 27001 access controls)
⚠️ Watch out for
- Conditions can’t explicitly deny access, they only filter what the role already allows
- ABAC for Azure is currently scoped to Blob Storage, ADLS Gen2, and Queues, not every resource type
- Complex conditions are harder to audit than a simple role list
- Custom security attributes require careful tagging discipline to stay useful
06. Best Practices Before You Roll This Out
- Map before you build. List resources, actions, and the roles that should perform them, on paper, not in the portal.
- Prefer built-in roles first. Only create custom roles when a genuine gap exists.
- Use groups, not individual assignments. Assign roles to groups so onboarding/offboarding is a group-membership change, not a manual role edit.
- Avoid wildcard permissions in custom roles unless the use case truly requires broad access, they’re a common source of privilege creep.
- Layer PIM on top of RBAC for anything privileged, eligible, time-bound, approval-gated access beats permanent standing access.
- Review role assignments and conditions regularly. Outdated roles and stale tags are how access control quietly rots.
Want the visual RBAC vs ABAC breakdown (capabilities, use cases, pros & cons) before diving into setup?
Read: RBAC vs ABAC, A DevOps Conversation That Cleared My Confusion