Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Architecture

The high-level view: what keyboot is, what it isn’t, and where it sits relative to GRUB and the booted OS. Extracted from SPEC §3/§4; the locked design decisions live in CLAUDE.md and decisions/ (the ADRs). Start here, then read unlock-flow.md for the mechanism.

What keyboot is

A greenfield boot stage that runs after GRUB and before the target OS’s init. In one boot it:

  1. decrypts an age-of-LUKS keyfile container inside its own initramfs,
  2. uses that keyfile’s payload to open every LUKS device backing the root zpool,
  3. imports the pool,
  4. lets the operator pick a boot environment (TTY or SSH),
  5. kexecs into that BE’s own kernel + initrd (the ZBM model).

The same artifact, selected by keyboot.mode= on the kernel cmdline, is also a netbootable rescue shell, an unattended installer, and a memtest launcher:

keyboot.mode=role
bootthe normal unlock → import → pick BE → kexec path
rescuefull ZFS+LUKS toolkit + memtester, interactive shell
installunattended installer (partition → keyfile → pool → BE → distro)
provisionunlock + import read-writeinstall-os --add-be shell
memtestkexec the ESP-staged memtest86+ (ADR 0014)

It targets Gentoo (openrc), Debian (systemd), and Alpine (openrc), on UEFI and BIOS-MBR.

What keyboot is NOT

  • Not the bootloader. GRUB stays. keyboot is a kernel+initramfs GRUB boots like any other entry; it never replaces GRUB.
  • Not a fork. Greenfield, not a patched ZBM/dracut/genkernel — those are reference points only (SPEC §3).
  • Not the init. It hands off (kexec) to the BE’s own kernel + init; it does not switch_root into the OS.
  • Not re-done by the OS. The booted OS does no LUKS or ZFS-import work — keyboot already opened the disks and (via the post-kexec payload handoff) the BE just re-opens + mounts. No legacy ZFS mounts in any supported distro.

Where it fits

firmware (UEFI / BIOS-MBR)
  └─ GRUB                         ← stays the bootloader; one entry = keyboot
       └─ keyboot  (its own kernel + initramfs)
            stage 1-9: unlock → import → pick BE → kexec
            └─ kexec  ──▶ the BE's OWN kernel + initrd
                              └─ BE initramfs: keyboot be-unlock (re-open + mount)
                                   └─ the distro's init (systemd / openrc)

The GRUB seam

keyboot owns its artifacts; the distro owns grub.cfg. keyboot-install install places /boot/keyboot-vmlinuz + /boot/keyboot-initramfs.img and drops an executable /etc/grub.d/10_keyboot snippet, so the distro’s own grub-mkconfig emits a menuentry 'keyboot'. On a keyboot-owned ESP (install-os) the grub.cfg is rendered directly. Either way keyboot stays one entry inside GRUB.

The three environments (keep them straight)

A keyboot host has up to three distinct ZFS/LUKS contexts — see hetzner-deploy.md:

  1. keyboot’s unlock env — its own lockstep kernel + zfs.ko + the keyfile. Imports read-only, briefly. Small uniform ARC (ADR 0011).
  2. the booted OS / BE — the distro’s kernel + zfs.ko, the real workload, production ARC.
  3. (transient) a vendor/USB rescue — only for the one-time bootstrap; after install, keyboot’s own provision mode is the rescue (the “ENV-as-rescue” vision).

The architectural pillars (locked decisions, SPEC §3)

  • Unlock = a LUKS1 keyfile container, not age. Its 32-byte payload is the AES-256 key for every data disk; multi-slot (daily/recovery/automation). LUKS1 for the container and the disks. See unlock-flow.md, SPEC §7.
  • Handoff = kexec into the BE’s kernel (ADR 0003): the 32-byte payload is carried RAM-only across the kexec so the BE re-unlocks with a single prompt; keyboot.handoff=0 falls back to an independent dropbear-over-SSH re-unlock (ADR 0002).
  • Devices open as sn-<serial> so pool topology survives bus reordering; one Rust source for serial discovery, shared install-time and boot-time.
  • A/B ESP slots for keyboot itself (ADR 0009): two slots + a decrement-before-boot trial counter → a bad keyboot upgrade auto-reverts. The GL#44 one-shot provision builds on this.
  • BE discovery enumerates any mountable dataset; no enforced layout. BE rollback is a pre-boot three-rung ladder (ADR 0007).
  • ZFS in lockstep with upstream OpenZFS; keyboot’s embedded ZFS is the pool feature floor — upgrade keyboot before bumping pool features (ADR 0004).
  • Delivery = CI-signed native packages (apk/ebuild/deb) in our own repos + a signed rescue USB; ansible manages the repo definitions (ADR 0008).

The pieces

PathWhat
init/the /init entrypoint + numbered stages 1-9 + lib/ helpers (the unlock env runtime)
tools/keyboot/the Rust core: keyboot (runtime: discover/unlock/be-unlock/slot-commit) + keyboot-install (installer: keyfile/partition/install/install-os/keyboot-slots)
tools/keyboot-install-os/the install-os orchestrator (busybox/bash) + per-distro plugins + lib/
tools/keyboot-be-*the BE-side lifecycle tools (autosnap, upgrade, rollback)
kernel/, zfs/the embedded LTS kernel + the lockstep OpenZFS build
pkg/, ci/native packaging + the build / QEMU / signing pipeline

Design invariants (do not break)

  • The decrypted keyfile/payload is RAM-only — tmpfs, never non-volatile storage, the cmdline, dmesg, or a crashdump; zeroed after use.
  • GRUB stays the bootloader; keyboot is never it.
  • The target OS does no LUKS/ZFS re-work; no legacy ZFS mounts.
  • Disk-serial discovery has a single source (the Rust code), shared by install and boot.

See: unlock-flow.md, operator-guide.md, disaster-recovery.md, decisions/ (the ADRs), and SPEC.md (the design of record).