Documents the deploy-time requirement that the cookie fail-safe fix (7629d5d)
introduced: the LAN appliance serves the SPA same-origin over plain http, where a
Secure cookie is never sent — so it MUST set COOKIE_SECURE=0 or operators can't log
in. A TLS deploy leaves it unset.
- wiki/concepts/disk-os-hardening.md: new "Deploy-time server configuration (runbook)"
section listing the security-load-bearing env (JWT_SECRET, EVENT_SIGNING_KEY,
COOKIE_SECURE=0) with the why + the network-scoped justification.
- wiki/entities/local-jwt-auth.md: corrected the stale "Secure when NODE_ENV=production"
cookie line to the Secure-by-default / opt-out model.
- wiki/log.md: entry.
Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
2.9 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.)
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.