pbs: namespace-aware client for per-customer offsite tenancy (S4)

Phase-1 live probe (felhom-hetzner) proved backup/restore/list/isolation over
the tunnel with a per-customer DatastoreBackup token, but the agent's PBS client
was namespace-unaware: Snapshots hit the datastore root (403 for a scoped token)
and Verify was whole-datastore (needs Datastore.Verify ~ admin). Operator-
approved fix.

- pbs.Config.Namespace + Client.namespace; Snapshots appends ?ns=; Verify sends
  ns= (ns-scoped verify works with DatastoreBackup on the own ns — no admin
  widening, Phase-1 confirmed). Root-ns clients unchanged (whole-datastore).
- proxmox.Storage.Namespace (parsed from /storage `namespace`).
- pbsTargetsFromPVE threads s.Namespace into the client.

Confirmed tenant ACL: DatastoreBackup on /datastore/felhom-offsite/<ns> (NOT
/ns/<ns>) to BOTH felhom@pbs (user) AND felhom@pbs!<ns> (token) — PBS privsep =
intersection; isolation holds (cross-ns 403 proven). TestClient_NamespaceScoping
red-proofed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
2026-07-04 16:12:15 +02:00
parent 734f45c422
commit 027948bf3f
5 changed files with 105 additions and 7 deletions
+23
View File
@@ -1,3 +1,26 @@
## v0.67.0 — S4: namespace-aware PBS client (per-customer offsite tenancy) (2026-07-04)
Phase-1 live probe on felhom-hetzner proved the offsite tenancy path (backup/restore/list/isolation
all green over the tunnel with a per-customer DatastoreBackup token) but surfaced that the agent's
PBS client was **namespace-unaware**: `Snapshots` hit the datastore root (403 for a scoped token)
and `Verify` was whole-datastore (needs Datastore.Verify ~ admin). Operator-approved small change to
make the client namespace-scoped so a properly-isolated token services its own tenant.
- **`internal/pbs`**: `Config.Namespace` (+ `Client.namespace`). `Snapshots` appends `?ns=<ns>`
(lists ONLY the tenant's namespace); `Verify` sends `ns=<ns>` (verifies ONLY that namespace —
Phase-1-confirmed to work with a **DatastoreBackup** token on its own ns, no Datastore.Verify /
admin widening). Root-ns clients (Namespace="") are unchanged → whole-datastore (the DooPlex
`felhom-pbs` n100 path). Test `TestClient_NamespaceScoping` pins both (red-proofed).
- **`internal/proxmox`**: `Storage.Namespace` (parsed from the PVE `/storage` config key `namespace`).
- **`cmd/felhom-agent`**: `pbsTargetsFromPVE` threads `s.Namespace` into the PBS client, so a PBS
storage configured with a namespace is verified/reported scoped to it automatically.
**Confirmed minimal tenant ACL (recorded live 2026-07-04, felhom-hetzner):** `DatastoreBackup` on
`/datastore/felhom-offsite/<ns>` (the namespace path — NOT `/ns/<ns>`) granted to **BOTH** the user
`felhom@pbs` **and** the token `felhom@pbs!<ns>` — PBS privsep tokens = intersection(user, token),
so both are required; isolation holds because each token's ACL is only its own ns (cross-ns
list/backup → 403, proven). No token exceeds DatastoreBackup; no admin on the endpoint for the box.
## v0.66.0 — S4 agent half: endpoint v4-pin + re-resolve watchdog + FELHOM_WG Critical flips (2026-07-04)
The two agent items S4 needs before offsite backups ride the tunnel (the tenancy + storage weight is