ALFA Language Basics
ALFA is a constrained, highly-structured fine-grained authorization policy language. Let's unpack each term.
- Constrained: ALFA is purpose-built for authorization. As such it is not a full-blown programming language, unlike Open Policy Agent's Rego. This makes it easier to read, write, test, and audit.
- Highly-structured: unlike Cedar and Rego, ALFA provides built-in structure or scaffolding. A
policy is in fact made up of one of three elements:
PolicySet
: the PolicySet (PS) is generally the root element. It can contain other PolicySet elements as well as Policy elements. It can be referenced or inlined.Policy
: the Policy generally lives inside a PolicySet element. It can be referenced or inlined. A Policy contains Rule elements.Rule
: the Rule is the lowest type of structure. It contains the effect (Permit or Deny).
- Fine-grained: With ALFA, you can implement authorization policies that are as broad or as specific as you see fit. You can express use cases such as A manager can view records in their department or Alice can view photo album 'Croatia 2014'.
- High-performant: ALFA is built for speed. Because it is constrained and highly-structured, the evaluation engine can quickly prune all the unneeded policies and only focus on the relevant ones.
- Built-in conflict resolution: ALFA lets you control how policies are combined and how conflicts are handled. The engine will always guarantee the same consistent result. You have oversight over priorities.
- Native support for ABAC and ReBAC: ALFA is all about attributes. They can describe the user, the action, the object, contextual data, and relationships. You can define your own attributes and choose where to source the data from.
Structure
PolicySet
A PolicySet
is the topmost structural element in an ALFA policy. It can contain
PolicySet
and
Policy
elements. A PolicySet
contains a Target
to scope access. Use
PolicySet
elements to organize your policies into logical building blocks e.g. use cases,
business applications, and features.
Policy
A Policy
is the second structural element in an ALFA policy. It can contain
Rule
elements only. A Policy
contains a Target
to scope access. Use
Policy
elements to organize your rules into logical building blocks e.g. use cases,
business applications, and features.
Rule
A Rule
is the third and last structural element in an ALFA policy. It contains
the effect of the overall policy i.e. either Permit
or Deny
. A Rule
contains a Target
to scope access. It can also contain a Condition
Use
Rule
elements to define the actual permissions you want to grant or deny.
Cheatsheet
Name | Description | Children | Target | Condition | Obligation & Advice |
---|---|---|---|---|---|
PolicySet | Topmost element of an ALFA policy. |
|
|||
Policy | Intermediary element of an ALFA policy. |
|
|||
Rule | Leaf element of an ALFA policy. It contains the effect, either Permit or
Deny .
|
|
Targets & Conditions
Target
A Target
is a simple way to match an incoming authorization request with a policy. In a target,
you can compare an attribute to a value e.g. role=="manager"
. You can also use and
and or
to combine attribute comparisons e.g.
role=="manager" and action=="view" and object=="financial record"
. Of all the functions
available in ALFA, only those that compare an attribute to a value (e.g. string equality) can be used in a
Target
. For a complete list of functions, check out the ALFA Function Reference.
When to use Targets?
Use Target
for simple matching or scoping. Break down your authorization challenge into simple
statements you can then use in your Target
.
Condition
A Condition
is a more advanced way to match an incoming authorization request with a policy. You
are free to use any of the functions available in ALFA in any structure you see fit. You can nest as many
functions as you like. Conditions are particularly useful to implement relationships. If
for instance, you want to grant a user access to a record because they are in the same department or because
the user's clearance is greater than the record's classification, then you use a Condition
.
user.clearance>record.classification // Permit if the user's clearance is high enough
user.department==record.department // Permit if the user is in the same department as the record
When to use Conditions?
Use Condition
for advanced logic, attribute manipulation, or relationships.
Tip
Try to use Target
elements as much as you can to organize your policies. Only use
Condition
when you need advanced logic or ReBAC (relationships).
Conflict Resolution & Combining Algorithms
Built-in conflict resolution
One of the coolest features of ALFA is its ability to organize, stack up, mix, and match policies. It means you can have a policy that will grant managers access to records and another that will deny access outside office hours.
Now, of course, if you have such policies, you need to decide which one wins. That's why ALFA comes with
built-in conflict resolution. The mechanism used to handle conflicts is called a combining
algorithm. It is defined at the level of the PolicySet
or Policy
parent element
and it applies to that element's children.
ALFA Combining Algorithms Definitions
- denyOverrides: any of the children returns Deny, then evaluation is stopped and Deny is returned. View Truth Table.
- permitOverrides: any of the children returns Permit, then evaluation is stopped and Permit is returned. View Truth Table.
- firstApplicable: as soon as a child returns either of Permit or Deny, then evaluation is stopped and that decision is returned. View Truth Table.
- orderedDenyOverrides: same as denyOverrides. Order is strictly enforced. View Truth Table.
- orderedPermitOverrides: same as permitOverrides. Order is strictly enforced. View Truth Table.
- denyUnlessPermit: any of the children returns Permit, then evaluation is stopped and Permit is returned. Otherwise, Deny is returned. View Truth Table.
- permitUnlessDeny: any of the children returns Deny, then evaluation is stopped and Deny is returned. Otherwise, Permit is returned. View Truth Table.
- onlyOneApplicable: only one of the children must apply and return a decision. That decision is the overall decision, either Permit or Deny. View Truth Table.
- onPermitApplySecond: the decision coming from the first child is Permit, then return the decision from the second child, otherwise return the decision from the third child (if any). View Truth Table.
Example
In the example above, we have a Policy
which contains three Rule
children. Each
rule returns its own decision: Permit, Deny, and NotApplicable respectively. Depending on the combining
algorithm defined on the level of the policy, the end result will either be Permit, Deny, or Indeterminate.
- denyOverrides: Deny.
- permitOverrides: Permit.
- firstApplicable: Permit.
- orderedDenyOverrides: Deny.
- orderedPermitOverrides: Permit.
- denyUnlessPermit: Permit.
- permitUnlessDeny: Deny.
- onlyOneApplicable: Indeterminate.
- onPermitApplySecond: Deny.
ALFA Combining Algorithm Truth Tables
DenyOverrides | 1. First choose the column below | ||||||
Permit | Deny | NotApplicable | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | ||
2. Then choose the row | Permit | Permit | Deny | Permit | Indeterminate (D) | Permit | Indeterminate (DP) |
Deny | Deny | Deny | Deny | Deny | Deny | Deny | |
NotApplicable | Permit | Deny | NotApplicable | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | |
Indeterminate (D) | Indeterminate (D) | Deny | Indeterminate (D) | Indeterminate (D) | Indeterminate | Indeterminate (DP) | |
Indeterminate (P) | Permit | Deny | Indeterminate (P) | Indeterminate (DP) | Indeterminate (P) | Indeterminate (DP) | |
Indeterminate (DP) | Indeterminate (DP) | Deny | Indeterminate (DP) | Indeterminate (DP) | Indeterminate (DP) | Indeterminate (DP) |
PermitOverrides | 1. First choose the column below | |||||||
Permit | Deny | NotApplicable | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | |||
2. Then choose the row | Permit | Permit | Permit | Permit | Permit | Permit | Permit | |
Deny | Permit | Deny | Deny | Deny | Indeterminate (P) | Indeterminate (DP) | ||
NotApplicable | Permit | Deny | NotApplicable | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | ||
Indeterminate(D) | Permit | Deny | Indeterminate (D) | Indeterminate (D) | Indeterminate (DP) | Indeterminate (DP) | ||
Indeterminate (P) | Permit | Indeterminate (P) | Indeterminate (P) | Indeterminate (DP) | Indeterminate (P) | Indeterminate (DP) | ||
Indeterminate (DP) | Permit | Indeterminate (DP) | Indeterminate (DP) | Indeterminate (DP) | Indeterminate (DP) | Indeterminate (DP) |
denyUnlessPermit | 1. First choose the column below | |||||||
Permit | Deny | NotApplicable | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | |||
2. Then choose the row | Permit | Permit | Permit | Permit | Permit | Permit | Permit | |
Deny | Permit | Deny | Deny | Deny | Deny | Deny | ||
NotApplicable | Permit | Deny | Deny | Deny | Deny | Deny | ||
Indeterminate (D) | Permit | Deny | Deny | Deny | Deny | Deny | ||
Indeterminate (P) | Permit | Deny | Deny | Deny | Deny | Deny | ||
Indeterminate (DP) | Permit | Deny | Deny | Deny | Deny | Deny |
PermitUnlessDeny | 1. First choose the column below | |||||||
Permit | Deny | NotApplicable | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | |||
2. Then choose the row | Permit | Permit | Deny | Permit | Permit | Permit | Permit | |
Deny | Deny | Deny | Deny | Deny | Deny | Deny | ||
NotApplicable | Permit | Deny | Permit | Permit | Permit | Permit | ||
Indeterminate (D) | Permit | Deny | Permit | Permit | Permit | Permit | ||
Indeterminate (P) | Permit | Deny | Permit | Permit | Permit | Permit | ||
Indeterminate (DP) | Permit | Deny | Permit | Permit | Permit | Permit |
firstApplicable | 1. First choose the column below | |||||||
Permit | Deny | NotApplicable | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | |||
2. Then choose the row | Permit | Permit | Deny | Permit | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | |
Deny | Permit | Deny | Deny | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | ||
NotApplicable | Permit | Deny | NotApplicable | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | ||
Indeterminate (D) | Permit | Deny | Indeterminate (D) | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | ||
Indeterminate (P) | Permit | Deny | Indeterminate (P) | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | ||
Indeterminate (DP) | Permit | Deny | Indeterminate (DP) | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) |
orderedDenyOverrides | 1. First choose the column below | |||||||
Permit | Deny | NotApplicable | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | |||
2. Then choose the row | Permit | Permit | Deny | Permit | Indeterminate | Permit | ||
Deny | Deny | Deny | Deny | Deny | Deny | Deny | ||
NotApplicable | Permit | Deny | NotApplicable | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | ||
Indeterminate (D) | Indeterminate | Deny | Indeterminate (D) | Indeterminate (D) | Indeterminate (D) | Indeterminate (DP) | ||
Indeterminate (P) | Permit | Deny | Indeterminate (P) | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | ||
Indeterminate (DP) | Indeterminate (DP) | Deny | Indeterminate (DP) | Indeterminate (D) | Indeterminate (D) | Indeterminate (DP) |
orderedPermitOverrides | 1. First choose the column below | |||||||
Permit | Deny | NotApplicable | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | |||
2. Then choose the row | Permit | Permit | Permit | Permit | Permit | Permit | Permit | |
Deny | Permit | Deny | Deny | Deny | Indeterminate (P) | Indeterminate (DP) | ||
NotApplicable | Permit | Deny | NotApplicable | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | ||
Indeterminate(D) | Permit | Deny | Indeterminate (D) | Indeterminate (D) | Indeterminate (DP) | Indeterminate (DP) | ||
Indeterminate (P) | Permit | Indeterminate (P) | Indeterminate (P) | Indeterminate (DP) | Indeterminate (P) | Indeterminate (DP) | ||
Indeterminate (DP) | Permit | Indeterminate (DP) | Indeterminate (DP) | Indeterminate (DP) | Indeterminate (DP) | Indeterminate (DP) |
onlyOneApplicable | 1. First choose the column below | |||||||
Permit | Deny | NotApplicable | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | |||
2. Then choose the row | Permit | Indeterminate | Indeterminate | Permit | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | |
Deny | Indeterminate | Indeterminate | Deny | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | ||
NotApplicable | Permit | Deny | NotApplicable | Indeterminate (D) | Indeterminate (P) | Indeterminate (DP) | ||
Indeterminate (D) | Indeterminate (D) | Indeterminate (D) | Indeterminate (D) | Indeterminate (D) | Indeterminate (DP) | Indeterminate (DP) | ||
Indeterminate (P) | Indeterminate (P) | Indeterminate (P) | Indeterminate (P) | Indeterminate (DP) | Indeterminate (P) | Indeterminate (DP) | ||
Indeterminate (DP) | Indeterminate (DP) | Indeterminate (DP) | Indeterminate (DP) | Indeterminate (DP) | Indeterminate (DP) | Indeterminate (DP) |