Role-Based Access Control (RBAC) VS. Relationship-Based Access Control (ReBAC)
- Share:
Role-Based Access Control (RBAC) VS. Relationship-Based Access Control (ReBAC)
Almost every app out there needs an authorization layer, but choosing which authorization model to implement/build can be challenging. In this article, we will dive into two common authorization models - RBAC and ReBAC, discuss their pros and cons, and try to guide you in the decision of which one is right for your application.
Before we start, let’s cover some basics -
Intro: What is Authorization
Authorization is a complex challenge that basically every developer building an application 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 - Authentication handles who can log in to your application, while authorization handles what they can do once they are inside.
Application-level Authorization can be managed through different authorization models, and it’s up to developers to pick the most suitable authorization model for their application at each moment in time.
In this blog, we will explore and compare two commonly used models:
Role-Based Access Control (RBAC), and Relationship-Based Access Control (ReBAC).
What is RBAC?
Role-Based Access Control (RBAC) is an authorization model where access control is determined based on predefined (or dynamic) roles. Users are assigned roles, such as “Admin” or “Editor”, with each role associated with specific permissions.
For example, here’s a rather simple example of an RBAC policy in simple English -
Employees can View and Edit Documents, while Admins can View, Edit, Create, and Delete them.
RBAC provides a rather simple solution for controlling access to resources based on a predefined set of roles that can, for example, correlate with an individual's job function or responsibilities.
Below is a simple example of an RBAC policy written in Rego, the policy language of Open Policy Agent (OPA). 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}
}
A detailed example of how to implement RBAC using OPA is available here.
What is ReBAC?
Relationship-Based Access Control (ReBAC) is a policy model focused exclusively on the relationships, or how resources and identities (aka users) are connected to each other and between themselves. The consideration of these relationships allows us to create authorization policies for 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 assigned the role of an Owner on a folder will also get the Owner role on 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.
To create ReBAC policies, we need to create roles specific to a given resource. This means that the role, and the permissions it carries, are only relevant in the context of that specific resource. A resource role is commonly denoted as Resource#Role.
The most common relationship types ReBAC allows us to handle include:
Parent-child hierarchies are relationships where resources are nested under other resources. This allows us to create a policy such as:
A user who is assigned the role of an Owner on a folder will also get the Owner role on every file within that folder.
We can see that the user's access to the files is derived from the combination of two elements: The nesting of the files within the folder, and their role on the folder.
Organizations are relationships based on grouping together users. This allows us to create a policy like:
A user who is assigned the role of Member on RnD Team will also be assigned the role of Editor on RnD File when the RnD Team is the Parent of RnD File.
Putting several users in one group allows us to derive policies based on their group membership instead of per individual user.
Here’s a simple example of ReBAC 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 for this example is available in the OPA Playground. For more information about implementing ReBAC with OPA, check out this guide.
RBAC vs. ReBAC: Pros and Cons
RBAC | ReBAC | |
Use case | RBAC allows administrators to define roles and assign permissions, without having to manage permissions for individual users This makes RBAC a good alternative to simpler models like ACL | ReBAC is designed to represent hierarchies and nested relationships, making it the most suitable choice for managing permissions for complex hierarchical relationships |
Representation of relationships | Ineffective 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 | Does not support reverse indices | Can support reverse indices (not only does x have access to y, but also who has access to y). |
Performance | Generally high performance - due to simple policy execution | Potentially lower performance compared to RBAC, large hierarchies requiring significant processing power and time |
Implementation complexity | Low complexity compared to other models* | Highly complex |
Scalability | Granular permissions and newly added roles can easily result in ‘Role explosion’ in complex systems | Easily scales for large applications thanks to the combined use of relationships with roles. |
Granularity | Limited granularity as the result of the dependency on roles | Higher granularity thanks to the support of hierarchies, still 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) | Better than RBAC - Permissions can be defined en masse instead of individually for every single resource by using teams and groups |
Auditing difficulty | Easily auditable if set up correctly. | The complexity and recursive nature of ReBAC policies can make auditing challenging |
* 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 attributes like time, location, quotas, etc.
Making the choice: RBAC vs. ReBAC
ReBAC’s role derivation allows us to construct authorization policies that are far more efficient for hierarchies than RBAC. In RBAC, we would have to assign users roles that grant them direct access to each folder and file. ReBAC allows us to avoid that by leveraging existing application-level relationships and creating simple policies based on hierarchies and groupings.
A visual representation of a key difference between RBAC and ReBAC
With RBAC, in order to grant Bob editor access to all files and folders, we would have to assign Bob the Editor role per each individual file and folder. With ReBAC, we can define a policy such as: “A user who is assigned the role Folder#Editor will also be assigned the File#Editor when the Folder instance is the Parent of a FIle instance”. This allows us to handle this hierarchical structure in a far more efficient way.
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 implement them so that they're flexible, scalable, and continue to evolve along with your application's needs.
Flexible, Scalable Implementation
As application requirements evolve, the need to shift from a simple authorization model (like ACLs) to more advanced models like RBAC, ABAC, or ReBAC can arise rapidly. Implementing and managing such complex authorization systems can be challenging for developers and other stakeholders, potentially leading to bottlenecks and inflexibility.
Setting up these policy models can take months of work, which doesn’t end at the point of implementation - as creating additional roles, attributes, and policies requires complex R&D work and steep learning curves.
Why not both?
The solution is 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 no-code UI that makes permission management accessible to other 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.