New wiki/decisions/appliance-provisioning.md: the hardware-verified step-by-step for provisioning a booth PC (Dell OptiPlex 7070, i5-8500, discrete Nuvoton TPM 2.0) from factory Windows to a hardened Ubuntu 26.04 LTS appliance. Every command was run on the first real unit (2026-06-23). Captures the firmware-specific gotchas: Ventoy → 0x1A under Secure Boot (flash ISO directly); the 7070 BIOS can't view db (verify via live USB); the installer's hardware-backed encryption fails with PCR_UNUSABLE/dbt (use passphrase LUKS + manual systemd-cryptenroll PCR-7 seal); GRUB password must be edit-only (--unrestricted) to keep unattended boot. OS hardening on unit 1 is COMPLETE + verified: LUKS FDE + TPM auto-unlock (PCR 7, unattended) + Secure Boot (Deployed) + GRUB edit-lock (closes the init=/bin/bash root-shell hole that PCR-7 sealing does not cover). Resolves the implementation half of open-questions #12 for unit 1. Cross-linked from disk-os-hardening; index + log updated. Still TODO on the box: Docker + run the stack. Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
3.5 KiB
type, tags, sources, updated
| type | tags | sources | updated | ||||
|---|---|---|---|---|---|---|---|
| concept |
|
|
2026-06-21 |
Disk / OS Hardening
Worthwhile, but not the main event — it defends against the outsider-with-physical-access, not the operator (see threat-model). (See parking-system-architecture §3.)
Physical-access attacks on Windows are trivial (boot media + password-reset tools), so a dedicated Linux machine is the correct platform — not Windows or WSL. This is a standing-decisions.
- LUKS full-disk encryption — defeats boot-from-USB.
- GRUB password + Secure Boot — prevents boot-parameter tampering / unsigned loaders.
- No desktop environment — single-purpose appliance.
- Key-based SSH only.
- tpm (recommended, 2026-06-21) — seals the LUKS key to the boot chain so the disk auto-unlocks only on an untampered boot, making encryption-at-rest compatible with unattended reboot (a booth must come back up after a power cut without a human typing a passphrase). Also a candidate home for the non-extractable host event-signing key. Caveats (live-root limit, bus-sniff, PCR brittleness, mandatory recovery passphrase + re-seal runbook) on tpm; implementation is open-questions #12.
With LUKS in place, SQLCipher becomes optional defence-in-depth rather than the critical layer. (The custom controller adds its own: ESP32 flash encryption + secure boot — see esp32-custom-controller.)
Step-by-step OS install + TPM-seal procedure (BIOS → encrypted install → manual PCR-7 TPM seal, with the Dell-7070-specific
dbtworkaround) lives in appliance-provisioning — written from the first real provisioning (2026-06-23) and verified on hardware. OS hardening on the first unit is COMPLETE: LUKS FDE + TPM auto-unlock (PCR 7, unattended) + Secure Boot (Deployed) + GRUB edit-lock (the GRUB password is the specific countermeasure to theinit=/bin/bashroot-shell hole that PCR-7 sealing does NOT cover). Resolves the implementation half of open-questions #12 for unit 1.
Deploy-time server configuration (runbook)
Env in apps/server/.env on the appliance (see apps/server/.env.example). The security-load-bearing ones:
JWT_SECRET— ≥32 random chars; the server refuses to boot without a strong one (no insecure default).openssl rand -hex 32. See local-jwt-auth.EVENT_SIGNING_KEY— dedicated HMAC key for the signed ledger; ≥16 chars. Falls back toJWT_SECRETwith a warning if unset — set a dedicated one before production.COOKIE_SECURE=0— REQUIRED on the plain-HTTP LAN appliance. Auth/CSRF cookies areSecureby default (fail-safe). The appliance serves the SPA same-origin over plain http on the booth LAN, where aSecurecookie is never sent — so without this opt-out operators cannot log in. Set it deliberately. (A TLS/reverse-proxied deploy leaves it UNSET so cookies staySecure.) This replaced the oldNODE_ENV=productiongate, which silently droppedSecureif the var was forgotten. See local-jwt-auth.
The plain-http booth LAN is acceptable because it's an isolated, single-purpose network (the only browser is the booth's own; access controllers sit on a separate VLAN — see network-isolation, trust-boundary).
Secure-off is a network-scoped decision, not a blanket weakening; the JWT stays HttpOnly + SameSite=Strict and CSRF double-submit still applies.