ADR-0008: YAML label-based policy, push-applied, signed snapshots
- Status: Accepted (owner approved 2026-10-13)
- Date: 2026-10-13
Decision
Section titled “Decision”- Document kinds:
role,role_mapping,resource, each withversion: v1. They are parsed strictly (deny_unknown_fields) withserde-saphyr, chosen becauseserde_yamlis deprecated andserde_ymlis unsound (RUSTSEC-2025-0068). - Evaluation:
- deny by default
- any matching
denyrule wins - an
allowrule matches when the resource kind matches, all selector keys match (values ORed within a key), and the requested principal (login, DB role, kube group, Redis user) is listed in the rule - only an explicit
"*"wildcard is accepted, and"*"in an admin role triggers a lint warning
Decision::RequiresApprovalis reserved for JIT and approvals (see ADR-0025). Every enforcement point treats it as deny, and tests assert this.- Delivery:
limen admin apply -f <dir> [--dry-run]requires thelimen:adminrole. The control plane stores immutable, numbered policy versions in Aurora and emitspolicy.changewith the author, version, SHA-256, and a structured diff. Git stays the source of truth, and CI runsapply. - Snapshots: the control plane signs
{version, issued_at, documents}with the internal CA key and streams it to proxies and workers, which persist it to disk. Each worker gets only the resources it serves plus all roles. - Extension points (not built in v1):
lock(deny a user or role immediately and end their sessions), and approval requests.
Consequences
Section titled “Consequences”- + GitOps-friendly. Every change is attributable and auditable inside Limen.
- − Two places to look (Git and the Limen policy history). The
policy.changeevent carries the Git commit SHA when CI passes--source-ref.