feat(nb): enable lanzaboote secure boot with user-only keys #3
Labels
No labels
bug
enhancement
in-progress
needs-info
needs-triage
p0
ready-for-agent
ready-for-human
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Cloonar/nixos#3
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Enable Lanzaboote Secure Boot on nb-01
Sign the boot chain on nb-01 with user-only keys. Closes the evil-maid attack window that LUKS+FIDO2 alone leaves open. PCR-friendly baseline for future migration to TPM2+PIN LUKS unlock.
Decisions
uefi_capsuleplugin blocklisted. BIOS updates done via temporary SB-off window 2-3×/year.fetchTarballpinned to lanzabootev1.0.0, new filehosts/nb/modules/secure-boot.nix, host-scoped (notutils/). Inline values, nooptions/mkIf./var/lib/sbctladded toenvironment.persistence."/nix/persist/system".directories. No off-machine key backup.configurationLimit5 → 3 in step 1.Pre-flight
Rollout — progress
Step 1 — Prep (no behavioural change)
Lanzaboote module imported but disabled; persistence in place; ESP trimmed; fwupd capsule plugin blocklisted. Boot still systemd-boot. Fully rollback-able by reverting the commit.
hosts/nb/modules/secure-boot.nixwritten (lanzaboote pinned,enable = false,pkiBundleset)hosts/nb/configuration.niximports./modules/secure-boot.nix/var/lib/sbctladded to persistenceconfigurationLimit5 → 3 (vialib.mkForceinsecure-boot.nix, keeps SB changes encapsulated)DisabledPlugins = [ "uefi_capsule" ]addednixos-rebuild dry-buildpasses (./scripts/test-configuration nb)sudo systemctl stop bento-upgrade.timer(pause bento for rollout)sudo nixos-rebuild switch -I nixos-config=$(pwd)/hosts/nb/configuration.nixbootctl statusstill shows systemd-boot,ls /var/lib/sbctlexists,sbctl --versionworkscontinue lanzaboote step 2Step 2 — Bootloader swap (still SB disabled in firmware)
Flip lanzaboote on, force systemd-boot off. Lanzaboote takes over /boot but SB is not enforced yet (firmware still has factory keys, MS-trusted). Equivalent to systemd-boot operationally.
secure-boot.nix:boot.lanzaboote.enable = true,boot.loader.systemd-boot.enable = lib.mkForce falsenixos-rebuild dry-buildpassessudo nixos-rebuild switch, rebootbootctl statusshows lanzaboote stub, generation list visible in boot menuStep 3 — Create user keys
Generate PK/KEK/db keypairs in persisted
/var/lib/sbctl. Sign all existing UKIs. Firmware still trusts factory keys at this point.sudo sbctl create-keyssudo sbctl sign-all(or rebuild)sudo sbctl verify— every file in /boot should report "is signed"Step 4 — Firmware Setup Mode
Clear factory PK in firmware to enter Setup Mode (PK absent → firmware accepts new key enrolment).
sbctl statusreports "Setup Mode: ✓ Enabled"Step 5 — Enrol user keys
Write user PK/KEK/db to EFI variables. No
-m(no Microsoft).sudo sbctl enroll-keys(NO--microsoftflag)sbctl status— "Installed: ✓ sbctl is installed", "Setup Mode: ✗ Disabled", "Secure Boot: ✗ Disabled"Step 6 — Enable Secure Boot enforcement
Firmware now enforces against user keys.
bootctl statusshows "Secure Boot: enabled (user)"sbctl statusshows "Secure Boot: ✓ Enabled"Step 7 — Cleanup + commit
Rollback playbook
Detailed in [grill-me session]. Summary:
nixos-rebuild switch, reboot.secure-boot.nix(enable = false, dropmkForce false), rebuild, reboot./mnt, btrfs@/@nix-store/@nix-persistsubvols, FAT/boot→nixos-enter --root /mnt -- nixos-rebuild bootafter editing/nix/persist/system/etc/nixos/hosts/nb/modules/secure-boot.nix.References
Step 1 — files written and validated
Changes (uncommitted, local repo only):
hosts/nb/modules/secure-boot.nix— lanzaboote v1.0.0 imported,enable = false,pkiBundle = "/var/lib/sbctl", sbctl in systemPackages,configurationLimitforced to 3, fwupduefi_capsuleplugin blocklisted.hosts/nb/configuration.nix— imports the new module; adds/var/lib/sbctltoenvironment.persistence."/nix/persist/system".directories.Validated:
./scripts/test-configuration nbsucceeds (dry-build, no eval errors).Operational impact when applied: none. Lanzaboote module is dormant (
enable = false); only side effects are a new empty/var/lib/sbctldir on the persisted disk,sbctlin$PATH, and fwupd skipping the uefi_capsule plugin.What the USER does next
This rollout uses local
-I nixos-config=...rebuilds (no commits to repo until step 7) to keep half-baked states out of bento's sync loop.1. (Recommended) Pause bento sync for the rollout
Bento's 15-minute auto-upgrade timer could clobber a local rebuild with an older
/var/bento/configuration.nix. Stop it for the duration:We'll re-enable it in step 7.
2. Apply step 1
From the repo root:
First build will fetch the lanzaboote v1.0.0 tarball (one-time, ~5MB). Should not need to build
lzbt— withboot.lanzaboote.enable = false, the package is never demanded.3. Reboot
4. Verify after reboot
5. Re-launch claude and say
continue lanzaboote step 2I'll pick up from the issue at
git.cloonar.com/Cloonar/nixos/issues/3and execute step 2 (the actual bootloader swap).Rollback if step 1 reboot fails
This is unlikely (no behavioural change), but:
cd repo && git checkout hosts/nb/configuration.nix && rm hosts/nb/modules/secure-boot.nix && sudo nixos-rebuild switch -I nixos-config=$(pwd)/hosts/nb/configuration.nix.Snag during step 1 deployment — claude-code build failure (resolved, not lanzaboote-related)
Bento rebuild failed on first attempt with cascading dep failures rooted in
claude-code:Root cause: upstream nixpkgs rewrote
claude-codebetween channel commits25.11.10830(last successful build, Oct 2025) and25.11.11112(current). New upstream uses binary distribution +installBin $src(expects a binary file). Our custom override atutils/pkgs/claude-code/overridessrcto a directory (srcWithLock) — structurally incompatible.Fix: commented out the
claude-code = self.callPackage ...line inutils/overlays/packages.nix. Fleet uses upstream's 2.1.140 (binary) instead of pinned 2.1.111 (npm). If we ever need to pin again, rewriteutils/pkgs/claude-code/default.nixto fetch from the GCS binary URL.Side effects:
nb-01,dev(both importutils/modules/development) get claude-code 2.1.140 instead of 2.1.111.fwunaffected (only had"claude-code"inallowUnfreePredicate, doesn't install it)../scripts/test-configuration nbpasses. Combined commit for step 1 + claude-code fix.