Cerbos#
Policy-based access control with Cerbos, through the Cerbos PDP’s HTTP API. No extra dependency: requests use the standard library.
docker run -p 3592:3592 -v "$PWD/policies:/policies" ghcr.io/cerbos/cerbos:0.56.0
from needtoknow.authorizers.cerbos import CerbosAuthorizer
authorizer = CerbosAuthorizer("http://localhost:3592")
What Cerbos sees#
Each chunk is a resource of kind document (change it with resource_kind=) whose attributes are
the chunk’s metadata, and whose id is the chunk id (or the metadata field resource_field=). The
subject is the principal:
{"id": "alice", "roles": ["user"], "attr": {"groups": ["eng", "hr"], "region": "eu"}}
roles= is a list of roles for every principal, or a function of the subject; attr holds the
subject’s groups and its attributes. A subject attribute named groups is refused with
AuthorizationError, since it would replace the subject’s groups. Pass policy_version= and
scope= to select a policy version and scope, and actions={"read": "view"} to map needtoknow’s
action to yours.
A policy for permissions stored on the chunks
(examples/cerbos/policies/document.yaml):
apiVersion: api.cerbos.dev/v1
resourcePolicy:
version: default
resource: document
rules:
- actions: ["read"]
effect: EFFECT_ALLOW
roles: ["*"]
condition:
match:
any:
of:
- expr: request.principal.id in request.resource.attr.allowed_users
- expr: '"*" in request.resource.attr.allowed_groups'
- expr: hasIntersection(request.resource.attr.allowed_groups, request.principal.attr.groups)
Checks#
check sends CheckResources requests of batch_size resources (50, Cerbos’s default limit per
request) and reads EFFECT_ALLOW or EFFECT_DENY for each. An answer for a different resource, a
missing or unknown effect, or a wrong number of results raises AuthorizationError.
Pre-filtering from query plans#
filter_for asks PlanResources which documents the principal may read. Cerbos answers with a query
plan: always allowed, always denied, or a condition over resource attributes, with the principal’s
attributes already filled in. needtoknow translates the parts of the plan it can express exactly:
Condition |
Filter |
|---|---|
|
|
|
|
|
|
|
|
always denied |
a filter that matches nothing |
Anything else (!=, not, comparisons, exists and other macros, nested attribute paths, boolean
or float values) and “always allowed” give no filter, and the retriever post-filters, with Cerbos
deciding each candidate. Results stay correct either way; pre-filtering is what keeps recall high
for users who may read little, so write the rules that decide reading in the subset above.
CEL’s == compares a list attribute as a whole, while needtoknow’s In matches any element of a
list. Keep attributes compared with == scalar, and use hasIntersection or in for list
attributes such as allowed_groups; otherwise pre-filtered hits fail the re-check and are reported
as violations.
Failures#
Every failure raises AuthorizationError, so retrieval returns nothing. Connections are reused,
transient failures are retried once, and a CircuitBreaker can pause requests to a failing PDP (see
Operations).
CI runs the authorizer against Cerbos 0.56.0 with the example policy: the policy yields a
pre-filter, every strategy returns exactly the reference answer for random documents, and check
and filter_for pass the conformance kit.