Files
felhom.eu/REPORT.md
T
admin 4a81a96678 slice 8A spike: agent<->controller channel + controller deploy plumbing findings
Doc-only spike (no hub code change). Validated on demo-felhom (guest 8200,
torn down): (1) guest->host HTTPS over vmbr0 with fingerprint-pin + bearer +
self-scoping (200/401/403, wrong-pin TLS fail, no firewall rule needed);
(2) config-mount + golden-baked bootstrap unit deploys+runs the controller
(docker login/pull/run v0.34.0) with no pct exec. Verdict: GO to 8A spec.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 08:57:48 +02:00

3.5 KiB

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.


REPORT — Slice 8 Phase A spike: agent↔controller channel + controller deploy plumbing (2026-06-10)

Type

SPIKE (CC-executed on the demo). Doc-only deliverable — no hub/code change, no version bump, no deploy. Probes the two unvalidated foundations of slice 8 before speccing the local API (doc §6) and the provisioning back-half. Findings: documentation/tests/slice8a-channel-deploy-spike-findings.md.

What was proven on demo-felhom

Spike guest 8200 was produced by the real slice-7 bring-up job (felhom-agent v0.9.0, -mode provision) from the golden archive — a golden, link-up, Docker-29.5.3 guest in 8s, fresh MAC. Torn down at the end; demo left as found (only pre-existing 9001/9999 remain; golden archive intact).

1. The channel (guest → host HTTPS over vmbr0, fingerprint-pinned) — PASS

A throwaway self-signed HTTPS stub on 192.168.0.162:8443, hit from inside guest 8200:

  • correct pin + guest-8200 token → 200; no token → 401; other-guest token → 403 (self-scoping holds); wrong pin → hard TLS failure (curl exit 90 — the pin gates the handshake).
  • No firewall rule needed (PVE firewall off; guest and host share the vmbr0 /24, direct route).
  • Security note: the local-API binds the host LAN IP → reachable by anything on the LAN; auth is the only gate (it held). Both pin forms captured (SPKI + leaf-cert SHA-256) for the 8A choice.

2. The deploy plumbing (no pct exec — config mount + golden-baked unit) — PASS

The F3 principle end-to-end: agent stays host-side, populates a read-only config mount (/etc/felhom-bootstrap, bind-mount hotplugged live); a golden-baked oneshot reads it → docker login (token via --password-stdin) → docker pull …/felhom-controller:v0.34.0docker run. The controller came up Up (healthy); an in-guest process read the bootstrap token from the mount and reached the host /storage200. No pct exec used.

Gotchas carried into 8A / the back-half

  1. Unprivileged-LXC uid mapping — the agent must chown 100000:100000 files it writes into the mount (else the guest reads them as nobody; the secret config is inaccessible).
  2. Registry-cred scope — the bootstrap currently carries the shared admin pull token; production wants a narrow, read-only, ideally per-guest/short-lived registry token (mount is the right channel).
  3. Controller config contractbootstrap.json ≠ the controller's controller.yaml; the controller boots to setup mode until 8A emits the real config format/path (or the unit translates).
  4. Pin form (SPKI vs leaf-cert SHA-256) and LAN exposure narrowing — 8A/back-half decisions.

Verdict — GO to spec 8A (local-API server + the 7 §6 endpoints) and the provisioning back-half.

Secret handling (held)

Test local-API tokens + the registry pull cred kept in 0600 host files, referenced by location, never logged/committed; the stub never logged the Authorization header; docker login via --password-stdin. No real per-guest token or registry cred in git. All scratch shredded on teardown. No throwaway registry token was minted (the existing gitea-creds admin cred was used by reference).