EDR 0015 Status: accepted Implementation: none
Who may approve what is reviewed configuration, not a console setting
Targets, roles, approval policy and standing orders live in a versioned repository, are applied by a signed change, and every applied version is recorded in the logbook. Delegation is the runtime path.
TL;DR
Marque's configuration — targets, roles, approval policy, standing orders, groups — is a
declarative document in a version-controlled repository. It is changed by a reviewed pull request and
applied by marque policy apply, which is itself an authenticated, signed, logged act.
Marque's runtime authority — delegations — is granted in the product, by people, within the bounds configuration allows (EDR-0007).
The line between them: configuration says who is allowed to grant; delegation is granting. A change to who can approve production writes should be as hard to make quietly as a change to production infrastructure, and should be reviewable by someone who was not in the room. A change to who may unlock sandbox accounts this month should take thirty seconds.
There is no console screen that widens approval authority. That is deliberate, and it is the first thing someone will ask for.
Context
Approval policy is the part of an approval system that gets quietly loosened. Not maliciously — someone is on holiday, a release is blocked, an approver is needed at 2am and the on-call engineer adds themselves to the approver group "just for tonight". Nobody removes it. Six months later the group is everyone, and the control has decayed to nothing without a single decision having been made to remove it.
Two properties defeat that decay. Review: a change is proposed, seen by someone else, and merged, which is enough friction to make "just for tonight" visible. Expiry: temporary access is expressed as something that ends by itself, so the holiday case does not need a permanent change at all — which is exactly what delegation is for.
Configuration-as-reviewed-code also solves the disaster-recovery question. If the policy exists only
in Marque's database, restoring Marque means restoring who could approve what from a backup, and
being unsure whether it is current. With the repository as the source, the answer is apply.
Decision
The document. One declarative file set, engine-agnostic:
{
"targets": [ { "name": "prod-primary", "engine": "postgres", "criticality": "critical",
"pilot": "pilot-us-west-2", "displayable_columns": [ … ],
"require_key_backing": "hardware", "signing_surface": "local",
"require_execution_presence": false } ],
"roles": [ { "role": "settings_writer", "target": "prod-primary",
"db_user": "app_settings_writer", "credential": { "kind": "aws-iam" },
"criticality": "sensitive" } ],
"groups": [ { "name": "support", "from": "idp:group:support-engineers" } ],
"policy": [ { "targets": ["prod-primary"], "roles": ["settings_writer"],
"approvers": ["group:data-oncall"],
"min_approvals": 1, "self_approval": false,
"may_delegate": ["group:data-oncall"],
"max_marque_ttl": "1h", "max_grace_seconds": 0,
"require_envelope": "webauthn", "signing_surface": "local",
"surveyor": { "jurors": 3 },
"emergency_approvers": ["group:incident-command"],
"urgency_may_collapse_stages": false,
"may_grant_unbounded_break_glass": ["theo@acme.example"],
"default_budget": { "executions": 1 } } ],
"standing_orders": [ … ]
}
Rules that are structural, not conventional:
- Groups come from the identity provider. Marque does not maintain a membership list, so offboarding happens in one place (EDR-0003).
self_approvaldefaults to false, and setting it true on acriticaltarget requires an explicit acknowledgement field naming who accepted the risk. A one-person team genuinely needs it; it should not be reachable by accident.min_approvalsmay exceed one. Two signatures on a marque (EDR-0004) is a natural extension of a format that already carries multiple.max_marque_ttlis a ceiling on what an approver may grant, not a default. An approver cannot sign a longer window than policy permits.max_grace_secondsis the same ceiling for revocation grace, and defaults to zero. Without it, one approver could mint a marque whosegracecovers its entire life, which is a standing credential wearing a lease. Raising it above zero requires the same explicit acknowledgement fieldself_approvalneeds (EDR-0004).require_key_backingis what actually expresses "not a file on a laptop":hardwareorany, checked against the backing recorded in the signer's roster entry (EDR-0031).criticaltargets default tohardware. The envelope was the wrong proxy for this —es256covers both a Secure Enclave key and the file fallback, so selecting on the envelope excluded a hardware CLI key while admitting nothing it meant to.require_enveloperemains, for a deployment that genuinely wants to constrain the wire envelope (EDR-0023). It is not thecriticaldefault any more.signing_surfacenames where the payload is rendered and signed, which is a different question and was originally conflated with the one above.localrequires locally-installed code the control plane does not serve;criticaltargets default tolocal(EDR-0036). Makingwebauthnthecriticaldefault on its own pushed those approvals into the browser — the surface the control plane serves — which was strictly worse than the file-backed key it was guarding against. Relaxing either on acriticaltarget requires the acknowledgement field.surveyor.jurorssets the Tier-B panel size, with a floor of 3 (EDR-0017).may_delegatebounds who can create delegations, and a delegation may never exceed the delegator's own policy grant.emergency_approversjoin every stage's eligible set when a request is marked urgent (EDR-0037). They are additional, never a replacement.urgency_may_collapse_stagesdecides whether urgency may reduce a multi-stage chain to one, and defaults to false. On, it lets urgency manufacture authority nobody granted, which is why it is a deliberate per-target choice rather than a global behaviour.
[!NOTE] "Break glass" means exactly one thing in this corpus, and it is EDR-0037's execution capability. The emergency policy apply here is
--unreviewed, and a marque carryingrevocation.policy: graceis a grace marque (EDR-0004). Three things were briefly called break-glass, which is how an operator ends up reaching for the wrong one during an incident.
may_grant_unbounded_break_glassnames who may issue a break-glass grant whosescopeisany. That is the widest object in the system, so granting it is its own permission rather than a value someone can type (EDR-0037).- Break-glass grants themselves are not policy — they are per-principal signed artefacts, granted in the product like a delegation, bounded by what policy above permits.
Applying produces an anchored artefact. The applied version is co-signed by k approver device keys and epoch-chained, in the same family as the roster (EDR-0031), and distributed to Pilots — which is what lets a Pilot recompute an approval requirement rather than believe the one in a marque's payload (EDR-0036). The control plane transports the artefact and cannot author it.
Applying. marque policy apply requires a fresh authentication, prints a diff of authority
rather than a diff of text — "adds 4 people to who can approve writes on prod-primary", "widens
settings_writer from 1 column to 3" — and requires confirmation of that summary. The applied
version's digest, its diff, and the applier's identity are appended to the logbook
(EDR-0012).
Refusals are loud. A policy that would leave a target with no eligible approver, grant approval
over a target to a group that does not resolve, or declare a transform provider on a target that
also has standing orders, is refused at apply time with the reason. That last one is the composition
EDR-0028 forbids: a transform changes the statement,
and a fast path exists precisely because a human signed the statement's shape in advance — so the
combination is caught where it is configured rather than discovered at execution.
An empty approver set must never silently mean "anyone" or "no one" — the first is a hole and the
second is an outage.
Emergency changes exist and are conspicuous. marque policy apply --unreviewed applies without a
merged review, and
it: requires two authenticated principals present, sets an automatic expiry after which the previous
version is restored unless the change has been merged, and posts to the deployment's notification
channel immediately. The emergency path is not blocked; it is made impossible to use invisibly.
Both epochs are signed at apply time. A policy version is a k-of-n co-signed artefact (EDR-0036), and an automatic reversion has no signers present — so the unreviewed-apply ceremony pre-signs both the change and its reversion, and the automatic step is the publication of an already-signed artefact rather than an unsignable act. Its two principals must therefore be approver-key holders. Without this the reversion either ships an unsigned artefact no Pilot accepts, or leaves Pilots enforcing the unreviewed policy while the control plane believes it reverted — the worst of both.
Reversion is an apply, not a restore. The automatic reversion runs the same validation as an ordinary apply, including the refusal rules above. If the previous version no longer validates — a group has since emptied, a target has gone — the reversion does not proceed: the unreviewed version is held in place and the deployment is alerted loudly. Silently restoring a policy that cannot be applied would be the worst of both outcomes. Notification goes out before expiry as well as at it, and both the attempted reversion and its outcome are recorded in the logbook — a reversion that did not happen is otherwise indistinguishable from one that did.
Consequences
Easier.
- Policy drift is visible in a history someone can read, and "who widened this, when, and who reviewed it" is answerable.
- Standing up a second deployment, or rebuilding after a loss, is applying the repository.
- Reviewers see an authority diff rather than JSON, so the review is about the consequence rather than the syntax.
Harder.
- Routine changes need a pull request, which is friction for small legitimate things. Delegation is the intended answer, and if people are opening pull requests for day-to-day access then delegation is under-used and that is the thing to fix.
- Two places to look — repository for policy, product for delegations — and someone will look in the wrong one. The console shows both on one screen, sourced from the journal, precisely so the effective answer is in a single place even though the inputs are not.
- The authority diff is real work to compute correctly, and a wrong summary is worse than no summary because it will be trusted.
- Break-glass with automatic reversion can revert a change that turned out to be needed. Loud notification and a generous window are the mitigation; it is a real trade.
New obligations.
- The repository holding policy is itself protected: required review, no self-merge, and its access is part of Marque's threat model rather than an assumption.
- Automatic reversion is tested. An untested reversion path will fail on the night it matters.
References
- ZFN-1 — decisions written down and cited.
- ZFN-47 — govern the contract centrally, and let teams operate within it.
- ZFN-37 — temporary authority expires by itself.
- EDR-0007 — the runtime half of authority.
Changelog
- 2026-08-15: Accepted.
- 2026-08-16: Amended after the expert panel's should-fix pass: added
max_grace_seconds,require_envelope(hardware oncriticalby default) andsurveyor.jurors, and specified break-glass reversion as an apply that can refuse rather than a silent restore. - 2026-08-16: Amended after a second expert panel: separated
signing_surfacefromrequire_envelope— conflating them had pushedcriticalapprovals into the browser, which is worse than the file-backed key it was guarding against — and made the applied policy version an anchored, co-signed artefact (EDR-0036). - 2026-08-16: Amended after the second panel's should-fix pass: split
require_key_backingfromrequire_envelope— the envelope was the wrong proxy, sincees256covers both a Secure Enclave key and the file fallback — and made atransformprovider on a target carrying standing orders a loud refusal at apply time. - 2026-08-16: Amended after the second panel's synthesis: break-glass now pre-signs both epochs, since an automatic reversion has no signers and cannot produce the k-of-n artefact EDR-0036 requires; added the per-target signing and presence fields.
- 2026-08-16: Amended for the emergency paths and operator surfaces: added
emergency_approvers,urgency_may_collapse_stages(default false) andmay_grant_unbounded_break_glass(EDR-0037). - 2026-08-16: Terminology and staleness fix: renamed the emergency policy-apply flag to
--unreviewed. Three different things were briefly called break-glass, which is how an operator reaches for the wrong one during an incident.