diff --git a/scripts/CHANGELOG.md b/scripts/CHANGELOG.md index 5c07639..7eb3954 100644 --- a/scripts/CHANGELOG.md +++ b/scripts/CHANGELOG.md @@ -1,5 +1,33 @@ # Felhom scripts — Changelog +## felhom-host-install.sh v1.7.0 — 3b-fix: `Datastore.Audit` box-wide (restore drive visibility) (2026-07-01) + +Fixes a regression the v1.6.0 pool-scoped ACL introduced: `Datastore.Audit` was placed in the +per-storage `Store` role (granted only on `local`/`local-lvm`/`felhom-pbs`), which **excluded the +enrolled removable drives** `felhom-usb`/`felhom-flash`. The agent enumerates storage via +`ListStorage`/`NodeStorage` (both gated by `Datastore.Audit` — `internal/storage/observe.go`), so it +could no longer SEE the drives → false "Meghajtó leválasztva" (drive detached) alerts + drives absent +from the agent-view. (The v1.6.0 swap's "felhom-usb → 403" was mis-read as blast-radius success; +felhom-usb is Felhom's OWN customer drive, not an out-of-scope object.) + +- **`Datastore.Audit` moved from Store → Base** (`PVE_PRIVS_BASE` now `"Sys.Audit SDN.Use + Datastore.Audit"`; `PVE_PRIVS_STORE` now `"Datastore.Allocate Datastore.AllocateSpace"`). Audit is + read-only metadata, so box-wide Audit restores visibility of ALL storages (incl. dynamically-enrolled + drives — no per-drive grant ever needed) while the **write** privs (`Allocate`/`AllocateSpace`) stay + per-storage → write/allocate blast-radius containment is UNCHANGED. Confirmed at source: the agent + creates no PVE storage (no `POST /storage`/`pvesm add`); drives are dir-storages it observes + mounts + via host ops, so they need only Audit, never Allocate. +- **`apply_scoped_acl` reordered** Base-before-Store (role + grant) so a RE-APPLY on a live box adds + `Audit@/` before Store drops its per-storage Audit → gap-free (the agent never loses enumeration). +- `remove_scoped_acl` / `--uninstall` / `--rescope-acl` operate by role NAME and inherit the corrected + privs automatically (no other change). +- **Live-repaired felhom-pve** (two `pveum role modify`, Base first — no agent stop/restart): drives + reappeared (agent-view 3→5 storages), detach alerts cleared. Re-tested under the scoped token: drives + readable (was 403), write-containment intact (vzdump→felhom-usb still 403; out-of-pool guest 403), + PBS Store grant unchanged. `bash -n` + `shellcheck` clean (0 new warnings). +- **NOT physically run** (source-confirmed, no `Datastore.Allocate` in the path): a brand-new-drive UI + enrollment (needs a spare USB) — the host-ops/Audit path is unchanged from pre-3b. + ## felhom-host-install.sh v1.6.0 — pool-scoped token ACL (3-role) + `--rescope-acl` retrofit (2026-07-01) Colleague-safety batch #4 phase b (script half; agent half = v0.53.0). Moves the agent token's dangerous diff --git a/scripts/felhom-host-install.sh b/scripts/felhom-host-install.sh index 9779767..69dc7ed 100644 --- a/scripts/felhom-host-install.sh +++ b/scripts/felhom-host-install.sh @@ -1,6 +1,6 @@ #!/bin/bash #=============================================================================== -# felhom-host-install.sh v1.6.0 +# felhom-host-install.sh v1.7.0 # Day-0 host-bootstrap for a Felhom Proxmox host (operator-deploy model). # # Run by the operator on a FRESHLY-PVE-INSTALLED box (after a manual PVE install @@ -104,7 +104,7 @@ set -euo pipefail -SCRIPT_VERSION="1.6.0" +SCRIPT_VERSION="1.7.0" #------------------------------------------------------------------------------- # Logging (mirrors felhom-controller/scripts/docker-setup.sh) @@ -172,14 +172,17 @@ PVE_ROLE="FelhomAgent" # the PRE-3b single broad role (removed on rescope/unin # across THREE roles applied at scoped paths so the token can only touch Felhom's own guests + storages # (blast-radius containment). `pveum acl` grants a whole role per path, hence 3 roles not 1. Each role is # granted to BOTH the user AND the token (privsep intersection). Guest privs (incl. Pool.Allocate so the -# agent restores INTO the pool) live at /pool/felhom; Datastore privs at each agent-touched storage; only -# Sys.Audit+SDN.Use box-wide at /. +# agent restores INTO the pool) live at /pool/felhom; Datastore WRITE privs at each agent-touched storage. +# `Datastore.Audit` is box-wide in Base (3b-fix v1.7.0): the agent must ENUMERATE every storage incl. the +# dynamically-enrolled removable drives (felhom-usb/felhom-flash) it observes but never registers — a +# per-storage Audit grant hid them → false "drive detached" alerts. Audit is read-only, so box-wide Audit +# keeps WRITE containment (Allocate/AllocateSpace stay per-storage). Only Sys.Audit/SDN.Use/Datastore.Audit box-wide. PVE_ROLE_GUEST="FelhomAgentGuest" PVE_ROLE_STORE="FelhomAgentStore" PVE_ROLE_BASE="FelhomAgentBase" PVE_PRIVS_GUEST="VM.Allocate VM.Audit VM.Config.Disk VM.Config.CPU VM.Config.Memory VM.Config.Network VM.Config.Options VM.PowerMgmt VM.Snapshot VM.Snapshot.Rollback VM.Backup Pool.Allocate" -PVE_PRIVS_STORE="Datastore.Allocate Datastore.AllocateSpace Datastore.Audit" -PVE_PRIVS_BASE="Sys.Audit SDN.Use" +PVE_PRIVS_STORE="Datastore.Allocate Datastore.AllocateSpace" +PVE_PRIVS_BASE="Sys.Audit SDN.Use Datastore.Audit" # Storages the agent reads/writes (archive+dump=local, restore=local-lvm, offsite DR=felhom-pbs). The # offsite felhom-pbs MUST be included or the agent's DR backup 403s (SPIKE residual #1). --acl-storages overrides. PVE_STORAGES=(local local-lvm felhom-pbs) @@ -406,17 +409,20 @@ _grant() { } # apply_scoped_acl — create the 3 scoped roles and grant each at its path(s). Requires the pool to exist. +# ORDER (3b-fix): Base (which holds box-wide Datastore.Audit) is ensured + granted BEFORE Store, so a +# RE-APPLY on a live box adds Audit@/ before Store drops its per-storage Audit → the agent never loses +# storage-enumeration visibility mid-apply (gap-free). apply_scoped_acl() { + _ensure_role "$PVE_ROLE_BASE" "$PVE_PRIVS_BASE" _ensure_role "$PVE_ROLE_GUEST" "$PVE_PRIVS_GUEST" _ensure_role "$PVE_ROLE_STORE" "$PVE_PRIVS_STORE" - _ensure_role "$PVE_ROLE_BASE" "$PVE_PRIVS_BASE" + _grant / "$PVE_ROLE_BASE" _grant "/pool/$PVE_POOL" "$PVE_ROLE_GUEST" local s for s in "${PVE_STORAGES[@]}"; do _grant "/storage/$s" "$PVE_ROLE_STORE" done - _grant / "$PVE_ROLE_BASE" - log_success " scoped ACL applied (Guest@/pool/$PVE_POOL, Store@[${PVE_STORAGES[*]}], Base@/)" + log_success " scoped ACL applied (Base@/, Guest@/pool/$PVE_POOL, Store@[${PVE_STORAGES[*]}])" } # _acl_grant_present PATH TYPE UGID ROLE — true if that exact ACL grant exists.