GL-2: --mode appliance|byo install profile (host-install v1.10.0) + harness
Mandatory install profile (no default): byo = a host the operator does not own. Break-glass gated OFF at its call site in byo (root@pam never touched), mandatory --cores/--memory, argv-time refusals (--enable-oob/--rotate-recovery, non-9.x PVE, missing --acl-storages), host-mutation disclosure + typed-hostname ack, byo config asserts (lan_resolver/wg_tunnel/oob off; byo flips the lan_resolver write default to off), pool+ACL verify asserts in BOTH modes (R2), --preflight-only (no state, PASS/FAIL verdict), resume mode-mismatch refusal, FELHOM_INSTALL_STATE_DIR harness override. NEW scripts/hostinstall-mode-harness.sh: static refusal matrix C1-C4 + grep invariants + PVE tier (C5 + A/B dry transcripts). 16/16 PASS on felhom-pve (C5 live); red-proofs RP-1..RP-3 run->fail->revert. shellcheck clean at severity=warning. Docs: day0-install SC.5 byo section + trust model; REUSE row; CONTEXT + REPORT. Live drill = GL-6 (supervised); STOP honored (no non-dry run). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
@@ -14,6 +14,12 @@
|
||||
>
|
||||
> Scope: a **shared** Proxmox box (the colleague's-box model) — a box that already runs, or will run,
|
||||
> non-Felhom guests. A dedicated box is the same procedure minus the sizing caution.
|
||||
>
|
||||
> **v1.10.0 (GL-2): every install now REQUIRES `--mode appliance|byo`** — there is no default. Use
|
||||
> `appliance` for a box Felhom owns/manages end-to-end (this guide's drilled path, unchanged apart
|
||||
> from the flag); use `byo` for a host the operator does NOT own (the pilot's own PVE) — see §C.5.
|
||||
> The byo profile is implemented + statically validated but **not yet drill-validated** (that is the
|
||||
> supervised GL-6 run).
|
||||
|
||||
## Who does what
|
||||
|
||||
@@ -135,7 +141,7 @@ Notes:
|
||||
```bash
|
||||
curl -fsSO https://felhom.eu/scripts/felhom-host-install.sh
|
||||
chmod +x felhom-host-install.sh
|
||||
./felhom-host-install.sh -h | head -3 # sanity: must print v1.9.1 (or newer) — the version this guide was drilled against
|
||||
./felhom-host-install.sh -h | head -3 # sanity: must print v1.10.0 (or newer) — older scripts don't know --mode
|
||||
```
|
||||
|
||||
### C.2 Preview (recommended)
|
||||
@@ -144,7 +150,7 @@ chmod +x felhom-host-install.sh
|
||||
read-only and asks for the passphrase):
|
||||
|
||||
```bash
|
||||
./felhom-host-install.sh --customer-id <CUSTOMER-ID> --vmid <VMID> \
|
||||
./felhom-host-install.sh --customer-id <CUSTOMER-ID> --mode appliance --vmid <VMID> \
|
||||
--cores 2 --memory 4096 \
|
||||
--force-gitea-golden --acl-storages "local local-lvm" \
|
||||
--dry-run
|
||||
@@ -153,7 +159,7 @@ read-only and asks for the passphrase):
|
||||
### C.3 The canonical shared-box install command
|
||||
|
||||
```bash
|
||||
./felhom-host-install.sh --customer-id <CUSTOMER-ID> --vmid <VMID> \
|
||||
./felhom-host-install.sh --customer-id <CUSTOMER-ID> --mode appliance --vmid <VMID> \
|
||||
--cores 2 --memory 4096 \
|
||||
--force-gitea-golden --acl-storages "local local-lvm"
|
||||
```
|
||||
@@ -163,6 +169,7 @@ Placeholders and flags — what and why:
|
||||
| Flag | Value | Why |
|
||||
|---|---|---|
|
||||
| `--customer-id` | the Part A customer ID | keys every hub call |
|
||||
| `--mode` | `appliance` or `byo` | REQUIRED, no default. `appliance` = a Felhom-owned/managed box (this section). `byo` = a host the operator does not own — use §C.5's command instead |
|
||||
| `--vmid` | the free vmid from Part B | ALWAYS pass it explicitly — deterministic, and recorded in the install state for a later `--uninstall` |
|
||||
| `--cores 2 --memory 4096` | the appliance cap | protects the other guests on a shared box; size to roughly half the host if the box is small (cap ≤ host resources) |
|
||||
| `--force-gitea-golden` | — | a fresh box has no local golden archive; fetch it from Gitea and verify its sha256 against the hub manifest (this is the normal customer path) |
|
||||
@@ -196,7 +203,57 @@ Expected duration: minutes; dominated by the two Gitea downloads (agent ~20 MB,
|
||||
the customer's uplink.
|
||||
|
||||
If a step fails: read the error (they are specific), fix the cause, re-run the SAME command with
|
||||
`--resume` appended.
|
||||
`--resume` appended (with the SAME `--mode` — the script refuses a mode flip on a half-done install).
|
||||
|
||||
### C.5 BYO hosts (`--mode byo`) — installing on a Proxmox server the operator does NOT own
|
||||
|
||||
**Trust model.** On a BYO host the roles invert: the box owner is root and stays root; Felhom is the
|
||||
guest. The installer therefore (a) never touches the owner's credentials — the break-glass step
|
||||
(4b/8, root@pam reset + hub vault) is skipped entirely, nothing is vaulted; (b) treats the owner's
|
||||
workloads as the thing to protect — the CPU/RAM caps are mandatory, they are the only
|
||||
noisy-neighbor containment there; (c) refuses anything host-invasive that the appliance profile
|
||||
allows (`--enable-oob`, `--rotate-recovery`, unvalidated PVE majors, ACL grants on storages the box
|
||||
doesn't have); and (d) asserts the written agent config keeps `lan_resolver`/`wg_tunnel`/`oob` OFF
|
||||
— the agent must not take over the owner's DNS or open tunnels. Recovery on a BYO box = the owner's
|
||||
own console access, by design.
|
||||
|
||||
**Recommended first run — preflight only** (all step-1 checks incl. the byo gates, an explicit
|
||||
PASS/FAIL verdict, exit 0/1, writes nothing — re-runnable any number of times):
|
||||
|
||||
```bash
|
||||
./felhom-host-install.sh --customer-id <CUSTOMER-ID> --mode byo --vmid <VMID> \
|
||||
--cores <N> --memory <MiB> \
|
||||
--force-gitea-golden --acl-storages "local local-lvm" \
|
||||
--preflight-only
|
||||
```
|
||||
|
||||
**The install command** (same flags, minus `--preflight-only`):
|
||||
|
||||
```bash
|
||||
./felhom-host-install.sh --customer-id <CUSTOMER-ID> --mode byo --vmid <VMID> \
|
||||
--cores <N> --memory <MiB> \
|
||||
--force-gitea-golden --acl-storages "local local-lvm"
|
||||
```
|
||||
|
||||
What byo does differently (everything else matches C.4's eight steps):
|
||||
|
||||
- `--cores` AND `--memory` are **required** — size them WITH the owner (the guest must never starve
|
||||
the owner's guests). `--acl-storages` must name storages that actually exist on the box, or the
|
||||
preflight dies naming the missing ones.
|
||||
- Preflight additionally prints what already listens on the host's `:53` (informational — Felhom
|
||||
never configures DNS on a byo box) and the existing-guest count.
|
||||
- At the end of preflight the script prints the **complete host-mutation list** (pveum
|
||||
roles/user/token/ACL/pool, agent user/binary/unit/sudoers/config/state, the watchdog + guarded
|
||||
wrappers, the guest + golden) and requires typing the host's **short hostname** to proceed —
|
||||
show this list to the box owner; it is the consent artifact.
|
||||
- Step 4b/8 (break-glass) is skipped; the verify step asserts pool membership + the scoped ACL
|
||||
grants landed (both modes do this from v1.10.0).
|
||||
|
||||
### C.6 Post-hoc mode note for pre-v1.10.0 installs
|
||||
|
||||
Boxes installed by ≤ v1.9.1 have no recorded mode; their state file simply predates it. `--resume`
|
||||
on such a box accepts whichever `--mode` you pass — pass the mode that matches how the box is
|
||||
actually operated (existing Felhom-owned boxes: `appliance`).
|
||||
|
||||
---
|
||||
|
||||
@@ -306,6 +363,10 @@ roles/ACL/token/user, the pool (if empty), the install state file.
|
||||
|
||||
| Symptom | Cause | Fix |
|
||||
|---|---|---|
|
||||
| dies immediately: "--mode is required" | v1.10.0+ has no default profile | add `--mode appliance` (Felhom-owned box) or `--mode byo` (owner's box, §C.5) |
|
||||
| dies immediately: "byo mode requires explicit --cores and --memory" | byo caps are mandatory | size the caps with the box owner and pass both |
|
||||
| dies: "install started as X; resume with --mode X" | `--resume` with the other mode | resume with the recorded mode, or `--uninstall` and start over |
|
||||
| byo dies: "acl storage(s) not found on this box" | `--acl-storages` names a storage the box lacks | pass the box's real storages (check `pvesm status`) |
|
||||
| step 1 dies: "this is a N-node cluster" | multi-node cluster | re-run with `--node <name>` |
|
||||
| step 5 dies: "hub artifact manifest has no agent version" | Day-0 manifest unset/incomplete | Part A.3 — set it in the operator UI |
|
||||
| step 5 dies: "no git token in controller.yaml" | customer created without git credentials | Part A.2 — add `git.username`/`git.token`, regenerate config |
|
||||
|
||||
Reference in New Issue
Block a user