How to Implement Attribute Based Access Control (ABAC) using Open Policy Agent (OPA)
- Share:
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) you should implement them using Open Policy Agent (OPA) - which allows you to create a separate microservice for authorization, decoupling our policy from our code.
So why ABAC and RBAC?
RBAC and ABAC 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:
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
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).
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.
You can learn more about the decision between RBAC and ABAC here.
For the purpose of this post, we’ll assume you decided you want to set up your policies with ABAC.
The challenge of setting up policies with ABAC
In case you decide 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 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?
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 (OPA).
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 - 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.
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.
OPA supports ABAC policies as shown below:
package abac
# User attributes
user_attributes := {
"Squid": {"tenure": 10, "title": "cashier"},
"Pat": {"tenure": 0.5, "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
.
Congrats! You have successfully implemented ABAC in OPA!
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”.
- 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.
- It is important to choose an authorization model that fits your organization's needs, so it’s neither too simple nor too complex.
- 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.
- 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.
- We saw an example of how to successfully implement ABAC in OPA :)
Want to learn more? Join our Slack channel to ask questions and talk about 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.