This one is like riding a bicycle. Once you know it, you know it. I’ve been going down some Kubernetes rabbit holes and I’ve landed on OPA - Open Policy Agent.
The Open Policy Agent (OPA, pronounced “oh-pa”) is an open source, general-purpose policy engine that unifies policy enforcement across the stack. OPA provides a high-level declarative language that lets you specify policy as code and simple APIs to offload policy decision-making from your software. You can use OPA to enforce policies in microservices, Kubernetes, CI/CD pipelines, API gateways, and more.
Basically, it’s a declarative decision engine which evaluates Rego policies for a given input.
Rego was inspired by Datalog, which is a well understood, decades old query language. Rego extends Datalog to support structured document models such as JSON.
Rego queries are assertions on data stored in OPA. These queries can be used to define policies that enumerate instances of data that violate the expected state of the system.
Rego comes packed with some very neat features.
The OPA project comes with an extensive, easy to follow and brief (good!!) documentation. However, there was one question to which I could not find an answer: how do I express:
(if this OR this) AND that
Here’s my semi-realistic problem:
- given a go structure with a bunch of string properties
- if a user reading the structure:
- belongs to an HR role
- they can see all values of all fields, regardless if a field is restricted, or not restricted
- belongs to any other role
- they can see non-restricted fields only
- ONLY when the user is enabled
- belongs to an HR role
For the following structure:
|
|
anyone who’s not a member of the HR team should see ********
instead of actual values.
There are two known facts while evaluating this policy:
- The list of restricted fields:
email_address
,address1
,address2
, andpostal_code
. - The input, an example goes like this:
|
|
and:
|
|
Okay, let’s start with the policy:
|
|
I want this:
- If the employee works in HR, there is no need to check if a field is restricted.
- Otherwise (if
not is_hr
), the field can be accessed only when it isn’t restricted.
The first condition is easy:
|
|
The second one is also easy:
|
|
What wasn’t clear to me was how do I make these two conditions into a single logical OR operation? It’s really easy, the full policy looks like this:
|
|
It essentially boils down to:
|
|
This policy returns for can_read_restricted_field_when_enabled
:
false
for disabledhr
and fieldemail_address
false
for disabledhr
and fieldfirst_name
true
for enabledhr
, any fieldfalse
for enabledchef
, any field from the restricted listtrue
for enabledchef
, any field outside of the restricted listfalse
for disabledchef
, any field outside of the restricted list
That’s it, pretty cool. Nothing that cannot be done with a bunch of conditionals and loops but on a highly variable input iterating with Rego will be much faster!
§closing thought
Turns out to be completely unrelated:
- Rego is inspired by Datalog.
- Datalog is a a subset of Prolog.
- Prolog would be a perfect language to implement Google’s Zanzibar in.
- Why did Keto project drop the OPA route?