--- type: decision tags: [parking, hardening, threat-model, luks, tpm, secure-boot, grub, firmware, offline-first] sources: [parking-system-architecture] updated: 2026-06-30 status: settled --- # Disk & OS hardening (booth appliance) The host-level defences that raise the cost of **offline, physical tamper** of a booth PC: full-disk encryption, TPM-sealed auto-unlock, Secure Boot, a GRUB edit-lock, an unprivileged operator account, and locking firmware updates away from the operator. This page is the **rationale (the *why*)**; the step-by-step verified commands live in the [[appliance-provisioning]] runbook (§3–5c, §4a). Settled across the first real provisioning (2026-06-23) and the firmware-update episode (2026-06-30). > ⚠ **This is the secondary control, not the main event.** The load-bearing anti-fraud mechanism is > [[reconciliation]] over the [[append-only-event-chain|signed event chain]]. Disk/OS hardening > defends the [[threat-model|outsider-with-the-box]] and raises the cost of offline tamper — it does > **not** replace reconciliation, and it cannot stop a *legitimate, logged-in* operator from > committing fraud through the app (that's what the signed ledger + reconciliation are for). > ⚠ **Caveat on the ledger's tamper-resistance (2026-07-02).** The "signed event chain" above is > **software-signed today** (HMAC, key in `EVENT_SIGNING_KEY` on the host disk) — the [[atecc608]] > secure element is [[open-questions|upcoming, not present]]. So a physical adversary who *decrypts > the disk* (see the tamper chain below) reads the signing key and can **forge/re-sign a doctored > ledger undetectably** — the chain does not save you against a host-owner until a non-extractable > hardware signer ([[tpm|TPM]] / USB HSM — [[hardware-signer-options]]) is wired. Until then the disk's > confidentiality/integrity leans harder on the controls below, and the residual backstop against > forgery is **external reconciliation** against records the box doesn't hold (payments, an offsite > backup, a separate witness), not the on-disk signature. ## What it defends against The appliance sits on-site, physically reachable by the [[threat-model|booth operator (the primary adversary)]] and by an outsider who can open the case. Without host hardening, either can: - **Pull the SSD** and read/alter the SQLite ledger offline → FDE (LUKS) defeats this. - **Boot a live USB** to mount and edit the disk → **the BIOS boot-order/boot-menu password is the load-bearing control here**, NOT Secure Boot. Secure Boot happily runs a *signed* Ubuntu live USB, and PCR-7-only sealing can't distinguish it from our own boot (same signing authorities → same PCR 7 → the TPM would unseal). So confidentiality rests on the operator being unable to *select* the USB. See the physical-tamper chain below (a CMOS reset strips that password). - **Edit the GRUB cmdline** (`init=/bin/bash`) for a no-login root shell on the *decrypted* disk → the GRUB edit-lock defeats this (the TPM seal does NOT — see below). - **Escalate from the operator login** (sudo, `docker`/`lxd` groups) → the unprivileged-operator model defeats this. ## The five controls and why each is shaped the way it is | Control | Choice | Why this shape (the load-bearing nuance) | | --- | --- | --- | | **FDE** | LUKS, **passphrase** at install (not the installer's "hardware-backed" option) | The 26.04 installer's automated FDE profiler fails on this firmware (`PCR_UNUSABLE`/`dbt`). Passphrase LUKS + a *manual* TPM seal sidesteps it and lets us pick PCRs. The passphrase slot is the **permanent recovery key**. | | **TPM auto-unlock** | `systemd-cryptenroll`, **PCR 7 only** | Unattended reboot is a hard requirement (no operator types a passphrase). PCR 7 = Secure-Boot policy: catches the attack that matters (disabling Secure Boot) **without** churning on kernel/GRUB updates (PCRs 4/8/9 → would drop to passphrase every boot). **Keep BOTH slots** — slot 0 password (recovery), slot 1 tpm2 (auto-unlock); the TPM is never the only key. | | **Secure Boot** | Enabled, **Deployed Mode**, stock MS keys | Ubuntu's signed shim needs stock `db`. Reaching the installer with Secure Boot ON is itself proof the MS third-party UEFI CA is trusted. | | **GRUB edit-lock** | password, **edit-only** (`--unrestricted`) | Closes the `init=/bin/bash` root-shell hole. **The PCR-7 TPM seal does NOT cover this** — editing the cmdline doesn't change PCR 7, so the TPM still releases the key and the attacker lands on the decrypted disk. Edit-only so the box still boots **unattended** (password required only to *edit* entries). | | **Operator account** | unprivileged, auto-login; separate **admin**+sudo | The operator is the adversary; their OS identity must not be able to escalate. Strip `sudo`, and the latent-escalation groups `lxd`/`docker` (both root-equivalent) + `lpadmin`. Admin is a distinct, no-auto-login identity. | See [[tpm]] for the TPM-2.0 analysis (why PCR-only sealing, bus-sniff limits, TPM-vs-[[atecc608|ATECC608]]). ## Firmware / UEFI dbx updates — a hardening surface AND an operator threat Settled 2026-06-30 after a real incident on `park-buzi`. This is the non-obvious one, because it turns a routine "security update" into a booth-availability risk: - **UEFI `dbx`** (the Secure Boot revocation database) and BIOS firmware are delivered by **`fwupd`/LVFS — a channel SEPARATE from APT** (Ubuntu's GNOME "Firmware Updater" = the `firmware-updater` snap). A clean `apt list --upgradable` does NOT mean no firmware update is pending. - **It can brick boot:** a new dbx against a *stale* GRUB/shim **revokes the installed bootloader** → Secure Boot refuses it → unbootable / GRUB panic. Correct order: `apt full-upgrade` (current `grub-efi`/`shim-signed`) **first**, then dbx. - **It breaks auto-unlock:** even with a current GRUB, applying dbx **moves PCR 7** → the TPM refuses the LUKS key → next boot falls back to the slot-0 passphrase prompt (not a brick). Recover with the PCR-7 re-seal runbook ([[appliance-provisioning]] §4/§4a). - **Threat-model consequence:** a firmware/dbx update makes the booth need a passphrase to boot unattended — so the **operator must be unable to trigger one, and must never hold the passphrase.** Lock it down: `systemctl mask fwupd.service fwupd-refresh.timer`, `snap remove firmware-updater`, a **BIOS admin password** that gates *entering setup* (so the operator can't disable Secure Boot / change boot order), and the **slot-0 passphrase escrowed off-machine** (same custody as `EVENT_SIGNING_KEY` / `BACKUP_KEY`). Firmware maintenance becomes **admin-only, on-site, deliberate**. > The booth is unattended-bootable **only while the firmware / Secure-Boot state is frozen** — that is > the security property, not a bug. The cost is that legitimate firmware maintenance now needs physical > presence + the slot-0 passphrase + a PCR-7 re-enroll. > **⚠ Verification trap:** `cryptsetup … --test-passphrase` **silently passes via the TPM token** (a > false safety signal). Before any firmware change, prove a *typed* passphrase still unlocks the disk > with `--disable-external-tokens` — see [[appliance-provisioning]] §4a. ## Physical-tamper chain & accepted risks (traced 2026-07-02, Dell OptiPlex 7070) The BIOS admin password gates Setup **and** the one-time boot menu (verified: choosing a USB device at F12 prompts for the password). That closes the live-USB path — *while the password holds*. The uncomfortable finding is that the password is a **soft control** against a case-opening adversary: 1. **CMOS reset** (pull the coin cell, or the on-board PSWD/CMOS-clear jumper — Dell documents its location) → BIOS *settings* return to factory defaults: **admin password cleared, boot menu open**. It does NOT wipe the Secure-Boot key databases (PK/KEK/db/dbx live in SPI-flash NVRAM, not the battery-backed RTC), and the 7070's factory default is **Secure Boot = Enabled**. So after the reset Secure Boot comes back **on, same MS keys** → **PCR 7 reconstructs to the same value.** 2. **Boot a signed Ubuntu live USB** (now selectable). Same signing authorities → PCR 7 matches the sealing policy → the attacker runs `cryptsetup`/`systemd-cryptsetup` and the **TPM releases the LUKS key**. Disk decrypts; they have **root on the decrypted filesystem**, including the ledger. - Note the asymmetry: if instead they *disable* Secure Boot in the now-unlocked BIOS, PCR 7 **changes** → the TPM refuses → the box drops to the slot-0 passphrase prompt they don't have. So *disabling* Secure Boot locks them out; leaving it at the reset default lets them in. This is the PCR-7-only "same-signer" weakness (systemd docs recommend PCR 7 **+ a PIN** to close it). **Net:** a battery-pull alone yields nothing (disk stays sealed), but **battery-pull → live-USB → PCR-7 unseal** is a realistic chain to **root on the decrypted data**. What it costs the attacker: a screwdriver and a signed USB. What still holds after it: they never get the **escrowed slot-0 passphrase**, and (the point of the caveat above) the ledger's forgery-resistance depends on the signer — with today's **on-disk HMAC key they CAN forge the ledger**; only a hardware signer ([[hardware-signer-options]]) would keep the financial record unforgeable through this. **Accepted risks (named, not silently "covered"):** - **PCR-7 same-signer unseal via CMOS reset** (above). *Not* mitigated by the current config. Real fixes both cost the thing we optimised for: a **TPM PIN** (`--tpm2-with-pin=yes`) closes it but **kills unattended boot** (someone types a PIN each power event); **custom Secure-Boot keys / more PCRs** close it but reintroduce re-seal churn on kernel/shim updates (the exact thing PCR-7-only avoids). Deferred decision — accept for now; the primary control remains reconciliation + escrowed backups, not disk confidentiality. - **Unsigned initramfs (evil-maid).** `/boot` is unencrypted and Ubuntu does **not** sign the initramfs (Secure Boot verifies shim→GRUB→kernel; PCR 7 doesn't measure the initrd). The initramfs is exactly the code that receives the LUKS key, so a maid who tampers it and waits one boot can harvest the key. Accepted: needs repeated privileged physical access, and a hardware signer would still keep the ledger unforgeable even from a fully-owned host. - **Operator USB at an auto-logged-in session** — unverified what the unprivileged operator account can read on the host (e.g. can it reach the Docker-mounted `/data`?). **TODO: verify** the operator can't read the DB volume or `EVENT_SIGNING_KEY` from its own login. ## Where the commands live This page is the rationale. The **verified, run-on-real-hardware commands** are in [[appliance-provisioning]]: §1 BIOS, §2 Secure-Boot live-USB check, §3 encrypted install (the `dbt` workaround), §4 TPM seal (PCR 7) + re-seal runbook, **§4a firmware/dbx lockdown**, §5 GRUB edit-lock, §5c admin-vs-operator accounts. Komodo Periphery is folded into the same hardened surface as a root-capable remote agent — see [[fleet-deployment-komodo]] (bind to the NetBird interface only). ## Relates - [[appliance-provisioning]] — the runbook (commands); this page is its *why*. - [[tpm]] — TPM 2.0 analysis (sealing, PCR choice, limits, vs ATECC608). - [[threat-model]] — the operator-adversary framing this hardening serves. - [[reconciliation]] / [[append-only-event-chain]] — the **primary** anti-fraud control this complements, never replaces. - [[hardware-signer-options]] — TPM / USB-HSM / ATECC608 options for a non-extractable ledger signing key (the missing piece this page's tamper chain exposes). - [[fleet-deployment-komodo]] — Periphery as part of the trusted computing base.