docs: offsite hardening bundle — hub README, REPORT, CONTEXT
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
@@ -2,32 +2,32 @@
|
||||
|
||||
> **Overwrite** this file with a summary of the most recent task only (uniform with the other repos; not cumulative). The cumulative hub history lives in [hub/CHANGELOG.md](hub/CHANGELOG.md); the scripts history lives in [scripts/CHANGELOG.md](scripts/CHANGELOG.md).
|
||||
|
||||
## RUNBOOK — offsite provisioning LIVE end-to-end (supervised) — 2026-07-09 — **PASS**
|
||||
## TASK — offsite provisioning hardening (F2/F4/F5 + key-auth-first + staged-secret wipe) — 2026-07-09 — DEPLOYED
|
||||
|
||||
**Full record:** `documentation/audits/VALIDATION-offsite-provisioning-e2e-2026-07-09.md`.
|
||||
**Shipped this run (felhom.eu):** manifest wiring `0a65f2b` (HETZNER_* env from Secret/storagebox),
|
||||
**hub v0.38.1** `7c70c54` + bump `6d5b3c1` (LIVE: Synced/Healthy, `Offsite provisioning enabled
|
||||
(pool_box=611714, location=fsn1)`). Pairs with controller v0.106.1 (that repo's REPORT).
|
||||
**Shipped (felhom.eu):** hub **v0.39.0** `17cc67f` + bump `17d9af5` — LIVE (Synced/Healthy, provisioner
|
||||
enabled). Bundle pairs: controller **v0.107.0** (key-auth-first bridge + wipe-on-escrowed; live on 9201) +
|
||||
agent **v0.78.0** (`DELETE /escrow/stage-secret`; live on felhom-pve, 56/56). All three green-gated with
|
||||
companion red-proofs.
|
||||
|
||||
The first live run of the SLICE 1+2 loop on `demo-felhom` against the new dedicated-project pool box:
|
||||
hub UI save → sub-account provisioned (269008, `u629488-sub1`) → non-secret descriptor + one-time password →
|
||||
controller config-refresh → apply-bridge (verify-pin, consume-once, pinned `ssh-copy-id`, offbox configured,
|
||||
`EscrowState=pending`) → fork-4 run-gate refusal proven → escrow confirm (Option A — the repo password was
|
||||
already escrowed under Viktor's R) → **first run: restic repo initialized, 2 apps, 2 snapshots on the new box,
|
||||
key-only** (independently verified by SFTP-listing the repo with the bridge-installed key + pinned host key).
|
||||
**Hub changes:**
|
||||
- **F4 (pilot-gating) — "Re-issue offsite credentials":** `Provisioner.ReissueCredentials` + UI button
|
||||
(confirm-gated, shown only when provisioned) + `POST /configs/{id}/offsite-reissue`. Resets the
|
||||
sub-account password (or dedicated-box password via the new `hetznerapi.ResetBoxPassword`), stores a
|
||||
FRESH one-time secret, re-saves the config unchanged → `ConfigVersion` bump → the stuck guest's next
|
||||
refresh re-runs the bridge. **Hard-scoped:** refuses unless the `felhom-customer=<id>` label lookup finds
|
||||
exactly 1 resource (red-proofed). Explicit action only — never implicit rotation. Password never logged.
|
||||
- **F2:** `scanWithRetry` — the host-key scan retries through fresh-subaccount DNS lag (2/4/8/16/30s ≈ 60s,
|
||||
inside the F1 3-min detached ctx; fail-closed past budget; red-proofed).
|
||||
- **F5:** the config form disables its submit buttons + shows an in-flight notice on submit (the re-click
|
||||
bait that caused live F1).
|
||||
|
||||
**Live bugs found + fixed mid-run:**
|
||||
- **F1 (hub v0.38.1):** a re-click canceled `r.Context()` between `CreateSubaccount` and
|
||||
`SaveOneTimeSecret` → sub-account stranded with its password lost. `applyOffsite` now provisions on
|
||||
`context.WithoutCancel` + 3-min timeout. Test `TestApplyOffsite_ClientDisconnectMidProvision` + red-proof
|
||||
(raw-ctx shape reproduces the exact live error).
|
||||
- **F3 (controller v0.106.1):** `ssh-copy-id -s` mktemp's under `~/.ssh`, absent from the container image —
|
||||
install died locally AFTER consuming the password (fail-safe held; password never transmitted).
|
||||
**One-off cleanup (executed):** the staged secret lingering on felhom-pve from the e2e's Option-A confirm
|
||||
was wiped through the NEW agent endpoint (controller container → pinned local API → `{"removed":true}`),
|
||||
verified gone; idempotent re-wipe returned `{"removed":false}`. No secret printed.
|
||||
|
||||
**Open findings:** F2 fresh-subaccount DNS lag → first-save scan 502 (retry-with-backoff wanted);
|
||||
F4 no hub password-reset path (recovery = delete sub-account + re-save); F5 no save spinner (the re-click
|
||||
bait); F6 Hetzner box-level 423 action lock on concurrent saves (fail-closed, correct).
|
||||
**Deliberately NOT exercised live:** the F4 reset itself (it would rotate the demo's working credential —
|
||||
touching it is forbidden; a live exercise needs a throwaway customer under supervision). Unit red-proofs
|
||||
cover the guards. F5 is template JS — verified on the next operator save.
|
||||
|
||||
**Standing state:** demo offsite now targets the NEW box, `escrowed`, un-paused; the old-box offsite
|
||||
(`u629193-sub1`) is a frozen archive until a NEW-box restore round-trip is verified.
|
||||
**NEXT:** SLICE 3 (escrow auto-confirm), SLICE 4 (soft-quota), F2/F4/F5, Peti/pilot onboarding runbook.
|
||||
**NEXT:** SLICE 3 (escrow auto-confirm — inherits wipe-on-escrowed), SLICE 4 (soft-quota on `quota_gb`),
|
||||
NEW-box restore round-trip → retire the old-box archive, Peti onboarding runbook.
|
||||
|
||||
Reference in New Issue
Block a user