ABAC vs. ReBAC: comparing fine-grained access control models

Feb 1st, 2023

Noa Shavit avatar

Noa Shavit

ReBAC  |  

Open Policy Agent

ABAC vs ReBAC authorization models

Attribute-based access control (ABAC) and relationship-based access control (ReBAC) are two approaches to fine-grained access control. ABAC assigns permissions based on user, resource, or environmental attributes. ReBAC uses the relationships between subjects and objects to determine what a user can access. Both models provide a high level of flexibility that promotes application security. They do this by allowing policies to be expressed in terms of attributes of entities, or chains of relationships between entities.

ABAC and ReBAC are increasingly adopted by organizations as security policies become more dynamic and complex. There are conflicting reports about the similarities and differences between the two models. Some claim that ABAC can mimic ReBAC since attributes can encode relationships. Others claim that the multilevel or indirect relations of ReBAC bring fundamentally new capabilities.

We believe that both models have their merits and they should be able to be used in tandem. It might be easier to express certain conditions using attributes (for example access is denied for users outside of the US) and others using relations (e.g. enable managers to perform actions on their reports).

Read on for a look into attribute-based and relationship-based access control.

ABAC uses dynamic attributes

Attribute-based access control is not new. Many enterprises have implemented  ABAC due to the ease of configuring access based on network, location, or device. Denying access to protected resources over public networks, or from certain locations are common use cases.  Regional differences in service levels or compliance requirements, such as GDPR, are other common examples.

ABAC policies use dynamic characteristics called “attributes” to determine access. These attributes can be about the subject of the authorization (e.g. a user or a group), the object that is the target of the authorization (e.g. a tenant, organization, team, or resource), or an environmental attribute (e.g. geo-location, date, time). Access is granted or denied based on one or more attributes.

A simple ABAC policy can restrict access to a customer’s planning doc only to users that have the relevant project attribute (e.g. “ACME”). A more sophisticated ABAC policy might also require that the access request be sent during standard business hours and over VPN.

Attribute-based access control lets us answer questions such as “Can Rick push to production if Rick has the ‘merge’ attribute and is connected over VPN.” The policy computes an allow/deny decision based on inputs (user, resource, environment) to answer these types of questions.

But, if you are looking to answer questions like “Who has the permissions to push to production under the right conditions?” you’ll have to look elsewhere.  This type of "Who has permission" question is open-ended and not a straightforward use-case for ABAC.

This question is easily answered with ReBAC, due to the bi-direction nature of the relationships. You can start with a subject and compute what objects are reachable through these relationships ("What does Rick have access to?"). You can also start with an object and compute which subjects are reachable through relationships ("Who has access to ACME org's planning doc?"). This bi-directionality is one of the differences between ABAC and ReBAC

Pros and cons of ABAC

Pros and cons of attribute-based access control

The attributes used to govern access bring a dynamic nature to authorization. This makes ABAC an easier model to scale than RBAC, which is based on static roles assigned to users.

If an employee changes departments, for example, an ABAC policy allows you to update that user attribute to grant them access to everything they need in their new department. This will also revoke access from anything they no longer need.

With RBAC, you’d need to update the user’s role across systems or create a new role to provide the right permissions. The former means manual updates, while the latter will lead to “role explosion,” which makes it difficult to reason about access decisions. ABAC avoids this because the policy evaluates the attributes, instead of  statically-assigned roles.

>> For more about the difference between ABAC and RBAC, go here.

ABAC is a flexible and scalable access control model, but it does have a couple shortcomings. You have to address all the potential values the attributes may have, or risk unanticipated and potentially unwanted behavior.  Also, writing access policies in a logic language like Rego involves a learning curve. It's a powerful language, but with power comes complexity.

These are the reason that initial implementations of ABAC are more time-consuming than those of other authorization models. You have to design an authorization model and then learn how to implement it in logic. Maintaining ABAC systems correctly also tends to require more expertise than that required for other models.

Example policy

A simple example of ABAC could be "Support agents can view customer tickets.” A more complex example could be “Support agents can only close the tickets of the customers they are assigned to during work hours." Let’s dive into this example, which uses the Open Policy Agent’s Rego as the policy language.

We’ll start by defining a list of workdays. We can then test whether the current day is a workday. We also want to check whether the user’s department is “Support” and if the user has the appropriate project attribute (in this example it is “ACME”).

Here’s an example of what this policy could look like:

workdays := ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
allowed {
  ns := time.now_ns()
  day := time.weekday(ns)
  day == workdays[_]
  input.user.department == "Support"
  input.user.project == "ACME"
}

If the user is trying to close a support ticket opened by a customer called “ACME org,” for example, they need to have the “Support” department attribute, the “ACME” project attribute, and make the request during a workday. If all these conditions are followed access will be granted. But if the user does not have one of the attributes, or is trying to access the resource outside of the permissible times, access will be denied.

ABAC resources

A couple resources to provide more information about attribute-based access control, as well as concrete steps for adding ABAC to your applications or APIs:

ReBAC uses a relationship graph

Relationship-based access control (ReBAC) also isn’t new. Examples of graph-based access control include social media, where users need to control access to their profiles and personal information based on the relationship they have with the requestor. First degree connections might be able to view your posts and pictures, while second-degree (or higher) connections can only access public information, like your name.

Recently, Google’s Zanzibar has brought new focus to ReBAC and inspired many open-source implementations. One such implementation marries ReBAC with OPA policies, for further flexibility and control.

The idea behind ReBAC also is not new. It’s a take on the Access Control List (ACL) paradigm of cascading access to each resource in a hierarchy, such as directories and files. ReBAC generalizes this model into a relationship graph between subjects and objects via relations. These relations include data ownership, parent-child relationships, groups, and hierarchies (or relation chains).

ReBAC models can be traversed as a graph to determine whether a user/group has a certain permission on a resource and answer questions such as “Can Morty edit the ‘ACME planning’ doc if they are part of the ‘ACME’ group that has edit permissions to every doc in the ‘ACME’ folder and ‘ACME planning’ doc is in the ‘ACME’ folder?”  It also allows you to answer general questions, such as "Who can edit the 'ACME planning' doc?”

Pros and cons of ReBAC

Pros and cons of relationship-based access control

Relationship-based access control uses a relationship graph to determine access. This allows developers to use criteria otherwise unavailable, or just cumbersome to set up. Management relationships are a great example.

Many applications want to enable managers to perform actions on their reports. This requires an understanding of a very specific type of user attribute which describes management relationships.

You could create a group that contains all the executives, map out their departments, and assign attributes. You would then explicitly manage the group, as you would with ABAC. Or you could construct a ReBAC policy to walk the organizational graph and determine whether a user is in that executive’s organization, in a fraction of the effort. This is also a more elegant solution.

The relationship graph is quick and easy to traverse, but ReBAC has the potential to add operational overhead as your application scales. Things can get messy when every resource needs to be present in your application code and authorization database.

Example policy

ReBAC is a flexible authorization model that allows you to define fine-grained access controls. It uses direct and indirect relationships between subjects and objects to determine access. Its graph-based nature allows you to define unique relationships, such as management relationships. Let’s take a closer look at that.

Being that most people are familiar with Google Drive, we'll use a document-sharing application as our example. We have a document-sharing application with a hierarchical structure between a set of folders and documents. The system is set up so that users can share individual documents or folders with other users, who are granted can-view or can-edit permissions. The system is also set up so that managers can access and edit any files created by their team members.

The authorization policy will have two rules:

  1. a check_permission call to cover the normal case where a user shares files with another user. In this case, the user requesting access is  explicitly granted can-view or can-edit permissions.
  2. a check_relation call to see if the user requesting access is the manager of the user that owns the file that is the target of the authorization. In this case, access isn't granted explicitly, but based on an indirect relationship between entities.

If either of these rules is true, the user gets access.

Here’s an example of how we can specify the can-edit permission in a policy:

allowed {
  ds.check_permission({
    "subject": {"id": input.user.id},
    "permission": "can-edit",
    "object": {"key": input.resource.file_id, "type": "file"},
  })
}

allowed {
  file = ds.object({"key": input.resource.file_id, "type": "file"})
  
  ds.check_relation({
    "subject": {"id": input.user.id},
    "relation": {"name": "manager_of", "type": "user"},
    "object": {"id": file.properties.owner_id},
  })
}

The first rule is straightforward. It grants access to any user that has the can-edit permission to that file, regardless of any other criteria. The second rule is where things get interesting. It uses ds.object to load the directory object representing the file being accessed and pulls up the owner_id property of the file. The policy then checks if the acting user has the manager_of relation to the owner of the file. If they have that relation with the owner of the file, access will be granted.

ReBAC resources

Here are a couple resources to help you get up to speed with relationship-based access control:

Combining ABAC with ReBAC

Sometimes the most elegant way to express authorization logic will be by combining ABAC and ReBAC. An easy example would be when you want to enforce access controls based on environmental attributes, like network or location. There are services out there, like Topaz.sh, that let you combine both models. This open-source project supports ABAC through OPA policies and ReBAC via a built-in directory.

Let’s take a look at a policy that combines ABAC and ReBAC. Going back to our document-sharing application, we might want to further tighten access to files users do not own by limiting access to standard working hours.

We can write a policy that enforces the following rules:

  • If a user has been explicitly granted the can-edit permission to a particular file, they may do so regardless of any other condition
  • If a user has the manager_of relation with another user they can edit any file owned by that user during workdays

Here’s what the policy could look like:

allowed {
  ds.check_permission({
    "subject": {"id": input.user.id},
    "permission": "can-edit",
    "object": {"key": input.resource.file_id, "type": "file"},
  })
}

workdays := ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]
allowed {
  ns := time.now_ns()
  day := time.weekday(ns)
  day == workdays[_]

  file = ds.object({"key": input.resource.file_id, "type": "file"})
  ds.check_relation({
    "subject": {"id": input.user.id},
    "relation": {"name": "manager_of", "type": "user"},
    "object": {"id": file.properties.owner_id},
  })
 }

Conclusion

ABAC and ReBAC are two forms of fine-grained access controls. Both authorization models have merits and drawbacks. ABAC simplifies access management governance, but has a heavier initial lift, and requires more expertise than other models to get right. ReBAC is extremely flexible, allowing for resource-level authorization. It can also add operational overhead as your application scales, since you need to store and manage relationships between subjects and objects.

So which is better? The simple answer is neither. ABAC is a more elegant solution for user attribute-based or environment-based access controls. And ReBAC allows for the definition of complex relations, such as parent-child relations or management relationships. Sometimes the most elegant solution is to combine the two, as in our example.

Learn more about ABAC, ReBAC, and RBAC, and see example policies in this comprehensive eBook. And if you have any questions, join us on Slack, or schedule a time to speak with an engineer.

Noa Shavit avatar

Noa Shavit

Head of Marketing