scripts: felhom-host-install.sh v1.0.0 — Day-0 host bootstrap (live-validated)
Operator-run Day-0 automation for a fresh PVE host: pveum token -> hub POST /host-enroll (single secret, option C) -> agent config -> felhom-agent --selftest=provision -> verify. Idempotent/resumable (state.json), --dry-run, --resume, --force, --preserve-from; --mode dr is a documented 10D stub. Live-validated on felhom-pve: authorized wipe of demo guest 9201 + full re-provision from the golden -> controller config-pull + public tunnel HTTP 200 + host-report of 9201; idempotent --resume no-op. Found+fixed one ordering bug during the run (token ACL must be applied AFTER token rotation — token-remove purges the ACL). Adds scripts/README.md (operator runbook) + scripts/CHANGELOG.md; REPORT overwritten; spike doc pointer added. No service code changed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TtXesNa2LGbMmE4DNL6SE7
This commit is contained in:
@@ -0,0 +1,87 @@
|
||||
# Felhom host scripts
|
||||
|
||||
Operator-side scripts for standing up a Felhom Proxmox host.
|
||||
|
||||
## `felhom-host-install.sh` — Day-0 host bootstrap (operator-deploy)
|
||||
|
||||
Run on a **freshly-PVE-installed** box to fully automate Day-0: Proxmox API token →
|
||||
hub host enrollment (single secret) → agent config → guest provision → verify. It
|
||||
composes already-proven mechanisms (the `pveum` role/token sequence, the hub
|
||||
`POST /host-enroll` enrollment from option C, and `felhom-agent --selftest=provision`).
|
||||
The agent renders `bootstrap.json` into the guest and the **controller pulls its own
|
||||
`controller.yaml`** in-guest — the script never fetches it.
|
||||
|
||||
Grounding: [`documentation/audits/SPIKE-day0-firstboot-handshake-2026-06-26.md`](../documentation/audits/SPIKE-day0-firstboot-handshake-2026-06-26.md).
|
||||
|
||||
### Prerequisites (manual, before running)
|
||||
|
||||
1. **Install Proxmox VE 9.x** on the box. During the installer, use **Advanced → LVM**
|
||||
sizing so `local-lvm` (the `pve/data` thin pool) has enough room for the appliance
|
||||
volumes — a useful box wants **≥ ~120 GiB** free on `local-lvm` (rootfs 32G + Docker-data
|
||||
~200G + user-data ~50G after grows). The script refuses below the hard minimum.
|
||||
2. **SSH into the box as root.**
|
||||
3. **Create the customer in the hub first** (hub UI → new customer). The customer's
|
||||
**retrieval passphrase** (a 5-word Hungarian phrase) is the only secret you carry to the box.
|
||||
4. A **golden archive** must exist on the archive storage (newest `vzdump-lxc-<golden-vmid>`).
|
||||
If none exists, build one with `felhom-agent/configs/build-golden.sh` first.
|
||||
5. The **felhom-agent binary** + its systemd unit installed (the script auto-detects the
|
||||
unit's `-config` path; if the binary is absent it tells you to install it).
|
||||
|
||||
### Usage
|
||||
|
||||
```bash
|
||||
curl -fsSL https://felhom.eu/scripts/felhom-host-install.sh -o felhom-host-install.sh
|
||||
chmod +x felhom-host-install.sh
|
||||
|
||||
# secure no-echo passphrase prompt:
|
||||
sudo ./felhom-host-install.sh --customer-id <customer>
|
||||
|
||||
# or from a 0600 file (no prompt):
|
||||
sudo ./felhom-host-install.sh --customer-id <customer> --passphrase-file /root/.pass
|
||||
|
||||
# preview every mutating command without executing:
|
||||
sudo ./felhom-host-install.sh --customer-id <customer> --dry-run
|
||||
|
||||
# resume after a fixed mid-way failure (skips completed steps):
|
||||
sudo ./felhom-host-install.sh --customer-id <customer> --resume
|
||||
```
|
||||
|
||||
The passphrase is read **no-echo** or from a **0600 file** — never a CLI argument, never
|
||||
echoed, never written to the state file or logs. The minted Proxmox-token secret and the
|
||||
per-host hub api_key live **only** in the agent config (`0600`, root).
|
||||
|
||||
### Key options
|
||||
|
||||
| Option | Default | Purpose |
|
||||
|--------|---------|---------|
|
||||
| `--customer-id ID` | (required) | customer (must already exist in the hub) |
|
||||
| `--vmid N` | `9201` | guest VMID to provision |
|
||||
| `--golden VOLID` | newest `vzdump-lxc-<golden-vmid>` | golden archive |
|
||||
| `--rootfs/--datavol/--sysdata-grow N` | auto-compute | volume grows (GiB over the golden base 32/16/8) |
|
||||
| `--passphrase-file PATH` | no-echo prompt | read passphrase from a 0600 file |
|
||||
| `--preserve-from PATH` | — | merge non-Day-0 sections (PBS/local_api/privileged/authz) from an existing config |
|
||||
| `--dry-run` / `--resume` / `--force` | off | preview / resume / clobber an existing vmid |
|
||||
| `--mode provision\|dr` | `provision` | `dr` is a documented 10D stub (not implemented) |
|
||||
|
||||
### Behaviour notes
|
||||
|
||||
- **Idempotent + resumable.** A step-state file (`/var/lib/felhom-install/state.json`) records
|
||||
completed steps; `--resume` skips them. A plain re-run **refuses** to clobber an existing
|
||||
`--vmid` (pass `--force` to override).
|
||||
- **Single-secret enrollment.** `POST /host-enroll` mints on first call (201) and **reuses**
|
||||
the credential on later calls (200) — re-running never orphans a running agent's key. The
|
||||
global operator key is never used.
|
||||
- **Token automation.** Creates/normalises the 16-priv `FelhomAgent` role, the
|
||||
`felhom-agent@pve` user + privsep token, and **both** ACL grants (user **and** token — the
|
||||
ACL is applied *after* the token exists, because `pveum user token remove` purges it).
|
||||
- **DR mode** (`--mode dr`) is a documented seam only — it restores the customer's **own** PBS
|
||||
whole-CT snapshot instead of the golden. Not implemented (10D).
|
||||
|
||||
### Productionization hooks (not done here)
|
||||
|
||||
- **Serving:** place this file where the felhom.eu site serves it at
|
||||
`https://felhom.eu/scripts/felhom-host-install.sh` (a static route; verify on deploy).
|
||||
- **Agent binary delivery:** the script expects the agent pre-installed; a fetch-from-release
|
||||
step is the documented hook.
|
||||
- **Golden delivery:** the test used a local golden; central download + checksum verify is the
|
||||
remaining hook.
|
||||
Reference in New Issue
Block a user