Frontier Warrant — Platform Authorization
How the Federal Frontier Platform decides whether an action is permitted — a per-action allow/deny gate over jurisdiction, classification, and separation of duties, evaluated locally by the service that owns the action.
Frontier Warrant
Frontier Warrant is the Federal Frontier Platform’s authorization model. It answers exactly one question, for one action at a time:
May this subject perform this action on this resource — right now?
The answer is a decision document and nothing more:
{ "allow": false, "reasons": ["over_classification"] }
That narrowness is deliberate. An authorization decision that returns a single verdict and its reasons can be tested, audited, and reasoned about. Warrant is defined by ADR-018 (permission catalog and role bindings), ADR-019 (on-behalf-of identity), and ADR-022 (the jurisdiction model).
What Warrant is not
Being precise about the boundaries saves a great deal of misdesign:
- It is not a tool-set oracle. You cannot call Warrant once and receive the set of tools an agent may use. It evaluates one action per call. Any design that assumes “ask Warrant, get a narrowed toolbox” is building against an interface that does not exist.
- It does not express human-in-the-loop. Warrant never says “this needs approval.” Whether a remediation pauses for a human is decided by the Remediation Policy and the dispatch state machine. Warrant only says whether the human who showed up is allowed to approve.
- It is not a replacement for Kubernetes RBAC. RBAC governs what a workload’s service account may do against the API server. Warrant governs what a person or agent identity may do against platform resources. Both apply.
- It does not grant anything. Warrant is a decision point. Grants live in the identity provider.
The three conditions
Every decision runs the same predicate, and all three conditions must hold. There is no ordering trick and no partial credit — deny is the default, and a subject is permitted only when the policy can affirmatively prove all three.
subject · action · resource"] J{"Jurisdiction
does a grant reach this resource?"} C{"Classification
resource ≤ subject's ceiling?"} S{"Separation of duties
subject ≠ originator?"} OK["allow: true
reasons: [permitted]"] NO["allow: false
reasons: [...]"] REQ --> J J -->|no| NO J -->|yes| C C -->|no| NO C -->|yes| S S -->|no| NO S -->|yes| OK
1. Jurisdiction
A grant is scoped to a jurisdiction — an opaque, customer-defined boundary. It might be an environment, an enclave, a program, a coalition partner, or a tenant; the platform does not care which, and deliberately does not impose a taxonomy. Governable resources carry a boundary_id, and a grant reaches a resource only when the two intersect.
The corollary matters more than the rule: a resource that belongs to no jurisdiction is in nobody’s authority, not everybody’s. An unassigned resource is denied to every subject, including administrators. Onboarding a deployment therefore includes declaring which resources belong to which jurisdiction.
2. Classification ceiling
Classification is an orthogonal axis, evaluated on every decision and never collapsed into jurisdiction. Every subject carries a clearance ceiling and every resource a classification; the resource must sit at or below the ceiling.
| Token | Rank |
|---|---|
unclassified |
0 |
cui |
1 |
il2 |
2 |
il4 |
4 |
il5 |
5 |
il6 |
6 |
Tokens are lowercase. An unrecognised token — including IL4 — has no rank, and an unranked classification cannot be proven to sit below any ceiling, so it denies. This is deliberate: a typo in a classification label fails safe rather than silently widening access.
3. Separation of duties
The identity that originated an action may not approve it. For remediation approval the rule compares the approving subject against the recorded originator, so the same person cannot both propose and authorise a change to production.
The grant model
A grant is the triple role × jurisdiction × clearance ceiling. Grants are expressed as group membership in the identity provider (Keycloak), using three path grammars:
| Group path | Scope conferred |
|---|---|
/warrant/global/<role> |
Unrestricted scope — the role applies estate-wide |
/warrant/project/<project>/<role> |
Scoped to a named project |
/warrant/<jurisdiction>/<role> |
Scoped to a jurisdiction (ADR-022) |
global and project are reserved segments. Roles come from the platform’s permission catalog, which defines resource families (cluster, workload, gitops, ontology, registry, secret, observability, identity, policy, remediation, and others) and the actions within each. A role binds a set of family:action permissions; frontier-admin holds the wildcard.
The subject’s ceiling and identity attributes ride in the access token, so a decision needs no directory lookup at evaluation time.
Two evaluation modes
The same core predicate serves both, which is what keeps a list view consistent with the action it offers.
Decision mode answers a point question — may this subject approve this remediation? It returns the allow/deny document and is the mode that gates an action.
Scope-predicate mode filters a candidate set — which of these resources may this subject act on? It exists so that a list endpoint never returns an unscoped collection. Because both modes run the identical predicate, an item cannot appear actionable in a list and then be refused when acted upon.
Where it runs
Warrant is evaluated locally, by the service that owns the action. A Policy Enforcement Point (PEP) library validates the caller’s token against the identity provider, assembles the subject, and evaluates the policy bundle on the spot — today by invoking OPA against the mounted bundle, once per decision. There is no network round-trip to a central decision service on the request path, and no OPA pod, sidecar, or central policy service in the deployment.
OIDC token"] SVC["Platform service
(PEP, evaluates locally)"] BUN["Policy bundle
mounted, hot-reloadable"] AUD["Audit record
subject · actor · action · resource · decision"] OP --> SVC BUN --> SVC SVC --> AUD SVC -->|allow| ACT["Action proceeds"] SVC -->|deny| DEN["Denial + reasons recorded
acted on only when the rollout
mode is set to enforce"]
Three properties follow from this design:
- Deny by default. The policy permits nothing unless it can affirmatively prove all three conditions —
default allow := falseis the first thing the Statute establishes. - Fail closed on evaluation error. If the policy cannot be evaluated, the decision it produces is a denial, never an accidental permit.
- Single source of truth. Authorization semantics live in one policy repository under a conformance suite, so they are uniform across installations rather than per-customer forks. There is no mechanism for editing deny logic outside that repository, and that is intentional.
The first two describe the decision the policy produces. Whether a denial is acted upon is a separate and deliberate setting — see Rollout model.
Every decision emits an audit record carrying the subject, the acting client, the action, the resource’s scope facts, the verdict and the reasons.
Deny reasons
Denials are structured, not prose. Consumers receive stable codes:
| Reason | Meaning |
|---|---|
no_authorizing_grant_in_jurisdiction |
No grant the subject holds reaches this resource’s jurisdiction |
over_classification |
The resource’s classification exceeds the subject’s clearance ceiling |
separation_of_duties |
The subject originated this action and may not also approve it |
More than one may be returned at once — the decision reports every condition that failed, not just the first.
Rollout model
Warrant ships with an explicit rollout mode so an installation can prove its policy against real traffic before anyone can be locked out.
| Mode | Behaviour |
|---|---|
shadow |
Every decision is evaluated and audited, but nothing is blocked. The system records what would have been denied. |
enforce |
Denials are enforced. A blocked action returns 403 with its reasons. |
Shadow is not a half-finished state — it is how an authorization control earns the right to refuse anything. Frontier Warrant runs in shadow on the Federal Frontier Platform today: the engine evaluates every guarded action against real production traffic and writes an audit record for each decision, and no request is refused on its verdict. Enforcement is a single, deliberate, reversible configuration change, held until every operator who needs a grant has one — because the failure mode of flipping early is locking the on-call team out of the tooling they need during an incident.
The asymmetry is the whole argument: a policy that is too permissive is a finding you can act on, while a policy that is too restrictive is an outage. Shadow converts that risk into an audit log you can review before anything is at stake.
shadow"] --> B["Observe real decisions
in the audit log"] B --> C["Assign jurisdictions
issue operator grants"] C --> D["Verify a real operator
is authorized, not locked out"] D --> E["Flip to enforce"]
Skipping straight to enforce is not recommended. The sequence above exists because each step surfaces a class of problem the next one would otherwise turn into an outage — most commonly resources that were never assigned a jurisdiction, and therefore deny for everyone.
Operator experience
Where Warrant governs a workflow, the decision is surfaced in the interface rather than left in a log. In the SRE approval queue in OutpostAI, each remediation shows its authorization state: authorized items are actionable, and items the decision would block are marked with the reason in plain language, with their approve control disabled to mirror the decision — outside your jurisdiction, above your clearance, you originated this remediation. An expandable breakdown shows all three checks with the failing one identified.
While an installation is in shadow mode the interface says so explicitly, so an operator is never misled into believing an advisory decision is a real refusal.
Design rationale
Why local evaluation rather than a central PDP? An authorization service on the request path is a new dependency for every guarded action, and a new outage mode. Evaluating the mounted bundle locally keeps the decision fast and keeps a policy-service failure from becoming a platform failure.
Why is the decision document so small? Because everything a caller might want to do with a richer response — narrow a toolbox, decide whether to prompt a human, attach obligations — is a different concern with a different lifecycle. Keeping Warrant to allow/deny/reasons means it can be exhaustively tested and its behaviour reasoned about from the outside.
Why jurisdiction rather than a fixed hierarchy? Because customers do not agree on what the boundary is. Environment, enclave, classification domain, program, tenant, coalition partner — imposing one taxonomy would force every deployment that disagrees into a workaround. An opaque boundary key with an explicit assignment step fits all of them without special cases.
Related
- Remediation Policy — where human-in-the-loop is actually decided
- OutpostAI — HIL Dispatch Console — where authorization is surfaced to operators
- Autonomous SRE Agent — the workflow Warrant governs today
- MCP Security Posture — the agent-tooling attack surface
- Network Policy Architecture — network-layer zero trust