RECON: trace the offsite DR chain link by link — it does not join up (R-198..R-201)
gates / gates (push) Successful in 7s
gates / gates (push) Successful in 7s
Read-only recon of the escrow -> recovery chain, from a dead node to an open
repository. No production code, no build, no version bump.
Headline: the hub's superseded-escrow retention does NOT retain the offsite
repository password. host_escrow_superseded has no identity_blob column and
demoteCurrentEscrowTx copies only the K-escrow blob, so what survives a
supersession is the PBS datastore key, not the restic repo password. The next
escrow ceremony -- which the system tells a rebuilt box's customer to run --
destroys the last copy. Both demo boxes crossed that line on 2026-08-04.
Also established:
- the hub's blob-serving endpoints (re-enroll / restore-directive) have zero
callers anywhere: agent, hub UI, scripts, runbooks (R-199)
- POST /backup/offbox/inject-password is routed and handled but no template
contains the form (R-200)
- nothing in the recovery path has ever been exercised; the one live
round-trip proof (2026-06-10) predates the ResticRepoPassword field (R-201)
- a fail-closed mint refusal IS implementable: the report ACK already carries
escrow{identity_blob_present, restic_pw_sha256} and the controller discards
it whenever no offbox target exists
Corrections: yesterday's spike annotated (candidate (b) overturned in part --
unattended recovery is impossible, customer-present is not); capability-map
retention claim struck through and replaced with what the code does.
Deliverable: documentation/audits/RECON-offsite-dr-chain-2026-08-04.md
Register: new R-198..R-201; R-193 and R-192 updated; STATUS.md refreshed.
This commit is contained in:
@@ -10,6 +10,39 @@ what it measured) · **Class:** spike — **no production code shipped for R-193
|
||||
|
||||
---
|
||||
|
||||
> ### ANNOTATION 2026-08-04 (later the same day) — read this before acting on §Q8
|
||||
>
|
||||
> A follow-up recon traced the escrow→recovery chain link by link
|
||||
> (`audits/RECON-offsite-dr-chain-2026-08-04.md`). **Two corrections to this document, and they pull
|
||||
> in opposite directions.**
|
||||
>
|
||||
> **(1) Q8 candidate (b) — "not implementable as specified" — is TOO STRONG and is overturned in
|
||||
> part.** Zero-knowledge means the *hub* cannot open the blob; the *customer* can, with R, which is
|
||||
> what the ceremony exists for. The mechanism to hand a rebuilt box its old repo password back —
|
||||
> customer-present, not unattended — is a real design, and the operator has since ruled on its shape.
|
||||
> What (b) got right is narrower than what it said: **an UNATTENDED rebuild cannot recover from a
|
||||
> zero-knowledge escrow.** A customer-present one can. The recon prices that shape row by row.
|
||||
>
|
||||
> **(2) A LOAD-BEARING FACT THIS SPIKE DID NOT CHECK, and it makes (d)-alone weaker than ranked
|
||||
> here.** `host_escrow_superseded` **has no `identity_blob` column**, and `demoteCurrentEscrowTx`
|
||||
> (`hub/internal/store/store.go:2547-2556`) copies only the K-escrow `blob`. So the retained
|
||||
> "superseded" blob holds the **PBS datastore key**, not the **restic repository password**. The
|
||||
> retention feature does not retain the secret it was built to retain, and the **next escrow ceremony
|
||||
> — which the system tells the customer to run whenever a rebuild leaves the escrow `pending` — is
|
||||
> what destroys the last copy.** Both demo boxes crossed that line on 2026-08-04 at 07:15:36 and
|
||||
> 07:20:08. → **R-198**.
|
||||
>
|
||||
> **Consequence for this document's recommendation.** "Ship (d), then decide (c)" still holds, but
|
||||
> (d)'s implicit promise — *the old history stays recoverable with the recovery code* — is **false as
|
||||
> the code stands**, and is repeated verbatim to the customer in Hungarian on the orphan card. (d) is
|
||||
> not complete without R-198.
|
||||
>
|
||||
> **Unchanged and still correct:** Q1, Q2, Q4 (R-196), Q5, Q6, Q7 (R-192) and the Q8 (a)/(c)/(d)
|
||||
> analyses. **Q3 remains UNMEASURED** — neither box has run since; the 2026-08-05 ~02:15 UTC run is
|
||||
> still the decisive one.
|
||||
|
||||
---
|
||||
|
||||
## 0. Why this exists
|
||||
|
||||
Two candidate fixes were named when R-193 was filed, and neither could be weighed, because two prior
|
||||
@@ -412,6 +445,12 @@ re-keyed, `host_leaf_changed` 2026-08-03 06:09:40), so re-enroll returns the exi
|
||||
|
||||
### (b) The credential becomes recoverable from escrow at re-bootstrap
|
||||
|
||||
> **ANNOTATED 2026-08-04 (recon) — this ruling is overturned in part. See the annotation at the top.**
|
||||
> The constraint is real but narrower than written: an **unattended** rebuild cannot recover from a
|
||||
> zero-knowledge escrow; a **customer-present** one can, and the operator has ruled on that shape.
|
||||
> The recon also found that the chain this option would use is clientless at three links and lossy at
|
||||
> a fourth (`RECON-offsite-dr-chain-2026-08-04.md` §3–§4).
|
||||
|
||||
- **BLOCKED AS STATED, and this is a hard constraint, not an estimate.** The escrow blob is
|
||||
**R-wrapped and zero-knowledge** — the hub holds opaque bytes and has no recovery code
|
||||
(`api/handler.go`, and D6 in `CONTEXT.md` S-3). **A rebuilt box cannot unseal it without the
|
||||
|
||||
Reference in New Issue
Block a user