Approval flows¶
Sensitive changes — custom policy publication, certain PKI operations, sometimes high-risk rollout configurations — require a four-eyes approval: a different operator must approve before the change goes live.
Where approvals are required¶
By default, approvals are required for:
- Custom policy publication. A policy draft must be approved by another Admin before it goes Active.
- Custom policy edits to an Active policy. Any edit that is not a metadata-only change reverts the policy to Draft and re-requires approval.
- Signing-key activation. Promoting a Draft signing key to Active is a tenant-wide event with broad blast radius; a second Admin must approve.
- Federation peer creation and edits. Adding or editing the trust relationship to another Ampora server is high-impact.
The list above is the default policy. Tenants can extend it via custom approval rules — see below.
How approval works¶
- Operator A creates or edits the entity (policy, signing key, federation peer).
- The entity sits in
PendingApproval. - Operator A is not allowed to approve their own change. Even if they have the role, the approve action is disabled with a "must be a different operator" tooltip.
- Operator B (a different operator with the relevant role) opens the entity, reviews the diff, and approves or rejects.
- On approval, the entity moves to its terminal state (Active, Live, etc.).
- On rejection, it returns to Draft with the rejection reason captured in audit.
Both A and B are recorded in the audit row, with the diff and the rejection / approval reason.
What "different operator" means¶
The check is on the user identity (OIDC sub claim), not on the role. Two Admins are still two Admins; the same Admin viewing under two browsers is still one Admin.
In multi-tenant deployments the check is also tenant-scoped — an Admin in tenant X cannot approve an action in tenant Y.
Editing during approval¶
If A edits a draft that is sitting in PendingApproval, the approval state is invalidated and the entity reverts to Draft. B's prior review on the older content is no longer authoritative; B (or another Admin) must review the new draft.
This is the right tradeoff: the alternative — letting an approval carry over to an edit — would let A get approval for X and then push Y.
Custom approval rules¶
Tenants can extend the default approval-required list via the same DSL as policies:
This makes any rollout targeting prod-eu require four-eyes — useful for environments where a senior operator must sign off on every production change. The rule is itself approved like a policy.
Audit trail¶
Every approval cycle produces multiple audit events:
Entity.DraftSaved— by A.Entity.ApprovalRequested— implicit on save; some integrations page operators on this.Entity.ApprovedorEntity.Rejected— by B, with reason.Entity.Activated(or equivalent terminal state) — implicit on approval.
Filter the audit log by the entity to see the full cycle in one view.
Bypassing approvals (dev only)¶
A development setting Approvals:RequireFourEyes=false lets a single operator approve their own work. Never enable this in production — it defeats the entire mechanism. The setting itself emits an audit event on every change; a deployment that turns it off is auditable even when its other audits are not.