Files
felhom.eu/REPORT.md
T
admin 7eb3772000 hub: opaque PBS recovery-code escrow storage (v0.8.0) + doc 03 §8a posture model
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>
2026-06-10 07:46:33 +02:00

55 lines
3.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.