Attribute Based Access Control (ABAC)
This page explains the design approach of Permify’s ABAC support as well as demonstrates how to create and use attribute based permissions in Permify.
What is Attribute Based Access Control (ABAC)?
Attribute-Based Access Control (ABAC) is like a security guard that decides who gets to access what based on specific characteristics or “attributes”.
These attributes can be associated with users, resources, or the environment, and their values can influence the outcome of an access request.
Let’s make an analogy, it’s the best way to understand complex ideas.
Think about an amusement park, and there are 3 different rides. In order to access each ride, you need to have different qualities. For example:
- ride one you need to be over 6ft tall.
- ride two you need to be under 200lbs.
- ride three you need to be between 12 - 18 years old.
Similar to this ABAC checks certain qualities that you have defined on users, resources, or the environment.
Why Would Need ABAC?
It’s obvious but the simple answer is “use cases”… Sometimes, using ReBAC and RBAC isn’t the best fit for the job. It’s like using winter tires on a hot desert road, or summer tires in a snowstorm - they’re just not the right tools for the conditions.
- Geographically Restricted: Think of ABAC like a bouncer at a club who only lets in people from certain towns. For example, a movie streaming service might only show certain movies in certain countries because of rules about who can watch what and where.
- Time-Based: ABAC can also act like a parent setting rules about when you can use the computer. For example, a system might only let you do certain things during office hours.
- Compliance with Privacy Regulations: ABAC can help follow rules about privacy. For example, a hospital system might need to limit who can see a patient’s data based on the patient’s permission, why they want to see it, and who the person is.
- Limit Range: ABAC can help you create a rules defining a number limit or range. For instance, a banking system might have limits for wiring or withdrawing money.
- Device Information: ABAC can control access based on attributes of the device, such as the device type, operating system version, or whether the device has the latest security patches.
As you can see ABAC has a more contextual approach. You can define access rights regarding context around subjects and objects in an application.
Modeling ABAC
To support ABAC in Permify, we’ve added two main components into our DSL: attributes and rules.
Defining Attributes
Attributes are used to define properties for entities in specific data types. For instance, an attribute could be an IP range associated with an organization, defined as a string array:
Here are the all attribute types that you use when defining an attribute
.
Defining Rules
Rules are structures that allow you to write specific conditions for the model. You can think rules as simple functions of every software language have. They accept parameters and are based on condition to return a true/false result.
In the following example schema, a rule could be used to check if a given IP address falls within a specified IP range:
We design our schema language based on Common Expression Language (CEL). So the syntax looks nearly identical to equivalent expressions in C++, Go, Java, and TypeScript.
Please let us know via our Discord channel if you have questions regarding syntax, definitions or any operator you identify not working as expected.
Let’s examine some of common usage of ABAC with small schema examples.
Boolean - True/False Conditions
For attributes that represent a binary choice or state, such as a yes/no question, the Boolean
data type is an excellent choice.
Text & Object Based Conditions
String can be used as attribute data type in a variety of scenarios where text-based information is needed to make access control decisions. Here are a few examples:
- Location: If you need to control access based on geographical location, you might have a location attribute (e.g., “USA”, “EU”, “Asia”) stored as a string.
- Device Type: If access control decisions need to consider the type of device being used, a device type attribute (e.g., “mobile”, “desktop”, “tablet”) could be stored as a string.
- Time Zone: If access needs to be controlled based on time zones, a time zone attribute (e.g., “EST”, “PST”, “GMT”) could be stored as a string.
- Day of the Week: In a scenario where access to certain resources is determined by the day of the week, the string data type can be used to represent these days (e.g., “Monday”, “Tuesday”, etc.) as attributes!
Numerical Conditions
Integers
Integer can be used as attribute data type in several scenarios where numerical information is needed to make access control decisions. Here are a few examples:
- Age: If access to certain resources is age-restricted, an age attribute stored as an integer can be used to control access.
- Security Clearance Level: In a system where users have different security clearance levels, these levels can be stored as integer attributes (e.g., 1, 2, 3 with 3 being the highest clearance).
- Resource Size or Length: If access to resources is controlled based on their size or length (like a document’s length or a file’s size), these can be stored as integer attributes.
- Version Number: If access control decisions need to consider the version number of a resource (like a software version or a document revision), these can be stored as integer attributes.
Double - Precise numerical information
Double can be used as attribute data type in several scenarios where precise numerical information is needed to make access control decisions. Here are a few examples:
- Usage Limit: If a user has a usage limit (like the amount of storage they can use or the amount of data they can download), and this limit needs to be represented with decimal precision, it can be stored as a double attribute.
- Transaction Amount: In a financial system, if access control decisions need to consider the amount of a transaction, and this amount needs to be represented with decimal precision (like $100.50), these amounts can be stored as double attributes.
- User Rating: If access control decisions need to consider a user’s rating (like a rating out of 5 with decimal points, such as 4.7), these ratings can be stored as double attributes.
- Geolocation: If access control decisions need to consider precise geographical coordinates (like latitude and longitude, which are often represented with decimal points), these coordinates can be stored as double attributes.
Example Use Cases
Example of Public/Private Repository
In this example, is_public
is defined as a boolean attribute. If an attribute is a boolean, it can be directly used without the need for a rule. This is only applicable for boolean types.
In this context, if the is_public
attribute of the repository is set to true, everyone can view it. If it’s not public (i.e., is_public
is false), only the owner, in this case user:1
, can view it.
The permissions in this model are defined as such:
permission view = is_public or owner
This means that the ‘view’ permission is granted if either the repository is public (is_public
is true) or if the current user is the owner of the repository.
relationships:
- post:1#owner@user:1
attributes:
- post:1$is_public|boolean:true
Check Evolution Sub Queries Post View → post:1#is_public → true → post:1#admin@user:1 → true
Request keys before hash
check*{snapshot}*{schema*version}*{context}\_post:1$is_public
→ truecheck*{snapshot}*{schema*version}*{context}\_post:1#admin@user:1
→ true
Example of Weekday
In this example, to be able to view the repository it must not be a weekend, and the user must be a member of the organization.
The permissions in this model state that to ‘view’ the repository, the user must fulfill two conditions: the current day (according to the context data day_of_week
) must not be a weekend (determined by the is_weekday
rule), and the user must be a member of the organization that owns the repository.
Relationships:
- organization:1#member@user:1
Check Evolution Sub Queries Organization View → organization:1$is_weekday(valid_weekdays) → true → organization:1#member@user:1 → true
Request keys before hash
check*{snapshot}*{schema*version}*{context}\_organization:1$is_weekday(valid_weekdays)
→ truecheck*{snapshot}*{schema*version}*{context}\_post:1#member@user:1
→ true
Example of Banking System
This model represents a banking system with two entities: user
and account
.
user
: Represents a customer of the bank.account
: Represents a bank account that has anowner
(which is auser
), and abalance
(amount of money in the account).
The check_balance rule: This rule verifies if the withdrawal amount is less than or equal to the account’s balance and doesn’t exceed 5000 (the maximum amount allowed for a withdrawal). It accepts two parameters, the withdrawal amount (amount) and the account’s current balance (balance). The owner check: This condition checks if the person requesting the withdrawal is the owner of the account.
Both of these conditions need to be true for the withdraw
permission to be granted. In other words, a user can withdraw money from an account only if they are the owner of that account, and the amount they want to withdraw is within the account balance and doesn’t exceed 5000.
Relationships
- account:1#owner@user:1
Attributes
- account:1$balance|double:4000
Check Evolution Sub Queries For Account Withdraw → account:1$check_balance(balance) → true → account:1#owner@user:1 → true
Request keys before hash
check*{snapshot}*{schema*version}*{context}\_account:1$check_balance(balance)
→ truecheck*{snapshot}*{schema*version}*{context}\_account:1#owner@user:1
→ true
Hierarchical Usage
In this model:
employee
: Represents an individual worker. It has no specific attributes or relations in this case.organization
: Represents an entire organization, which has afounding_year
attribute. Theview
permission is granted if thecheck_founding_year
rule (which checks if the organization was founded after 2000) returns true.department
: Represents a department within the organization. It has abudget
attribute and a relation to its parentorganization
. Theview
permission is granted if the department’s budget is more than 10,000 (checked by thecheck_budget
rule) and if theorganization.view
permission is true.
Note: In this model, permissions can refer to higher-level permissions (like organization.view
). However, you cannot use the attribute of a relation in this way. For example, you cannot directly reference organization.founding_year
in a permission expression. Permissions can depend on permissions in a related entity, but not directly on the related entity’s attributes.
Relationships
- department:1#organization@organization:1
- department:1#organization@organization:2
Attributes
- department:1$budget|double:20000
- organization:1$organization|integer:2021
Check Evolution Sub Queries For Department View
→ department:1$check_budget(budget) → true
→ department:1#organization@user:1 → true → organization:2$check_founding_year(founding_year) → false
→ organization:1$check_founding_year(founding_year) → true
Request keys before hash
check*{snapshot}*{schema*version}*{context}\_department:1$check_budget(budget)
→ truecheck*{snapshot}*{schema*version}*{context}\_organization:2$check_founding_year(founding_year)
→ falsecheck*{snapshot}*{schema*version}*{context}\_organization:1$check_founding_year(founding_year)
→ true
Evaluation of ABAC Access Checks
Model
In this case, the part written as ‘context’ refers to the context within the request. Any type of data can be added from within the request and can be called within the model.
For instance,
Relationships
- organization:1#admin@user:1
Attributes
- organization:1$ip_range|string[]:[‘187.182.51.206’, ‘250.89.38.115’]
Check request
Check Evolution Sub Queries Organization View → organization:1$check_ip_range(context.ip_address,ip_range) → true → organization:1#admin@user:1 → true
Cache Mechanism The cache mechanism works by hashing the snapshot of the database, schema version, and sub-queries as keys and adding their results, so it will operate in the same way in calls as in relationships. For example,
Request keys before hash
check*{snapshot}*{schema*version}*{context}\_organization:1#admin@user:1
→ truecheck*{snapshot}*{schema*version}*{context}\_organization:1$check_ip_range(ip_range)
→ true
How To Use ABAC
Install Permify
Validation Yaml Structure
Note: The ‘data’ field within the ‘context’ can be assigned a desired value as a key-value pair. Later, this value can be retrieved within the model using ‘request.key’.
Example in validation file:
This YAML snippet specifies a validation context with no tuples or attributes, and a data field indicating the day of the week is Saturday.
Example in model
In the model, a delete
permission rule is set. It calls the function is_weekday
with the value of valid_weekdays
from the related entity. If is_weekday(["monday", "tuesday", "wednesday", "thursday", "friday"])
is true, the delete permission is granted.
Create Validation File
Run validation command
Need any help ?
Our team is happy to help you get started with Permify. If you’d like to learn more about using Permify in your app or have any questions about this example, schedule a call with one of our Permify engineers. Alternatively you can join our discord community to discuss.