0efdc78d75
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
176 lines
9.3 KiB
Markdown
176 lines
9.3 KiB
Markdown
# Felhom pilot — tester agreement (Peti)
|
|
|
|
> The terms of the first external pilot: what Peti runs, what Felhom can and cannot do on his
|
|
> hardware, the honest limitations of the pilot, and his exit rights. Lives at
|
|
> `felhom.eu/documentation/pilot/PETI-tester-agreement.md`.
|
|
> Created 2026-07-09 (GL-7). Operator: Viktor. Tester: Peti.
|
|
>
|
|
> This is the operator-side record of the bargain. The points in §3, §4 and §5 are what Peti is told
|
|
> and asked to acknowledge at onboarding; that conversation happens in Hungarian — this document is
|
|
> the English source of truth those points are drawn from.
|
|
|
|
---
|
|
|
|
## 1. What the pilot is
|
|
|
|
Peti runs **Felhom as a guest on his own Proxmox server** — the **BYO-host** model. He stays root on
|
|
his hardware; Felhom is one LXC guest plus a narrow, non-root management footprint. This is not the
|
|
appliance model (Felhom-owned hardware); the whole point of the pilot is to prove the BYO trust
|
|
boundary on someone else's box.
|
|
|
|
**Peti's box:** an 80-core / 128 GB rack server already running his own workloads. The Felhom guest
|
|
is capped at **12 cores / 32768 MiB** (noisy-neighbour containment — the only thing standing between
|
|
Felhom and his other guests, since we do not control the host).
|
|
|
|
**Name:** `sajatfelhom.hu`. The existing Cloudflare tunnel for that domain must be re-pointed at the
|
|
new guest as part of onboarding (§7).
|
|
|
|
---
|
|
|
|
## 2. What runs on Peti's box
|
|
|
|
| Component | Footprint | Privilege |
|
|
|-----------|-----------|-----------|
|
|
| Felhom guest (LXC) | one container in the `felhom` pool, capped 12c/32 GB | unprivileged LXC |
|
|
| Host agent | one binary + systemd unit on the host | **non-root** (`felhom-agent` user) |
|
|
| Sudoers allowlist | `/etc/sudoers.d/felhom-agent` | narrow, `pct`/`vzdump`/mount verbs only |
|
|
| PVE API token | scoped to the `felhom` pool + named storages only | `Pool.*`/`VM.*`/`Datastore.*` on those objects |
|
|
| Local API | binds `vmbr0:8443` on his LAN | TLS + per-guest bearer token |
|
|
|
|
Nothing else. In particular, on a BYO host the installer **does not** touch these appliance-only
|
|
mechanisms:
|
|
|
|
- **Break-glass is OFF.** Felhom never runs `chpasswd` on `root@pam` and never vaults a host root
|
|
credential to the hub. Peti's root password is his own and is never seen or changed.
|
|
- **Out-of-band operator SSH is OFF** (`oob.enabled=false`). Felhom opens no operator tunnel into
|
|
his box.
|
|
- **The offsite WireGuard tunnel is OFF** (`wg_tunnel.enabled=false`). No Felhom-side connection
|
|
reaches back into his network.
|
|
|
|
These are asserted at install time (the byo config-write asserts `oob`/`wg_tunnel`/`lan_resolver`
|
|
are all off before the install is marked complete) and were live-validated on the demo host during
|
|
the GL-6 drill.
|
|
|
|
---
|
|
|
|
## 3. What Felhom can and cannot do (the trust boundary)
|
|
|
|
**Can:** provision and manage its own guest, run backups of its own guest to the storages named in
|
|
its ACL, report guest/host health to the hub, and — only with an operator signing key that Peti's
|
|
box has pinned — apply a signed agent self-update. Every host action goes through the narrow sudoers
|
|
allowlist, scoped to the `felhom` pool.
|
|
|
|
**Cannot:** read or modify Peti's other guests (the pool-scoped token is refused outside `felhom`);
|
|
change his root password; open an inbound operator session; touch his DNS service (see F6 below);
|
|
or reach storages outside its named ACL. The local API authorises every request strictly against the
|
|
calling token's own guest — a token minted for one guest is refused for any other
|
|
(`localapi/server.go`; spot-verified).
|
|
|
|
---
|
|
|
|
## 4. Honest limitations of the pilot
|
|
|
|
This is the data-sovereignty pitch stated plainly, not hidden:
|
|
|
|
- **No offsite backup yet (local-only).** Backups stay on Peti's own hardware. **A dead or stolen
|
|
box, or a dead backup drive with no second local target, loses data.** The offsite tier
|
|
(Tier-1/Tier-2 split + production WG endpoint) is a fast-follow, not part of this pilot. Local
|
|
backups being green is asserted at onboarding (§7).
|
|
- **Backups live on a physically removable drive on his own hardware (F2).** This is the flip side
|
|
of "no offsite" and is the sovereignty guarantee: his data never leaves his premises, and he can
|
|
physically remove the drive. It also means the resilience of the backup is exactly the resilience
|
|
of that one local drive/pool.
|
|
- **The `felhom` pool membership is asserted at bring-up only, not continuously healed (F7).** If
|
|
something outside Felhom moves the guest out of the pool while it runs, Felhom won't silently
|
|
re-grab it; a re-run (or `--adopt-pool`) repairs it. No autonomous host-level reassertion.
|
|
- **Port 53 must be free on his host (F6).** Felhom's guest DNS wants `:53`. If Peti already runs a
|
|
DNS service there, the installer **refuses and tells him** — it will not stop, mask, or reconfigure
|
|
a DNS service on a host Felhom does not own. He resolves the conflict; Felhom mutates nothing. This
|
|
is checked before anything is written (§7 pre-flight).
|
|
|
|
---
|
|
|
|
## 5. Exit rights (data sovereignty)
|
|
|
|
Peti can leave at any time and keep his data. The uninstaller:
|
|
|
|
- **Keeps** all drive data under `/mnt/felhom-drives/*`, the backup storage contents, the hub record,
|
|
and any vaulted recovery credential — and prints a KEPT-vs-WIPED statement naming each, in both
|
|
modes. Drives are unmounted (plain `umount`; a busy drive is warned, never force-unmounted).
|
|
- **Removes** only Felhom's own footprint: its guest, agent, sudoers, self-update artifacts, and
|
|
config (including `.bak*` siblings that could hold a hub API key).
|
|
- Refuses to touch any guest that is not a Felhom guest (it targets only guests carrying the
|
|
`/etc/felhom-bootstrap` bind mount).
|
|
|
|
Result: Peti walks away with his hardware untouched and his data on his own removable drives. This
|
|
was live-validated twice on the demo host (two real uninstalls, drive data intact each time, host
|
|
audit clean) during the GL-6 drill.
|
|
|
|
---
|
|
|
|
## 6. Pre-install checklist (confirm with Peti before day-0)
|
|
|
|
- [ ] **PVE major version 9.x** (the byo preflight refuses non-9.x unless forced).
|
|
- [ ] **Port 53 is free** on the host — no existing DNS service bound there (F6; preflight refuses
|
|
otherwise).
|
|
- [ ] **The `felhom` pool** either does not exist or is Felhom's to use.
|
|
- [ ] **VMID 9201 is free** (or pick another; the installer auto-selects a free one if 9201 is taken).
|
|
- [ ] **⚠ OPEN — the backup target.** `felhom-pbs` (the demo offsite datastore) is unreachable from
|
|
Peti's LAN, so the default `--acl-storages "local local-lvm felhom-pbs"` is wrong for him. We
|
|
must know **whether Peti's server has a second disk/pool** to use as the local backup target:
|
|
- If **yes** → name it in `--acl-storages` (e.g. `"local local-lvm <his-backup-storage>"`) so
|
|
backups land on a *different* physical drive than the live guest — real local resilience.
|
|
- If **no** (single pool) → backups land on the same pool as the guest; this is a degraded
|
|
posture (one drive failure loses both live and backup) and must be stated to Peti explicitly.
|
|
**Resolve this before finalising the install command below.**
|
|
- [ ] **`sajatfelhom.hu` Cloudflare tunnel** — confirm we can re-point it at the new guest (§7).
|
|
- [ ] **Customer `peti-felhom` exists in the hub** with real Gitea read creds filled in
|
|
(`git.username`/`git.token`) — the artifact fetch needs them, or relies on the anonymous path.
|
|
|
|
---
|
|
|
|
## 7. The install command
|
|
|
|
Built from the hub's customer page (`peti-felhom` → **Setup Command** → BYO). The BYO shape is
|
|
deliberately minimal — a fresh box auto-fetches the golden template from Gitea, so no
|
|
`--force-gitea-golden` is needed:
|
|
|
|
```
|
|
sudo ./felhom-host-install.sh \
|
|
--customer-id peti-felhom \
|
|
--mode byo \
|
|
--cores 12 \
|
|
--memory 32768 \
|
|
--acl-storages "local local-lvm <PETI-BACKUP-STORAGE>"
|
|
```
|
|
|
|
`<PETI-BACKUP-STORAGE>` is resolved by the §6 open question. Add `--vmid`/`--node` only if 9201 is
|
|
taken or the host is multi-node. The command is **download-then-run** (the script is fetched and
|
|
inspected, never piped straight into a shell).
|
|
|
|
**Onboarding sequence:**
|
|
|
|
1. Run pre-flight first: same command with `--preflight-only` — prints PASS/FAIL, writes no state.
|
|
Confirms 9.x, `:53` free, ACL storages exist, pool membership.
|
|
2. Run the install. Peti sees the host-mutation disclosure and types his hostname to acknowledge.
|
|
3. **Set the dashboard password (G9).** The customer dashboard is open until the operator sets the
|
|
password via the hub config; set it at onboarding, along with the geo-restriction. Until then the
|
|
dashboard is publicly reachable — do not consider onboarding complete without it.
|
|
4. **Re-point the `sajatfelhom.hu` Cloudflare tunnel** at the new guest.
|
|
5. **Verify local backups are green** on his box (§4 — the honesty gate). Confirm a backup completes
|
|
to `<PETI-BACKUP-STORAGE>` and a restore-test passes mount-parity.
|
|
|
|
---
|
|
|
|
## 8. Acknowledgement
|
|
|
|
At onboarding, Peti is asked to acknowledge (in Hungarian):
|
|
|
|
1. Felhom runs as a guest on his hardware; he stays root and Felhom never changes his root password
|
|
or opens an inbound operator session.
|
|
2. **There is no offsite backup in the pilot.** His data stays on his premises on a removable drive;
|
|
a lost box or a failed backup drive without a second local copy loses data.
|
|
3. He can uninstall at any time and keep his data and hardware; Felhom removes only its own footprint.
|
|
4. This is a pilot: rough edges are expected, and the honest limitations above are the trade for full
|
|
data sovereignty.
|