Operations: Scanner CA Rollover
An evaluator-facing overview of how mipo rotates the CA that signs scanner client certificates, with no scanner ever losing the ability to authenticate. This is not the operational procedure.
Operators: use the runbook in your release bundle
The step-by-step procedure, every verb with its real flags, and the recovery paths ship with every
mipo release at docs/operations/scanner-ca-rollover.md, alongside the incident runbooks
ops/runbooks/scanner-ca-rollover-stall.md, ops/runbooks/scanner-ca-rollover-failed.md
and ops/runbooks/scanner-ca-emergency-transition.md. Follow those instead of this page.
The rollover flow
There is no GUI for a rollover. The manager's background driver executes the state machine one phase at a
time (a tick every 5 seconds); operators observe and gate it with runRolloverCli.js inside the
manager container or the admin API (/api/config/scanner-mtls/rollover, step-up gated; starting one
requires the body literal confirm: 'rollover-ca'). At most
one rollover is non-terminal at a time, and a non-terminal rollover also blocks the fleet policy flip to
required.
- Stage generation N+1 (start --operation-id <id>). Abandonable until the next step.
- Widen the served trust bundle to N and N+1 — DB revision (dual_bundle_db_active), watchdog publish (dual_bundle_published), dedicated mTLS Traefik reload (dual_bundle_reloaded), real handshake (dual_served_verified). From here the rollover is forward-only.
- Re-issue every scanner and resolver identity a leaf signed by N+1 (n1_issuing) and wait until each scanner and resolver has actually presented it (fleet_reissued). Usually the longest phase; an unreachable scanner stalls it.
- Narrow the bundle to N+1 only — single_bundle_db_active, single_bundle_published, single_bundle_reloaded, single_served_verified. The driver stops here.
- An operator confirms the drop (confirm-drop, echoing the revision and snapshot digest from status). The driver destroys N’s private key on a later tick (n_destroyed).
Terminal phases are n_destroyed, emergency_n_destroyed and abandoned.
Every bundle transition is four separate phases (*_db_active, *_published,
*_reloaded, *_served_verified) because each can fail and is retried independently.
The emergency path (emergency_quarantined onward) never serves a dual bundle and needs no
confirmation: the compromised key is destroyed as soon as the replacement is served-verified and the fleet
re-issued.
The verbs
start --operation-id <id>— Record intent; first advance to n1_staged.status [--operation-id <id>]— Phase, blockers, and the drop-confirmation preview.advance / run --until <phase> [--timeout-ms N]— Operator path when the background driver is unhealthy: one phase, or up to a named phase.confirm-drop --operation-id <id> --single-bundle-revision <int> --snapshot-digest <hex> --actor-user-id <int> --actor-ip <ip>— Authorize the destruction of N. Deferred to a later driver tick; irreversible once done.abandon --operation-id <id> --reason <text>— Legal only from idle or n1_staged.emergency --compromised-generation <int> [--operation-id <id>]— CA compromise: quarantine + revoke first, no dual overlap, forced re-issue, destroy. No confirmation step.reconcile-bundles [--watchdog-deadline-ms N] / verify-bundles [--require-proof-receipt N]— Republish the DB’s active bundle to the served bundle and record a proof receipt; read-only verification (both run by restore.sh).
Two irreversible edges
Forward-only after the dual bundle. abandon is legal only from idle or
n1_staged; once dual_bundle_db_active is reached the runtime already trusts the staged CA
and the only way out is to finish the single-bundle phases.
Destruction is deferred and final. confirm-drop records the operator's
authorization against a persisted readiness snapshot; the driver wipes generation N on a later tick, and a
scanner still holding only an N leaf after that must be re-enrolled.
Alarms and runbooks
scanner-ca-rollover-stall— no phase advance and no blocker change for the stall window →ops/runbooks/scanner-ca-rollover-stall.mdscanner-ca-rollover-failed— a step of an orderly rollover threw →ops/runbooks/scanner-ca-rollover-failed.mdscanner-ca-emergency-transition-failed— a step of the emergency transition threw →ops/runbooks/scanner-ca-emergency-transition.mdscanner-certificate-expiry— a scanner leaf is close to expiry (renewal failing) →check the scanner host and status blockers
Scanners: provisioning, enrollment, fleet policy → Alarm rules Scanner install