sudoers: close non-root allowlist gaps (lxc-info, make-private, restart dnsmasq, pct reboot/onboot) — restores multi-drive

Root cause of multi-drive flapping: lxc-info absent from the allowlist → empty guest
PID → bound_under_parent=false for every drive → controller gate stops apps. Audit-driven
completeness pass; surfaces GuestExec/pct-exec (controller-swap) for operator decision.
No binary change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EPZ4GJ8L5Jqf8UiPwbn1kt
This commit is contained in:
2026-06-29 15:58:41 +02:00
parent c3020ee3a8
commit 55888e5686
2 changed files with 46 additions and 2 deletions
+34
View File
@@ -3,6 +3,40 @@
All notable changes to **felhom-agent** are recorded here. Update on every code
change that gets pushed.
## (unreleased) — sudoers completeness audit: close non-root allowlist gaps (no binary change) (2026-06-29)
A full audit of every privileged command the agent shells via `sudo -n` against
`configs/felhom-agent.sudoers`, closing the read-only/fixed-vector gaps left by the 2026-06-28
root→non-root cutover. **Sudoers-only change — no Go change, no version bump** (the file is fetched
canonically by the host-install script). Root cause of the multi-drive "attach one, the other drops"
symptom (audit `felhom.eu/documentation/audits/SPIKE-multidrive-mutual-exclusion-2026-06-29.md`): the
allowlist was incomplete, so several `sudo -n` calls were denied under the non-root user.
- **`lxc-info -n [0-9]* -p -H` → FELHOM_INTERMEDIARY (THE root-cause fix).** `guestInitPID`
(`intermediary.go:256`) shells this to resolve the guest init PID for
`GuestSeesMount``bound_under_parent`. It was absent from the allowlist → `sudo -n` denied → empty
PID → **every external drive reported absent** → the controller drive-gate stopped each drive's apps
(flapping). With the grant, `bound_under_parent` reports truthfully and the gate quiesces.
- **`mount --make-private /mnt/felhom-drives` → FELHOM_INTERMEDIARY.** `EnsureSharedParent`
(`intermediary.go:110`) calls it to isolate the shared parent's peer group on first setup; the
allowlist had only `--make-shared`, so the parent stayed in root's peer group and host submounts
"doubled". Guarded by a mountpoint check (never re-churns a live parent).
- **`systemctl restart dnsmasq` → FELHOM_DNSMASQ.** The v0.29.x LAN-DNS fix switched `reload``restart`
(`lanresolver.go restartDnsmasq`) but the allowlist still only permitted `reload` → split-horizon
DNS self-heal was silently denied under non-root. Added alongside the retained `reload`.
- **`pct set [0-9]* -onboot 1` → FELHOM_PROVISION.** The provision back-half (`backhalf.go`, F3
auto-start) sets onboot; only `-mp[0-9]*` was allowed → denied under non-root.
- **`pct reboot [0-9]*` → FELHOM_GUESTHOOK.** `RebootGuest` (`disks.go:448`, the enroll "activate
pending binds" fallback) was unmatched.
**Surfaced for operator decision (NOT added — would require arbitrary root-in-guest):** `GuestExec`'s
general `pct exec [0-9]* -- <…>` (controller-swap self-update / Phase-2 managed updates) runs variable
vectors incl. `bash -c "<interpolated>"` — granting it = arbitrary execution. **Controller-swap is
currently broken under the non-root agent** until narrow per-vector grants are decided. **Deferred:**
`sensors -j` (defined-but-unwired AND `lm-sensors` not installed on the host — no live caller, path
unverifiable). **Not added (no daemon caller):** `pct create …` (CreateGoldenLXC, maintenance/broad),
`mount UUID=… …` (MountUSBByUUID, legacy/unreferenced). Full audit table in `REPORT.md`.
## v0.43.0 — canonical systemd unit + binary published to Gitea (BUNDLE slice) (2026-06-28)
Day-0 no longer needs a hand-installed agent. The agent binary is now PUBLISHED to Gitea as a generic