docs(wiki): firmware/dbx-vs-TPM hardening + create disk-os-hardening page
Real-world park-buzi episode: a UEFI dbx update (delivered via fwupd/LVFS, NOT apt) revoked a stale GRUB -> panic, and moved PCR 7 -> broke TPM-sealed LUKS auto-unlock -> passphrase prompt. Recovered by re-sealing PCR 7. - appliance-provisioning.md: extend the §4 re-seal runbook to name dbx; new §4a (fwupd-not-apt, GRUB-panic ordering, PCR-7 re-seal, operator lockdown: mask fwupd + remove firmware-updater snap + BIOS-password + passphrase escrow) incl. the --test-passphrase-silently-passes-via-TPM trap (--disable-external-tokens); gotchas #12/#13. - disk-os-hardening.md: NEW — resolves a long-dangling wikilink referenced from ~18 pages. The *why* of host hardening (5 controls + firmware lockdown); commands stay in appliance-provisioning; reconciliation remains the primary anti-fraud control. - index.md: expand the disk-os-hardening catalog line. - log.md: two note entries. Claude-Session: https://claude.ai/code/session_01Xcm6ikLgGoCxxHrxtjkk5V
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
type: reference
|
||||
tags: [parking, deployment, appliance, hardening, runbook, offline-first]
|
||||
sources: []
|
||||
updated: 2026-06-27
|
||||
updated: 2026-06-30
|
||||
status: settled
|
||||
---
|
||||
|
||||
@@ -103,9 +103,67 @@ sudo reboot
|
||||
- Still prompts = PCR mismatch; type the passphrase (NOT locked out), then retry with
|
||||
`--tpm2-pcrs=0`. The `password` slot + `crypttab.bak` make this fully reversible.
|
||||
|
||||
> **Re-seal runbook:** a BIOS update / Secure Boot change alters PCR 7 → the TPM refuses → boot
|
||||
> falls back to the passphrase prompt (not a brick). After such a change, re-run step 4's
|
||||
> `systemd-cryptenroll --wipe-slot=tpm2 --tpm2-device=auto --tpm2-pcrs=7 /dev/sda3` to re-bind.
|
||||
> **Re-seal runbook:** a BIOS update / Secure Boot change / **UEFI dbx (revocation list) update**
|
||||
> alters PCR 7 → the TPM refuses → boot falls back to the passphrase prompt (not a brick). After
|
||||
> such a change, re-run step 4's
|
||||
> `systemd-cryptenroll --wipe-slot=tpm2 --tpm2-device=auto --tpm2-pcrs=7 /dev/sda3` to re-bind, then
|
||||
> reboot to confirm unattended unlock returned.
|
||||
|
||||
### 4a. Firmware / UEFI dbx updates break PCR 7 — and are an OPERATOR threat (VERIFIED 2026-06-30)
|
||||
|
||||
The PCR-7 re-seal hazard above is **not** a rare event — the most common trigger is a **UEFI `dbx`
|
||||
(Secure Boot revocation database) update**, and it bit the real `park-buzi` booth on 2026-06-28:
|
||||
|
||||
- **What `dbx` is:** the Secure Boot blocklist of known-vulnerable bootloader/shim hashes
|
||||
(vendor = Microsoft). It is delivered by **`fwupd`/LVFS — a channel SEPARATE from APT** (the GNOME
|
||||
"Firmware Updater", which on Ubuntu is the **`firmware-updater` snap**, surfaces it). `apt list
|
||||
--upgradable` being clean does NOT mean a firmware/dbx update isn't pending.
|
||||
- **The GRUB panic (root cause):** applying a *new* dbx against a *stale* GRUB/shim revokes the
|
||||
installed bootloader → Secure Boot refuses to load it → **unbootable / GRUB "panic"**. The fix is
|
||||
ordering: `apt full-upgrade` (current `grub-efi`/`shim-signed`) FIRST, *then* dbx. A fresh reinstall
|
||||
ships a current GRUB, so reinstalling recovers it.
|
||||
- **It moves PCR 7:** even with a current GRUB, applying dbx changes the Secure-Boot-policy
|
||||
measurement → the TPM (slot 1) refuses to release the key → next boot **drops to the slot-0
|
||||
passphrase prompt**. Recover with the re-seal runbook above. VERIFIED: on `park-buzi` the dbx
|
||||
update went through, the box rebooted to a passphrase prompt, the slot-0 passphrase unlocked it,
|
||||
and `systemd-cryptenroll --wipe-slot=tpm2 … --tpm2-pcrs=7` restored silent auto-unlock.
|
||||
|
||||
**Threat-model consequence ([[threat-model]]: the operator is the adversary).** A firmware/dbx update
|
||||
on a TPM-sealed booth → the booth won't boot unattended and needs the slot-0 passphrase. So the
|
||||
operator must be unable to *trigger* a firmware update, and must never hold the passphrase. Lock it
|
||||
down (DONE on `park-buzi` 2026-06-30):
|
||||
|
||||
```bash
|
||||
# 1. Kill the firmware-update DAEMON (the GUI "Update" button then fails with no daemon):
|
||||
sudo systemctl mask fwupd.service fwupd-refresh.timer
|
||||
systemctl is-enabled fwupd.service fwupd-refresh.timer # → masked / masked (persists across reboot)
|
||||
|
||||
# 2. Remove the operator-facing GUI so the screen is never even presented (Ubuntu = a snap):
|
||||
sudo snap remove firmware-updater
|
||||
snap list | grep -i firmware # → no output (re-check: seeded snaps can re-install)
|
||||
```
|
||||
|
||||
Plus: the **BIOS admin password** (§1) must gate *entering setup / changing settings* (a
|
||||
supervisor/admin password, not just a boot password) so the operator can't disable Secure Boot or
|
||||
change boot order — either of which also breaks the seal. And the **slot-0 passphrase stays
|
||||
off-machine / escrowed** (same custody as `EVENT_SIGNING_KEY` / `BACKUP_KEY`); it is an admin-only
|
||||
recovery secret, used on-site during a maintenance window, never known to operators.
|
||||
|
||||
> **Net:** firmware/dbx updates become an **admin-only, on-site, deliberate** action. The booth is
|
||||
> unattended-bootable only while the firmware/Secure-Boot state is frozen — that is the security
|
||||
> property, not a bug. Legitimate firmware maintenance now costs: physical presence + the slot-0
|
||||
> passphrase + a PCR-7 re-enroll.
|
||||
|
||||
> **⚠ Gotcha — `cryptsetup … --test-passphrase` SILENTLY passes via the TPM.** Before any
|
||||
> firmware/dbx change, you must *prove a typed passphrase still unlocks the disk* (the TPM-independent
|
||||
> safety net). But `sudo cryptsetup open --test-passphrase /dev/sda3` with a TPM2 token enrolled will
|
||||
> succeed **without prompting** — the TPM auto-answers (it unlocks the tpm2 *slot*, e.g. slot 1), a
|
||||
> FALSE positive that proves nothing about a human-typeable key. Force a real test with
|
||||
> `--disable-external-tokens` (→ `No usable token is available.` then it prompts; success on slot 0 =
|
||||
> the passphrase genuinely works):
|
||||
> ```bash
|
||||
> sudo cryptsetup open --test-passphrase /dev/sda3 --disable-external-tokens --verbose
|
||||
> ```
|
||||
|
||||
## 5. GRUB password — EDIT-ONLY (VERIFIED 2026-06-23)
|
||||
|
||||
@@ -317,6 +375,16 @@ works; the desktop app is a separate workstream.
|
||||
6. GRUB password MUST be **edit-only** (`--unrestricted` on entries) or it prompts on EVERY boot →
|
||||
breaks unattended reboot. Verify `grep -c unrestricted /boot/grub/grub.cfg` ≥1 before rebooting.
|
||||
|
||||
### Firmware / dbx gotchas (2026-06-30, §4a)
|
||||
|
||||
12. **UEFI dbx ships via `fwupd`/LVFS, NOT APT.** `apt list --upgradable` clean ≠ no firmware update
|
||||
pending. A new dbx vs a stale GRUB → revoked bootloader → **unbootable / GRUB panic** (`apt
|
||||
full-upgrade` first, then dbx). And dbx **moves PCR 7** → breaks TPM auto-unlock → passphrase
|
||||
prompt → re-seal (§4 runbook). Mask `fwupd` + remove the `firmware-updater` snap so the operator
|
||||
can't trigger it.
|
||||
13. `cryptsetup … --test-passphrase` **silently passes via the TPM token** (false safety signal). Use
|
||||
`--disable-external-tokens` to actually force a typed-passphrase test before any firmware change.
|
||||
|
||||
### Komodo deploy gotchas (2026-06-27)
|
||||
|
||||
7. Periphery `core_address` is **Core's reverse-proxy URL** (`https://komodo.infra.msai.al`), NOT
|
||||
|
||||
Reference in New Issue
Block a user