initos is a minimal, unified boot tool and initialization sequence for early host setup. It replaces complex, bloated, machine-specific initramfs systems (like dracut) with a single, easily auditable Rust binary.
By integrating UEFI Secure Boot, fs-verity, and TPM2 policies, it decouples the bootloader and kernel from the host OS, providing a container-like read-only environment to run any Linux distribution.
The goal is to simplify verified boot for common physical machines, replacing the usual Initrd (dracut, etc) with a minimal and easier to understand and review boot process. Minimal is the key, keep only features that can't be removed.
The boot chain establishes a secure path from the UEFI firmware up to the execution of the target operating system:
graph TD
subgraph UEFI Boot Stage
A["UEFI Firmware (Secure Boot)"] -->|Loads & Verifies| B["EFI Loader (efi.rs)"]
B -->|Verifies signature against DB cert| C["Kernel & Commandline (bzImage)"]
end
subgraph Initrd Stage (PID 1)
C -->|Executes /init| D["initos (initos-init)"]
D -->|Mounts| E["Pseudo-FS (proc, sysfs, devtmpfs)"]
D -->|Scans by label| F["STATE Partition (ext4)"]
D -->|Verifies fs-verity signature| G["Read-Only OS Image (initos.erofs)"]
G -->|Loop-mounts as EROFS| H["Verified Rootfs (/mnt/root)"]
H -->|Bind-mounts STATE| I["STATE at /z"]
I -->|Handover| J["switch_root"]
end
subgraph OS Stage
J --> K["Real OS (Debian, Alpine, etc.)"]
K -->|TPM2 Policy / fscrypt| L["Decrypt Writable Overlay / Home"]
end
┌──────────────────────────────────────────┐
│ EFI Loader (src/bin/efi.rs) │
│ · Reads /EFI/BOOT/config │
│ · Verifies config signature using db │
│ · Loads/Verifies kernel using db cert │
│ · Handover to Linux kernel │
└────────────────────┬─────────────────────┘
│
┌────────────────────▼─────────────────────┐
│ initos / initos-init (PID 1) │
│ ┌─────────────────────────────────────┐ │
│ │ mount.rs │ │
│ │ · mount_pseudo_fs (proc/sys/dev) │ │
│ │ · find_partition_by_label (STATE) │ │
│ │ · mount_ext4 / mount_loop │ │
│ │ · switch_root │ │
│ └─────────────────────────────────────┘ │
│ ┌─────────────────────────────────────┐ │
│ │ verity.rs │ │
│ │ · measure_verity (ioctl) │ │
│ │ · digest_to_hex │ │
│ └─────────────────────────────────────┘ │
│ ┌─────────────────────────────────────┐ │
│ │ verify.rs │ │
│ │ · verify_signature (Ed25519) │ │
│ │ · verify_image │ │
│ └─────────────────────────────────────┘ │
└──────────────────────────────────────────┘
- Zero-Trust Boot Chain: Validates everything from the UEFI Secure Boot DB keys all the way up to the filesystem blocks using fs-verity Merkle trees.
- Host Portability: Replaces machine-specific ramdisks. The same static
initosinitrd binary works across all physical servers - Frictionless Upgrades: Upgrading the OS is as simple as copying an
.erofsimage and its accompanying.sigsignature to the STATE partition. - Hardware Cryptography: Out-of-the-box support for TPM2 sealing (locked to PCR 7 policies with automatic anti-replay extension lockout) and fscrypt-based folder encryption.
- Auditable & Small: Written in Rust with minimal dependencies, replacing thousands of lines of shell scripting in standard initramfs generators.
- Firmware Stage: The UEFI firmware executes
initos.EFI(built fromsrc/bin/efi.rs). The loader reads the kernel command line from\EFI\BOOT\configand verifies its signature (config.sig) against the Secure Bootdbcertificate. It then verifies and executes the kernel (bzImageandinitrd.img). - Mounting Pseudo Filesystems: Upon initrd start,
initosis executed as PID 1. It mounts/proc,/sys, and/dev. - Partition Discovery:
initosscans block devices in sysfs for a partition or EXT4 volume labeledSTATEand mounts it as /z. - fs-verity Verification: Once mounted, it measures the EROFS system image (
img/initos.erofs) and validates its cryptographic hash against the signature file (initos.erofs.sig) using a public key passed via kernel command lineINITOS_PUB_KEY. - Switch Root: The image is loop-mounted, the
STATEpartition is bind-mounted at/zinside the new rootfs, andinitosperforms aswitch_rootto run the OS init (defaults/opt/initos/bin/initos-init-ver-INITOS_INITcommand line override).
A standard installation expects the following drive partitions:
| Partition Name | Typical Size | Filesystem | Purpose |
|---|---|---|---|
BOOTA |
32 MB | VFAT | Active UEFI Boot (Kernel, Loader, Configs) |
BOOTB |
32 MB | VFAT | Alternate UEFI Boot (A/B updates) |
STATE |
100+ GB | EXT4 | Contains read-only system images and encrypted user data |
/img/— Read-only EROFS images (e.g.,initos.erofs, kernel modules, firmware)/c/—fscrypt-encrypted directory for home directories, mutable settings, and distro overlays.
initos provides tools to manage images, encryption, and TPMs.
Run initos help to list all subcommands:
initos verify <IMG>: Verify an image against its signature usingINITOS_PUB_KEY.initos mount <IMG> <DIR>: Cryptographically verify and loop-mount an EROFS image.initos primary: Create an RSA-2048 primary storage key in the TPM owner hierarchy.initos seal <SECRET>: Seal a key to the TPM under PCR SHA256:7.initos unseal: Unseal the TPM secret to stdout.initos lock_tpm: Extend PCR 7 with random data to prevent further unsealing during this boot.initos fscrypt-setup <DIR>: Setup v2 encryption policy on a directory.initos encrypt/decrypt: Multi-recipient age/X25519-compatible encryption.
The project uses a containerized runtime environment via cctl to build and test the boot sequence cleanly:
# Setup the debian container
./scripts/container_build.sh initos_dev
# Build all binaries & images inside the container
./scripts/container_build.sh build
# Run tests
POD=initos_dev cctl cargo test -p initos
# Boot and verify the images inside QEMU with a simulated TPM2
POD=initos_dev cctl bash -lc 'TIMEOUT=90 tests/run_qemu.sh'The main reason for writing this is that I got too frustrated with having to deal with Grub and Dracut and the general model of Linux booting - where each machine has to create its own init image that only work on that machine. Security is so complicated and likely to fail that few bother - and the fundamental design of having each host deal with signing and building the boot image is IMO fundamentally flawed.
-
The EFI DB is critical to verify the EFI - zero trust in distributions, so my own key sigining EFI. I can also use the same key to sign kernel, cmdline and the images. Custom EFI loader is used instead of Limine for better secure boot integration and minimal features - the EFI doesn't need to be recompiled or patched with keys. UKI EFI has no clear benefits - looked pretty closely and complexity is not worth it.
-
minimum and optional initrd - only verifies rootfs image with fsverity, using the public key from the signed config file. This also works as a separate dm-verity partition - but a bit more complicated. Scripts create this as well.
-
We need a writable disk anyway - ext4 has fsverity/fscrypt and good enough for a STATE partition holding signed images, signed configs and encrypted home and configs. Additional btrfs/LVM/etc disks can be used as needed.
-
Small A/B partitions for EFI. The EXT4 parititon hold versioned images, modules and everything else.
-
using fsverity/fscrpt is useful post boot for a lot of other use cases, more dynamic. Upgrades involve just copying files.
-
the model works well with central build system - where all signing happens. All other machines just get signed images and signed configs.
Spent a lot of time to get TPM/2 work - but I think it is only useful for unattended server reboot. For laptops - entering a password after boot is not a huge effort.
-
Limine is a relatively minimal boot loader that works well. The config, initrd can be signed along with the bootloader, it works pretty well.
-
Using a linux kernel with initrd and command line built in (compling the kernel after the initrd is generated) is also possible and avoids an extra step. It assumes kernel doesn't accept additional command line options.
-
I wrote (with LLM help) a very minimal loader, using the DB key (same key used to sign the EFI) to also sign kernel/config - to simplify the steps and allow them to be updated independently of the EFI (not the case with limine). Works well - except on one old laptop.
Either one seems to work fine and make different tradeoffs.
The boot partitions only holds the kernel, bootloader and configs (in option 2 - only the kernel as EFI/BOOT/BOOTX64.EFI).
Assuming 2 ESP boot partitions (BOOTA and BOOTB) this can be updated safely by replacing the entire parition with a new image.