Attribute Based Access Control (ABAC)
Attributes are a way to further describe your application. Every part of your application has characteristics that can be thought of as an attribute. You can use this to control your authorization logic in a very granular way. For example, a user in your app might have a status of active or inactive. Or, a resource might be public or private. A few more examples are given in the table below.
Object | Example Attributes |
---|---|
Users | • Employment Status: full-time, part-time, contractor, ... • Reward Status: platinum, gold, silver, ... • User Level: superadmin, user, guest |
Resources | • Privacy Status: private, public • Region: Africa, Americas, Asia, Europe, Oceania • Confidentiality Status: top secret, secret, restricted,..., public |
Attributes also have a few characteristics of their own! They might be binary (this or that, true or false, ect.), or they may come from a collection of terms. These factor contribute to how you use them in your authorization.
Toggle Attributes
When modeling attributes that have only one or two states that you care about, you can use the rule name to describe the state that a user or resource currently has. The resulting rule statements usually take the form is_<ATTRIBUTE_STATE>.
Example Use Case | Attribute | Attribute State | Rule Statement |
---|---|---|---|
All users have the read permission on public repos. | Privacy Status | public | Use this attribute to label a resource as public: is_public(repo). |
Superadmins can edit resources across organizations. | User Level | superadmin | Use this attribute to label a user as a superadmin: is_superadmin(user). |
Only rewards members users have access to certain resources. | Membership Type | rewards_member | Use this attribute to label a user as a rewards member: is_rewards_member(user). |
Get Started with Toggle Attributes
Action Items
Prerequisites
We'll use a concrete Github example and add two attributes:
- An attribute that marks a repo as public.
- An attribute that describes a user as the owner of a repo.
Step 1: Use the attribute rule statement to modify existing rule behavior
If the rule doesn't exist in longhand, write a new rule with the attribute rule statement. Make sure the new rule doesn't conflict with any shorthand rules defined in resource blocks.
In this example we'll be extending the logic for
read if collaborator
. By extending the rule, rather than replacing it, we allow existing
has_role(actor, "collaborator, repo)
facts to still be valid. The new has_permission
rule appears in the right
column code block below.
NOTE: What's not obvious in this example is that we are modifying a
has_permission
rule. You may recall that the shorthand statementread if collaborator;
, expands to:
has_permission(actor: Actor, "read", repo: Repository) ifhas_role(actor, "collaborator", repo);
Simple Resource Specific Pattern
| Resource Specific Pattern with Attributes
|
Using this same pattern we can also assign default roles to users with certain attributes. For example, the owner of a repo should have admin permissions.
has_role(user: User, "admin", repo: Repository) if is_owner(user, repo);
NOTE: The ownership of a resource is dependent on two pieces of information: the specific resource in question, and the user labeled as the owner. The attribute rule statement must also contain this information to work as intended.
Next Steps
Defining Attributes with Additional State
Get Started with Defining Attributes with Additional State
Action Items
In the get started example above, we introduced a simple way to add attributes to rules. However, this approach does not work when the attribute has many possible states that you need to represent. In this case, you'll use an additional argument to the attribute to represent this additional state:
has_<ATTRIBUTE>(Type, <ATTRIBUTE_STATE>)
Using Multiple Attribute States
In Github, public and private are labels repositories can have. For this last pattern we'll present, suppose there is a third label: open_collaboration. Anyone can collaborate on a repo with this label.
First, change the attribute rule statement from is_public
to has_label
in the has_permission
rule:
has_permission(_: Actor, "read", repo: Repository) if has_label(repo, "public");
Next, create a new default collaborator role when a repo has the open_collaboration label. Reuse the has_label
rule statement and change the attribute state.
has_role(_: Actor, "collaborator", repo: Repository) if has_label(repo, "open_collaboration");
Next Steps
Additional Resources
Talk to an Oso Engineer
If you'd like to learn more about using Oso Cloud in your app or have any questions about this guide, connect with us on Slack. We're happy to help.