Authorization Policy Showdown: RBAC vs. ABAC vs. ReBAC
- Share:
Introduction: The Arena of Authorization
Authorization is a challenge that every app developer has to face. It plays the crucial role of ensuring that the right people and services have the right access to the right resources.
It’s important to distinguish between Authorization and Authentication: as this Reddit user put it, telling the two apart is as easy as understanding the difference between a 401 and a 403:
401 - When you're trying to enter a club, you need to show your ID to the bouncer, but you left it at home.
403 - When you are inside the club but you are not invited to enter the VIP area
In application development, Authentication handles who can log in to your application, while authorization handles what they can do once they are inside.
Authorization gets very complicated very quickly. It can start off with something as simple as “Check if this user is an admin or not, and then give them access according to that”, but as your application evolves, so do the authorization requirements. Very quickly, you might end up needing to grant access based on multiple role types, attributes (like geo-location or payment status), team association, hierarchies, and many more.
That’s where authorization models come into play. In this blog, we bring you a face-off between some of the most common authorization models: Role-Based Access Control (RBAC), Attribute-Based Access Control (ABAC), and Relationship-Based Access Control (ReBAC). We’ll cover all three, focusing on the use cases, strengths, and weaknesses of each one.
Now that we've covered the basics - let’s meet our contenders:
Role-Based Access Control (RBAC):
The classic, tried-and-true champion. Role Based Access Control (RBAC) uses predefined roles assigned to users to determine their access rights. Simple and elegant, RBAC has been the go-to choice for many application developers for many years.
In RBAC, users are assigned roles, such as “Admin” or “Editor”, with each role associated with specific permissions.
An RBAC policy in simple English would look like this:
Employees can View and Edit Documents, while Admins can View, Edit, Create, and Delete them.
Strengths:
Simplicity: RBAC provides a solution that is simple and familiar to both your developers and end-users.
Easy management: The predefined roles set by RBAC can correlate with aspects such as an individual's job function or responsibilities. This allows administrators to manage permissions at a high level rather than per individual user.
Scalability: RBAC enables developers to scale rather easily as their application grows. If implemented correctly, adding or removing roles and permissions can be a simple task.
High Performance: RBAC generally has higher performance capabilities compared to other policy models due to simple policy execution.
Weaknesses:
Limited capacity: RBAC is prone to ‘role explosion’ in more complex applications - a situation in which, for the sake of granularity, many roles are created, making it extremely hard to manage / audit).
Limited flexibility: As user access is defined solely by roles and not specific attributes, an RBAC system can quickly become insufficient when new, more granular access control requirements emerge.
Here’s a simple example of an RBAC policy written in Rego, the policy language of Open Policy Agent (OPA).
Open Policy Agent (OPA) is an open-source policy engine for controlling access to systems and resources. It allows separating policy logic from application code, enabling easy policy management and updates without requiring code changes or deployments.
default allow = false
allow {
# Lookup the list of roles for the user
roles := user_roles[input.user]
# For each role in that list
r := roles[_]
# Lookup the permissions list for role r
permissions := role_permissions[r]
# For each permission
p := permissions[_]
# Check if the permission granted to r matches the user's request
p == {"action": input.action, "object": input.object}
}
RBAC, as well as the other policy models, can be implemented via different policy engines and languages - but that’s a different showdown.
While in this blog we focus on the different policy models, you can read about different policy engines here - Open Policy Agent vs AWS Cedar vs Google Zanzibar.
Here are also some detailed examples of implementing how to implement RBAC with OPA and how to implement RBAC with Cedar (AWS’ open-source policy engine).
Attribute-Based Access Control (ABAC):
The sturdiest of our challengers, Attribute-Based Access Control (ABAC) uses attributes – aspects of users, resources, actions, and environmental conditions – to determine access. Infinitely versatile, you can’t get any more granular than this.
ABAC expands upon basic RBAC roles adding attributes into the mix, allowing the creation of much more granular authorization policies.
An ABAC policy in simple English would look like this:
Employees based within the European Union can Edit Documents that are GDPR Protected.
In this example:
Employee is a Role
The location of the employee in the European Union is a User Attribute
Edit is the Action
Document is the Resource
GDPR Protected is the Resource Attribute
ABAC’s use of attributes allows the creation of very fine-grained authorization policies. Common attributes include (But are not limited to): Time, Location, Billing Status, and many more - all depending on the specific needs of your application.
Strengths:
- Fine-grained: ABAC provides the ability to create extremely fine-grained access control policies with its use of attributes.
- Highly Dynamic: It is very often that applications rely on abilities that have to be managed in a real-time fashion. If implemented using the right tools, ABAC can provide dynamic access control based on real-time changes in user/resource attributes.
Weaknesses:
- Complexity: ABAC can be a huge challenge to implement, manage, and maintain. Not only can it be very complex and time-consuming to design, but it's also an ongoing endeavor.
- Resource-intensive: As ABAC potentially requires taking a very large number of attributes into account, it can be very resource-intensive, requiring more processing power and time.
Here’s an example of an ABAC policy written in Rego:
package abac
# User attributes
user_attributes := {
"User1": {"location": "EU", "title": "employee"},
"User2": {"location": "US", "title": "employee"},
"User3": {"location": "EU", "title": "manager"}
}
# Document attributes
document_attributes := {
"Doc1": {"classification": "GDPR Protected"},
"Doc2": {"classification": "Non-sensitive"}
}
# Default deny
default allow = false
# EU employees can perform any action on GDPR Protected Document
allow {
# Lookup the user's attributes
user := user_attributes[input.user]
# Check that the user is an employee
user.title == "employee"
# Check that the employee is based in the EU
user.location == "EU"
# Check that the document is GDPR Protected
document_attributes[input.document].classification == "GDPR Protected"
}
# Allow any employee to access non-GDPR-protected documents
allow {
# Lookup the user's attributes
user := user_attributes[input.user]
# Check that the user is an employee
user.title == "employee"
# Lookup the document's attributes
document := document_attributes[input.document]
# Check that the document is not GDPR Protected
document.classification = "Non-sensitive"
}
To learn more about implementing ABAC with OPA’s Rego, check out this guide.
Relationship-Based Access Control (ReBAC):
Relationship-Based Access Control (ReBAC) relies on relationships between entities to make access decisions, making it the most suitable to handle hierarchical structures.
ReBAC allows us to derive authorization policies based on existing application-level relationships. Put in the simplest way, it allows us to create a policy like this:
A User who is the Owner of a Folder will also get Owner access to every File within that Folder.
Creating policies based on relationships rather than roles or attributes saves us from having to create authorization policies on a per-instance basis.
Strengths:
- Handling Complex Hierarchies: ReBAC is designed to represent hierarchies and nested relationships, making it the most suitable choice for this task.
- Enables reverse indices: ReBAC’s graph structure allows for reverse queries (not only does x have access to y, but also who has access to y).
- Using ReBAC allows us to define permissions en masse instead of doing it individually for every single resource by using teams and groups.
Weaknesses:
- Complexity: Implementing, managing, and maintaining ReBAC by yourself can be complex and time-consuming.
- Resource-intensive: ReBAC's consideration of numerous attributes can require significant processing power and time.
- Difficult to audit: The complexity and recursive nature of ReBAC policies can make auditing challenging.
Here’s an example of a ReBAC policy written in Rego:
# return a full graph mapping of each subject to the object it has reference to
full_graph[subject] := ref_object {
some subject, object_instance in object.union_n([files, teams,organizations])
# get the parent_id the subject is referring
ref_object := [object.get(object_instance, “parent_id”, null)]
}
# … see full Rego code at https://play.openpolicyagent.org/p/4qkNc0GtPP
# rule to return a list of allowed assignments
allowing_assignments[assignment] {
# iterate the user assignments
some assignment in input_user.assignments
# check that the required action from the input is allowed by the current role
input.action in data.roles[assignment.role].grants
# check that the required resource from the input is reachable in the graph
# by the current team
assignment.resource in graph.reachable(full_graph, {input.resource})
}
The full rego code with some example data is available in the OPA Playground
To learn more about implementing ReBAC with OPA’s Rego, check out this guide.
Now that we’ve met all of our contenders, let’s get into it -
Round 1: RBAC vs. ABAC
In our first match-up, we're pitting two authorization models against each other: RBAC and ABAC.
Think of a club - the bouncer (Authentication) lets you in. Now what? Can you go dancing? Can you pour people drinks? Are you allowed in the VIP section?
RBAC solves this in a very straightforward way: "Got the right role? Go ahead." This direct approach is simple, easy to understand and manage, and is usually sufficient for simple applications.
However, an RBAC approach can sometimes be a bit too rigid. It strictly goes by roles, without considering any other factors.
ABAC, Instead of just checking roles, has a guest list, a timestamp, and maybe even checks the weather! This means it allows us to make more nuanced decisions.
This finesse also comes with complexity. The more details ABAC considers, the more time and resources it might need.
Now, here's the twist: These two aren’t always rivals - RBAC and ABAC can be used together, with broad access enforced by RBAC protocols and more complex access managed by ABAC.
Many organizations start with RBAC's clear-cut rules and then gradually evolve them into ABAC as additional attributes are required. When dynamic data points such as time, location, billing status, and current behavior come into effect - ABAC becomes a necessity.
You can check out a more detailed comparison of RBAC vs. ABAC here.
Round 2: RBAC vs. ReBAC
As the bell chimes for the second round, we're tossing RBAC back into the ring, this time, against ReBAC.
Returning to the same analogy from the previous section, think of a VIP lounge in the club that has a dance floor and a VIP bar. With RBAC, we would have to give our VIP guests 3 badges - One allows them access to the lounge, one allows them to dance on the dancefloor, and one allows them to order drinks at the bar.
ReBAC, on the other hand, allows us to define access policies based on existing application-level relationships. Instead of juggling multiple badges, one for each area, ReBAC identifies the relationships between the different areas to grant access in a more efficient way.
A ReBAC policy might state: “A guest of the VIP Lounge can also Dance on the Dance Floor and Order Drinks at the VIP Bar - if the Dance Floor and VIP Bar are inside the VIP Lounge”.
In more practical terms - ReBAC's method shines in hierarchical or grouped setups. Whereas RBAC might require multiple roles to be defined for each related area, ReBAC navigates through these complexities by recognizing and applying inherent relationships and hierarchies.
Using ReBAC allows us to set up a system similar to Google Drive, where if you have editor access to a folder, you have editor access to every file within that folder.
You can check out a more detailed comparison of RBAC vs. ReBAC here.
Round 3: ABAC vs. ReBAC
Let’s continue our club metaphor - Imagine a user, let's call him Jay, has a locker in our club. This locker contains different items, and Jay wants to ensure he can access everything that he owns.
With ABAC, it's a tad like adding a specific tag to each item in Jay's locker saying, "Jay’s Property". Every time Jay wants to fetch something, the club checks if that tag exists. Tagging each item with an "Owner=Jay" is very precise, but no very efficient.
ReBAC, on the other hand, allows us to simply define a policy like “A guest can access all items inside their own locker - if the items are inside the locker”. No need for individual tags on each item.
By leveraging the inherent relationship of the items with the locker, ReBAC constructs simpler, more efficient access policies.
On the flip side, let's picture a sophisticated cocktail bar where each drink requires a specific combination of ingredients and the right bartender skills. This is where ABAC shines! ABAC can determine, based on multiple attributes, which bartender can make which cocktail, and who among the guests can order them. This allows us to define a policy like “a guest can only order a specific drink after midnight if they're seated at the bar”. ABAC’s expertise is in crafting these intricate, detailed rules by piecing together several attributes.
So, while ReBAC effortlessly navigates through hierarchies granting access based on relationships, ABAC allows us to craft and enforce multi-attribute rules for nuanced scenarios.
In many cases, two policy models can also be used together, with hierarchies enforced by ReBAC-based policies, and more fine-grained access managed ABAC.
You can check out a more detailed comparison of ABAC vs. ReBAC here.
Full recap: RBAC vs. ABAC vs. ReBAC
RBAC | ABAC | ReBAC | |
Use case | Allows creating policies based on roles without having to manage permissions per individual user (Making it a good alternative to simpler models like ACL). | Allows the creation of fine-grained policies based on user and resource attributes, significantly extending basic RBAC. | Designed to represent hierarchies and nested relationships, making it the most suitable choice for managing permissions for complex hierarchical structures. |
Performance | Generally high-performance - due to simple policy execution | Often provides better query performance, but can be heavier on data mapping and loading. | Data mapping is usually easier, but the recursive nature of relationships can produce inefficient queries. |
Homebrew Implementation Complexity | Low complexity compared to other models* | Medium complexity compared to other models* | Highly complex |
Granularity | Limited granularity as the result of the dependency on roles | Extremely high level of granularity | Higher granularity than RBAC, not as granular as ABAC** |
Policy definition | Better than simpler models - Permissions can be added/removed from an application, without requiring complex data migrations (e.g., adding/removing permissions for each individual user record). | Permissions can be defined en masse instead of individually for every single resource by using teams and groups. They can also be added/removed from an application without requiring complex data migrations (e.g., adding/removing permissions for each individual user record)*** | |
Auditing difficulty | Easily auditable if set up correctly. | More complex than RBAC, yet still easily auditable if set up correctly. | High auditing complexity due to the recursive nature of ReBAC policies. |
Representation of Relationships | Ineffective when managing access to hierarchical structures where the nesting of resources under other resources is present. | Can be cumbersome and verbose when managing access to hierarchical structures where the nesting of resources under other resources is present. | Excellent for representing hierarchies and nested relationships |
Reverse Indices(who has access to y, instead of does x have access to y) | Does not support reverse indices | Implementing reverse indices is very difficult | Naturally supports reverse indices (Thanks to its graph-like nature). |
* While less complex than other models, RBAC can still be quite challenging to implement, especially in large and complex applications that require support for a large number of roles and users. Designing and implementing RBAC requires a thorough understanding of the application's requirements, and the roles and permissions needed to support them. It is also crucial to follow established best practices when doing so.
**Though much more granular than RBAC, ReBAC still struggles with truly fine-grained, or dynamic permissions - such as rules dependent on dynamic attributes like time, location, and quotas.
***The challenge of getting all the relevant attribute data into your decision point in time can be daunting (though this can be elevated by tools like OPAL).
The bottom line
At the end of the day, authorization models are more thinking tools than concrete guidelines, and most applications end up mixing between them (especially as time passes and the applications evolve). The most important thing is how you design them so that they're flexible, scalable, and continue to evolve along with your application's needs.
Flexible, Scalable Implementation
Setting up and managing complex authorization frameworks like RBAC, ABAC, or ReBAC can pose a challenge for developers and other stakeholders, potentially leading to bottlenecks in the process. On top of that, as the requirements of your application change, you might need to quickly transition away from basic authorization methods, potentially causing delays that could take months to resolve.
It’s also important to note that the work you put into implementing an authorization layer doesn’t end at the point of implementation either - as creating additional roles, attributes, and policies requires complex R&D work and steep learning curves.
Why not combine them all?
What if I told you that there is no need to pit these contenders against each other, and their combined strengths? How, you ask?
By implementing and managing your RBAC, ABAC, or ReBAC policies using an authorization service that allows for flexible transition between authorization models and provides a simple API and no-code UI that makes permission management accessible to all stakeholders.
That’s where Permit comes in -
Permit.io: RBAC, ABAC, and ReBAC with a no-code UI
Permit provides developers with a permission management solution that allows for both smooth transitioning between RBAC, ABAC, or ReBAC without any changes to your application code, and the ability to create and manage policies using an accessible no-code UI.
Permit’s UI allows us to define our required roles, attributes, and role derivation logic, generates code for us, and pushes any updates or changes to our application in real-time. Implementing authorization with Permit ensures that everyone is included in the permission management process, preventing developers from becoming bottlenecks.
Want to learn more about Authorization? Join our Slack community, where there are hundreds of devs building and implementing authorization.
Written by
Daniel Bass
Application authorization enthusiast with years of experience as a customer engineer, technical writing, and open-source community advocacy. Comunity Manager, Dev. Convention Extrovert and Meme Enthusiast.