diff --git a/REPORT.md b/REPORT.md index 4ec5e7b..278a434 100644 --- a/REPORT.md +++ b/REPORT.md @@ -4,79 +4,76 @@ --- -# REPORT — `felhom` pool as a Day-0 default (+ `--adopt-pool` retrofit + uninstall teardown) (host-install v1.5.0) +# REPORT — pool-scoped token ACL (3-role) + `--rescope-acl` retrofit (host-install v1.6.0) -**Date:** 2026-07-01 · **Repo:** `felhom.eu` (`scripts/` only) +**Date:** 2026-07-01 · **Repo:** `felhom.eu` (`scripts/` + `documentation/`) -Colleague-safety batch **#4 phase a**. Every Felhom-managed guest now joins a dedicated **`felhom` -pool** (fleet uniformity + the environment 3b will spike the pool-scoped ACL against). Script-only, all -pool ops run as `root@pam` from the installer → **NO agent/token/ACL change, zero permission risk** -(`PVE_PRIVS` untouched; the `FelhomAgent` token stays scoped at `/`). +Colleague-safety batch #4 phase b (script half; agent half = v0.53.0). Moves the agent token's dangerous +privileges off `/` to `/pool/felhom` + `/storage/`, so on a shared box the token can only touch +Felhom's own guests + storages. Implements `documentation/audits/SPIKE-pool-scoped-acl-2026-07-01.md` +(PASS) and live-migrated the demo host. -## 1. Confirmed baseline +## 1. Baseline → target -| Repo | `main` @ commit | Current | → Target | -|------|-----------------|---------|----------| -| felhom.eu (`scripts/felhom-host-install.sh`) | `6148e61` | script **v1.4.0** | **v1.5.0** | +script `v1.5.0` @ `554845b` → **v1.6.0**. Paired with agent v0.53.0 (separate repo). -PVE 9 `pveum pool` syntax + `/pools` JSON shape confirmed live before wiring: `pveum pool add -[--comment]` / `pool delete ` / `pool modify --vms ` (additive); `pvesh get /pools` → -`[{poolid,comment}]`, `pvesh get /pools/` → `{poolid,comment,members:[{vmid,type,status,…}]}`. +## 2. Files changed + commits -## 2. Files changed + commit +- `scripts/felhom-host-install.sh` (v1.5.0 → **v1.6.0**), `scripts/CHANGELOG.md` — commit **`741f322`**. +- `documentation/audits/SPIKE-pool-scoped-acl-2026-07-01.md` — status → IMPLEMENTED (this commit). +- `REPORT.md` — this file. -- `scripts/felhom-host-install.sh` (v1.4.0 → **v1.5.0**) — the only code file. -- `scripts/CHANGELOG.md` — v1.5.0 entry. -- `REPORT.md` — this file (overwritten). -- Commit **`482dbec`** on `main` (parent `6148e61`). +## 3. What shipped -## 3. What was implemented +- **3-role scoped ACL** (`step_token` rewrite): `FelhomAgentGuest` (`VM.*`+`Pool.Allocate`)@/pool/felhom, + `FelhomAgentStore` (`Datastore.*`)@each `PVE_STORAGES` (default `local local-lvm felhom-pbs`; + `--acl-storages` overrides), `FelhomAgentBase` (`Sys.Audit SDN.Use`)@/ — each to BOTH user + token. + Pool ensured before the grants; the pre-3b broad `/` grant+role removed if present. +- **`--rescope-acl`** retrofit mode (add-before-remove; supervised). **`--uninstall`** removes both the + scoped and the old shapes. Post-provision `pool_add_guest` dropped (agent `restore --pool` owns it). +- `bash -n` + `shellcheck` clean (0 new warnings; the 2 pre-existing SC2015 in `step_verify` unchanged). -- **Part 1 — pool default:** const `PVE_POOL="felhom"`; helpers `pool_exists` / `pool_members` - (`.members[].vmid`) / `ensure_felhom_pool` / `pool_add_guest` (skip-if-member). `step_provision` - ensures the pool then adds the guest after a successful provision (dry-run prints both). -- **Part 2 — `--adopt-pool`:** early root-only dispatch + `run_adopt_pool` — resolves the vmid - (`--vmid` else recorded `provisioned_vmid`), requires the guest to exist, ours-checks the - `/etc/felhom-bootstrap` mount (refuse non-Felhom unless `--force`), ensures the pool, adds the guest. - Membership-only; never reconfigures/restarts the guest; no hub contact. -- **Part 3 — uninstall teardown (step 5b):** after the pveum removal, `pveum pool delete felhom` **only - if empty**; otherwise `log_skip` naming the members. Summary line notes the pool when removed. Not - reached on the Spec-1 safe-skip path. -- Usage header gains a "Retrofit" group; every pool mutation goes through `run()` (dry-run-aware). - -## 4. Green gate - -- `bash -n scripts/felhom-host-install.sh` → OK (local + felhom-pve). -- `shellcheck v0.10.0` → **2× SC2015 (info)** at lines 1286 & 1296, both the *pre-existing* `step_verify` - `A && B || C` lines. **0 new warnings.** - -## 5. Tests → §7 mapping (felhom-pve; dry-run + SAFE live) +## 4. Tests → §7 | # | Scenario | Result | |---|----------|--------| -| T-A | fresh install (dry-run) | **PASS** — `--customer-id demo-felhom --vmid 9300 --dry-run` at step 8/8 prints `[DRY-RUN] pveum pool add felhom --comment Felhom-managed guests` + `[DRY-RUN] add guest 9300 to pool felhom`. | -| T-B | **live adopt of 9201** | **PASS** — `--adopt-pool --vmid 9201` → ours-check passes, `guest 9201 added to pool felhom`. `pvesh get /pools/felhom` → `members:[{…,"vmid":9201,"status":"running","type":"lxc"}]`; **9201 still `running`, config unchanged** (membership-only). The demo node is now pool-uniform. | -| T-D | idempotency | **PASS** — re-run `--adopt-pool --vmid 9201` → `[SKIP] pool felhom already exists` + `[SKIP] guest 9201 already in pool felhom` (no-op). | -| T-B' | ours red-proof | **PASS** — `--adopt-pool --vmid 9001` (no bootstrap mount) → `die` "does not look like a Felhom-provisioned guest … Refusing to adopt. Pass --force", exit 1, pool membership unchanged. | -| T-C | uninstall empty-guard | **PASS** — `--uninstall --vmid 9201 --dry-run` → `[SKIP] pool felhom not empty (members: 9201) — leaving it` (guest not destroyed in dry-run, so the pool retains 9201 → the delete-only-if-empty guard is proven). | +| T-A | fresh install (dry-run) | ✅ pool-before-token; 3 roles created once; scoped grants incl. `/storage/felhom-pbs` (transcript) | +| T-E | `--rescope-acl` (dry-run + LIVE) | ✅ dry-run shows add-scoped→remove-old; **live-run on felhom-pve** applied it | +| T-F | `--uninstall` (dry-run) | ✅ removes old-shape `FelhomAgent` grant+role (scoped tolerated-absent), pool not-empty skip | +| T-B/C/D | provision-into-pool / PBS / restore-test under scope | ✅ **live** (see §6) | +| T-D-neg | blast-radius | ✅ **live** 403 on non-pool guests + ungranted storage | -## 6. Served-copy version +## 5. Served script version -``` -curl -fsSL https://felhom.eu/scripts/felhom-host-install.sh | grep SCRIPT_VERSION -``` -→ **`SCRIPT_VERSION="1.5.0"`** (confirmed ~1 min after push). +`curl -fsSL https://felhom.eu/scripts/felhom-host-install.sh | grep SCRIPT_VERSION` → **`1.6.0`**. -## 7. NOT yet live-validated — awaiting supervised run +## 6. Supervised swap on felhom-pve — executed + ALL gates PASS -- A live **`--uninstall`** (now also deletes the pool when empty) — the destroy path remains the - supervised STOP carried over from Spec 1; the pool-delete-if-empty branch is proven only in dry-run. +`stop felhom-agent` → `--rescope-acl --vmid 9201` (added the 3 scoped roles+grants; removed the old +broad `FelhomAgent` `/` grant+role) → deploy agent v0.53.0 → `start`. Then, all under the scoped token: +selftest=read OK (now sees only the pool guest + 3 scoped storages); **provision-into-pool** of scratch +9300 (boot+running, in pool); **PBS backup→felhom-pbs + restore-from-PBS→9301** (both 200/OK — residual +#1); **restore-test** scratch into pool (pass — residual #2); **blast-radius 403** on non-pool guests +9001/9100 + ungranted storage felhom-usb; 9201 running + controller healthy + hub link OK. All scratch +cleaned up; `.bak-0.52.0` rollback binary retained; pool = `[9201]`. Details in `felhom-agent/REPORT.md`. -## 8. Observations (for 3b, not acted on) +## 7. REQUIRED operator follow-up (fresh installs) -- **`/pools` API shape confirmed for 3b:** list = `[{poolid,comment}]`; detail = `{members:[{vmid,type, - status,node,…}]}`. `pveum pool modify --vms ` is additive (a `--delete 1` variant removes; - `--allow-move` if a guest is already in another pool). -- 3b (the actual permission change) will add a `/pool/felhom`-scoped ACL + `Pool.Allocate` and make the - agent restore INTO the pool under a scoped token — deliberately NOT attempted here (spike-gated). -- The demo `felhom` pool now exists with 9201 as its member — a ready environment for the 3b spike. +The served **hub artifact manifest still advertises agent 0.52.0**. A fresh v1.6.0 install (scoped ACL) +is only correct with agent ≥ v0.53.0 (restore `--pool`) — with 0.52.0 the guest restores OUTSIDE the pool +and the scoped token 403s on it. **An operator must set the manifest to agent 0.53.0 / sha +`9d1ef8298dcc5090936afa1b88f1612c0b5f03a62548ebbe0989d34d6622aa61`** in the hub UI (dropdown, auto-sha — +hub v0.29.0). Agent 0.53.0 is already published to Gitea. The demo swap didn't depend on this (binary +deployed directly). + +## 8. NOT yet live-validated — awaiting supervised run + +- The **colleague's-box migration** (single-node; a later supervised repeat of §6 once the manifest + serves 0.53.0). + +## 9. Observations + +- Multi-node: pools + ACLs are cluster-wide in PVE; felhom-pve is single-node so the restore-targets-a- + node behaviour under a `/pool/felhom` grant is unverified on a cluster (node is in the URL, not the + ACL path — expected fine; verify on the colleague's box if it's a cluster). +- Colleague-safety batch is now COMPLETE through #4 (uninstall, CPU/mem cap, pool-default, pool-scoped ACL). diff --git a/documentation/audits/SPIKE-pool-scoped-acl-2026-07-01.md b/documentation/audits/SPIKE-pool-scoped-acl-2026-07-01.md index 5d4b2da..04e4f9e 100644 --- a/documentation/audits/SPIKE-pool-scoped-acl-2026-07-01.md +++ b/documentation/audits/SPIKE-pool-scoped-acl-2026-07-01.md @@ -1,5 +1,12 @@ # SPIKE — pool-scoped ACL for the FelhomAgent token (2026-07-01) +> **STATUS: IMPLEMENTED** in agent **v0.53.0** (`RestoreLXCOptions.Pool` / `reconcile.DefaultPool`, both +> restore sites) + host-install script **v1.6.0** (3-role scoped ACL, `--rescope-acl`, uninstall +> cleanup). The demo host felhom-pve was live-migrated (agent stopped → `--rescope-acl` → agent v0.53.0 +> → start) and ALL residual gates passed under the scoped token: **PBS backup+restore (residual #1)** +> and **restore-test into pool (residual #2)** both succeed; blast-radius 403 confirmed on out-of-pool +> guests + ungranted storage. See the felhom.eu + felhom-agent REPORTs. + **Class:** SPIKE (empirical validation; no product code). **Repos read:** felhom-agent `33e3443` (v0.52.0, read-only). **Host:** felhom-pve (192.168.0.162, node `demo-felhom`, PVE 9.2.2, **single-node**). **Verdict: PASS** — the agent's 16 privileges CAN be scoped from `/` to `/pool/felhom` +