How to Implement Attribute Based Access Control (ABAC) using Open Policy Agent (OPA)
Tags: tutorial, authorization, openpolicyagent, abac
Published: 2022-01-17 12:13:40

Building authorization can be a complicated endeavor. There are different models for building authorization and different ways of implementing them. At the end of the day, only one thing matters - we want the **right person** to have the **right access** to the **right asset**.
 
For this purpose, we want to review a couple of **authorization models** (ABAC and RBAC), and then explain how (and why) should you implement them using Open Policy Agent - which allows you to create a separate microservice for authorization, decoupling our policy from our code.
⁠</br>
</br>
## So why ABAC and RBAC?
ABAC and RBAC are the two most basic and commonly used authorization models, and they provide the baseline for most other complex and specific ones. Let’s start by getting to know them a little better:
⁠</br>
</br>
##What is RBAC?
Role-based access control (RBAC), is an authorization model used to determine access control based on predefined roles. Permissions are assigned onto roles (Like “Admin or “User”), and roles are assigned to users by the administrator. This structure allows you to easily understand who has access to what.
 
The combination of three elements - **who **(What role are they assigned?) can do **what **(What actions are they allowed to perform) with a **resource **(Which resources) is called a **policy**.

[⁠You can also check out our tutorial on implementing RBAC in OPA](https://www.permit.io/blog/implement-rbac-using-opa)
⁠</br>
</br>
##What is ABAC?
ABAC (Attribute-based access control), determines access based on a set of characteristics called **“attributes”**, rather than roles. Attributes include parameters such as a user’s role, security clearance, time of access, current time, location of the data, current organizational threat levels, resource creation date or ownership, data sensitivity, etc.

It's important to note that the attributes examined in ABAC are not just the user's - but of the accessed resource, the overall system, and anything else that is relevant in this context.

ABAC based policies are based on a combination of four elements: **Who **(The identity of the user) can do **what **(What actions are they allowed to perform) with a **resource **(Which resources) in what **context **(What are the circumstances required for the action to be performed).
⁠</br>
</br>
##RBAC VS ABAC
The choice between RBAC and ABAC depends on the needs of your organization -

RBAC provides a rather simple solution for determining authorization. Having evolved from RBAC, ABAC provides a more in-depth approach for authorization needed in order to prevent unauthorized access. While requiring more processing power and time, ABAC provides a more complex and detailed authorization method factoring a much greater number of variables.

In many cases, RBAC and ABAC can be used together hierarchically, with broad access enforced by RBAC protocols and more complex access managed by ABAC. That being said, it is important to choose relevant authorization methods tailored to your organization’s needs - so the authorization process is **neither too simplistic nor too complex**.

For the purpose of this post, we’ll assume you decided you want to set up your policies with ABAC. 
⁠</br>
</br>
##The challenge of setting up policies with ABAC 
In case you decided to set up your policies using ABAC, it is important to note the challenges you’ll have to face along the way:
 

The set of policies for each individual service has to be manually set up inside the service itself. This can be kind of a pain to do - as the amount of policies, users, and services grows, updating them in each relevant service becomes super tedious and time-consuming. Not only that, but considering the fact that policies change all the time - they have to be at least somewhat fluid.
 
Another issue can come from having the code of the authorization layer mixed in with the code of the application itself. This creates a situation where we struggle to upgrade, add capabilities and monitor the code as it is replicated between different microservices. Each change would require us to refactor large areas of code that only drift further from one another as these microservices develop. 

**So how can we solve these challenges? **

![Plankton Safe](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/78n4tnnk9mvu18dt19dq.gif)

By creating **a separate microservice for authorization**, thus **decoupling our policy from our code**. Controlling access management centrally through a separate authorization service allows you to offer it as a service to every system that needs to check whether a user can or cannot access its resources. This can be done by using [Open Policy Agent](https://www.openpolicyagent.org/) (OPA). 

⁠</br>
</br>
##What OPA gives us?
- OPA unifies all policies across each individual service in one server.

- Takes on the role of policy decision-making and enforcement from the service: The service queries OPA, OPA makes a decision and sends an output to the service, The service acts according to OPA’s reply. 

- It allows you to have a policy as code, that can be easily reviewed, edited, and rolled back.


While we have a centralized authorization solution, the enforcement itself is still distributed - 
</br>
We have an OPA agent next to every microservice, providing decisions and enforcement with near-zero network latency. The OPA agents are distributed and can grow as the services scales. 



![Spongebob Door](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/vb9abkffzifew1fbpa2k.gif)

⁠</br>
</br>

##How to implement ABAC in OPA?
With attribute-based access control, you make policy decisions using the attributes of users, objects, and actions involved in the request. For this we need three types of information:

- Attributes for users

- Attributes for objects

- Logic dictating which attribute combinations are authorized


For example, let’s take the following attributes for our users:
`Squid`:
- Joined the company 10 years ago
- Is a cashier

`Pat`:
- Joined the company 6 months ago
- Is a cashier 

We would also have attributes for the objects, in this case, menu items:

`Burger`:
- Is sold on the menu
- Costs 3$

`Shake`: 
- Is sold on the menu
- Costs 1$

If we try and write up an example ABAC policy in English, it will look like this:

- Cashiers may process orders of up to 1$ total. 
- Cashiers with more than 1 year of experience may process orders of up to 10$ total. 



![Patrick](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9xyd3xrqjmcllu1ti4kl.jpg)


⁠**OPA supports ABAC policies as shown below:**

```
package abac

# User attributes
user_attributes := {
    "Squid": {"tenure": 10, "title": "cashier"},
    "Pat": {"tenure": 0.000114155, "title": "cashier"}
}

# Menu attributes
menu_attributes := {
    "Burger": {"items": "Menu", "price": 3},
    "Shake": {"items": "Menu", "price": 1}
}

default allow = false

# All cashiers may process orders of up to 1$ total
allow {
    # Lookup the user's attributes
    user := user_attributes[input.user]
    # Check that the user is a cashier
    user.title == "cashier"
    # Check that the item being sold is on the menu
    menu_attributes[input.ticker].items == "Menu"
    # Check that the processed amount is under 1$
    input.amount <= 1

}

# Cashiers with 1=> year of experience may ⁠process orders of up to 10$ total.
allow {
    # Lookup the user's attributes
    user := user_attributes[input.user]
    # Check that the user is a cashier
    user.title == "cashier"

    # Check that the item being sold is on the menu
    menu_attributes[input.ticker].items == "Menu"
    # Check that the user has at least 1 year of experience
    user.tenure > 1
    # Check that the processed amount is under is under $10
    input.amount <= 10
}

```

⁠Now let’s review the following input:

```
{
  "user": "Squid",
  "menu": "Burger",
  "action": "sell",
  "amount": 2
}
```

⁠Querying the allow rule with the input above returns the following answer: `True`.




![Patrick Plank](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8a7x0zpey0deethmmm8q.gif)



**Congrats! You have successfully implemented ABAC in OPA! **
⁠</br>
</br>
## To sum things up:

Let’s do a quick review of what we learned:

- **RBAC** is an authorization model based on **predefined roles**, while **ABAC** determines access based on a set of characteristics called **“attributes”**. 
</br>
</br>

- While RBAC provides a rather simple solution for determining authorization that fits most organizations, ABAC is a more complex and detailed authorization method factoring in a much greater number of variables.
</br>
</br>

- It is important to choose an authorization model that fits your organization's needs, so it’s **neither too simple nor too complex**.
</br>
</br>

- The main challenges of setting up policies with RBAC are the requirement to manually set up the set of policies for each individual service, and having the code of the authorization layer mixed in with the code of the application itself. **Both can be solved by using OPA**.
</br>
</br>

- OPA solves these issues by **unifying all policies** in one server, **taking on the role of policy decision-making and enforcement** from the service, and allowing you to manage **policy as code**. 
</br>
</br>

- We saw an example of how to **successfully implement ABAC in OPA** :)
</br>
</br>

⁠Want to learn more? check out the rest of our [Blog](https://www.permit.io/blog) for more useful tutorials, or join our ⁠[Slack channel](https://opal-access.slack.com/join/shared_invite/zt-nz6yjgnp-RlP9rtOPwO0n0aH_vLbmBQ#/shared-invite/email) to ask questions and talk about authorization.