7eb3772000
Slice-7 close-out (hub half). PUT /api/v1/hosts/{host_id}/escrow (per-host key)
stores the agent's OPAQUE R-wrapped blob verbatim against the host; the hub never
decrypts it (no recovery code, no decrypt path). host_escrow table + Save/GetHostEscrow.
Tests: verbatim store, rotation last-write-wins, 401/403/400 auth+body, wire contract.
doc 03 §8a rewritten into the key-custody posture model: separation principle,
topology matrix, default + anti-lockout ladder, SSH-vs-key, breach/legal, integrity
caveat. Corrected: hub opaque storage is slice 7 (this task); serving is slice 10.
Slice table + §13 updated.
No secrets committed (R/K never appear; spike findings + docs use placeholders).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
55 lines
3.1 KiB
Markdown
55 lines
3.1 KiB
Markdown
# felhom.eu — task reports
|
||
|
||
> **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).
|
||
|
||
---
|
||
|
||
# REPORT — Slice 7 close-out: PBS escrow — hub opaque storage + doc 03 §8a (v0.8.0) (2026-06-10)
|
||
|
||
## Outcome
|
||
|
||
The `felhom.eu` half of `TASK — Slice 7 close-out: PBS recovery-code escrow`. The agent
|
||
(felhom-agent v0.9.0) creates an **opaque** `R`-wrapped copy of the PBS key in the zero-knowledge
|
||
default; this slice adds the **hub opaque storage** for that blob and rewrites **doc 03 §8a** into a
|
||
full key-custody posture model. The wrap→recover→restore round-trip was proven on a throwaway first
|
||
(`documentation/tests/slice7-escrow-spike-findings.md`).
|
||
|
||
## What landed (hub v0.8.0)
|
||
|
||
- **`PUT /api/v1/hosts/{host_id}/escrow`** (`internal/api/handler.go`) — per-host-key authed (a host
|
||
writes only its own escrow; global operator key also accepted). Decodes the base64 blob and stores
|
||
the **opaque bytes verbatim** against the host. The hub **never decrypts** — there is no decrypt
|
||
path; it has no recovery code. Rotation is last-write-wins.
|
||
- **`host_escrow`** table + `SaveHostEscrow`/`GetHostEscrow` (`internal/store`). Blob is ciphertext.
|
||
- **Contract:** `escrowUploadRequest` mirrors the agent's emit struct (`blob_b64`, `key_fingerprint`,
|
||
`posture`, `created_at`); a key-set test in each repo guards drift.
|
||
- **Tests:** stores the blob byte-identical; rotation last-write-wins; 401 (absent/wrong key), 403
|
||
(host writing another host's escrow), 400 (bad base64); contract key-set. `go test ./...` green.
|
||
|
||
## Documentation (doc 03 §8a)
|
||
|
||
Rewrote §8a into the **key-custody posture model**: the **separation principle** (reading data needs
|
||
both chunks *and* a key; zero-knowledge holds while Felhom never holds both), the **topology matrix**
|
||
(data location × key custody → who can read; the one dangerous cell flagged), the **default**
|
||
(Felhom storage + customer-only key; `R` printed durably), the **anti-lockout ladder** ((b) wrapped
|
||
offline copy → (a) raw paperkey → Felhom-holds-a-key), **SSH-for-support is a separate grant** (not
|
||
coupled to key custody), **why zero-knowledge stays default** (breach + legal compellability), and
|
||
the **integrity caveat** for self-hosted-data postures. Corrected the storage-slice note: hub opaque
|
||
storage is **slice 7** (this task); only restore-mode **serving** is slice 10. §9 slice table + §13
|
||
updated.
|
||
|
||
## Live validation
|
||
|
||
After the v0.8.0 deploy, the demo agent's `--selftest=escrow-create -upload` PUT the opaque blob and
|
||
the hub stored it against the host; the stored bytes are **ciphertext** (not the key). The recovery
|
||
code `R` is never sent to or stored by the hub. *(No `R`/`K` value appears in any committed file.)*
|
||
|
||
## Deferred / security
|
||
|
||
Restore-mode serving + consumption → slice 10. The hub holds ciphertext only — possessing the blob
|
||
does not let Felhom read customer data (separation principle). No secrets committed.
|
||
|
||
## Deploy (GitOps)
|
||
|
||
Build+push `felhom-hub:v0.8.0` → bump `manifests/hub.yaml` → commit → sync the `felhom` ArgoCD app.
|