Lion Cipher Lab
Write and unit-test an authorization policy with OPA and Rego
- Identity & Access Management
- Intermediate
- ~70 min
- Free · no account required
Why it matters
Almost every breach story has an authorization failure somewhere in it: a user who could reach a record that was not theirs, a role that quietly did more than anyone intended, an endpoint that forgot to check who was calling. In most applications those decisions -- 'can this subject do this action on this resource?' -- are scattered as if/else branches through the codebase. That is a bad place for them. Nobody tests them, the same rule gets copied into three services and then only two get updated, and a single mistyped condition -- an OR where you meant AND, a role check you forgot to add --…
What you'll learn
- naming the problem precisely: an AUTHORIZATION decision answers 'can subject X do action Y on resource Z?', and when that logic lives as scattered if/else branches inside application code it is brittle, untested, duplicated across services, and drifts -- so a one-line logic slip silently grants privilege nobody reviewed
- separating the two jobs behind every access check: the POLICY DECISION POINT (PDP) that decides yes/no, and the POLICY ENFORCEMENT POINT (PEP) that actually blocks or allows the request -- and understanding that OPA is only the PDP: your application is still the PEP and must ask OPA and obey the answer
- installing OPA (Open Policy Agent) as a single self-contained binary -- no Docker, no service to manage -- and running policy decisions entirely offline with the `opa` command-line tool
- reproducing the BEFORE honestly: a naive Python authorization check with a subtle OR bug (`role == 'editor' or action in ('read','write')`) that reads as reasonable but grants ANY role -- including a read-only viewer -- the right to WRITE, and watching it return 'allowed' for a request that should be denied
- writing an authorization policy in Rego, OPA's declarative language: a `package`, a `default allow := false` line that makes the policy DENY BY DEFAULT, and explicit rules that grant `allow` only for specific role/action/resource combinations (RBAC -- role-based access control)
- adding an attribute-based (ABAC) rule -- resource ownership: the owner of a document may read or write it whatever their role -- so you can see the difference between deciding on ROLES alone and deciding on ATTRIBUTES of the subject, action, and resource together (the model NIST SP 800-162 defines)
- evaluating a real decision with `opa eval -d authz.rego -i input.json 'data.authz.allow'` and reading the true/false result out of the returned JSON, plus running the same policy as a decision service with `opa run -s` and querying it over HTTP
- the core discipline: writing a `_test.rego` file of `test_...` rules and running `opa test` so the policy is UNIT-TESTED -- and specifically testing the DENIES (a viewer must NOT write, a stranger must NOT touch another user's document), not just the allows, because over-permission is the failure that actually hurts you
- proving the tests earn their keep: expressing the same OR privilege bug in Rego, running `opa test` and watching the deny test go RED, then fixing the rule and watching it go GREEN -- a change that would have silently over-granted is now caught before it ships
- the judgment that makes this real: deny-by-default; test the denies; policy-as-code is reviewable, versioned in git, and testable like any other code; and the honest limits -- OPA only decides, tests only cover the cases you write, Rego has a learning curve, and a tiny app may not need a whole engine
Steps in this lab
- The problem: authorization decisions scattered through code
- The words you need: OPA, Rego, PDP vs PEP, RBAC vs ABAC, deny-by-default
- Install OPA: one binary, no Docker, no service
- The BEFORE: a naive in-app check that over-permits
- Write authz.rego: deny by default, then RBAC rules
- Add an ABAC rule: the owner of a resource may edit it
- Evaluate a decision: opa eval with an input document
- The key discipline: unit-test the policy, and test the DENIES
- Watch a test catch the privilege bug (red), then fix it (green)
- Wire it into an app (PDP/PEP) and log decisions
- The honest negatives and the judgment that makes this worth doing