Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

18 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Vanguard Logo

Vanguard

A minimal, security-focused initramfs generator for Linux systems with full disk encryption. Written in Go, Vanguard creates lightweight boot images optimized for LUKS + LVM + TPM2 setups with PCRLock boot integrity enforcement.

Features

  • Full Disk Encryption — LUKS2 with TPM2 automatic unlock via systemd-cryptenroll
  • Native Go TPM2 — Zero external dependencies; uses google/go-tpm for sealed key unseal with traditional PCR policy and PolicyAuthorizeNV (pcrlock)
  • Native Go LUKS — LUKS v1/v2 header parsing, Argon2/PBKDF2 key derivation, and dm-crypt mapper setup via ioctl — no libcryptsetup required at runtime
  • TPM2 Integration — Automatic token detection, PIN support, PCRLock policy binding with multi-branch PCR prediction (PolicyOR)
  • LVM Support — Full LVM2 volume group and logical volume activation with persistent symlinks across switch_root
  • Non-Root Filesystem Mounting — Mounts /home and other non-root filesystems from fstab before switch_root, bypassing udev database corruption issues
  • Boot TUI — Bubble Tea-based terminal UI with spinner, stage progress, and password/PIN prompts during boot
  • GPT Autodiscovery — Automatic root partition detection using Discoverable Partitions Specification
  • Hibernate/Resume — Support for resuming from encrypted swap (inside LUKS+LVM)
  • Filesystem Check — Optional fsck before mounting root
  • Vconsole Support — Keyboard layout and console font configuration for password prompts
  • Minimal Footprint — Only includes binaries and modules needed for your configuration
  • Fast Boot — zstd compression, parallel device scanning
  • Self-contained — CLI embeds pre-built init binaries; no CGo in init

Screens

Vanguard Boot TUI

Quick Start

# Build from source
git clone https://github.com/zaolin/vanguard
cd vanguard
make

# Check system protection status
sudo ./vanguard status

# Generate initramfs
sudo ./vanguard generate -o /boot/initramfs-linux.img

# With debug output enabled
sudo ./vanguard generate -o /boot/initramfs-linux.img --debug

# Strict mode — token-only unlock, no passphrase fallback
sudo ./vanguard generate -o /boot/initramfs-linux.img -s

Documentation

Document Description
Boot Flow Detailed initramfs boot sequence
Configuration CLI options and config file format
TPM2 Setup TPM2 enrollment and PCRLock guide
Kernel Parameters Supported kernel command line options

Commands

generate

Generate an initramfs image:

vanguard generate -o /boot/initramfs-linux.img [options]
Option Description
-o, --output Output path (required)
-f, --firmware Comma-separated firmware files
-m, --modules Comma-separated kernel modules
-c, --compression zstd, gzip, or none (default: zstd)
-d, --debug Enable verbose boot output
-s, --strict Strict mode: token-only unlock, no passphrase fallback
--config Path to TOML config file

update

Update TPM2 PCRLock policy for secure boot:

vanguard update -u /boot/EFI/Gentoo/kernel.efi [options]
Option Description
-u, --uki-path Path to UKI file (required)
-p, --policy-output Output path for policy JSON (default: <uki-path>.pcrlock.json)
-l, --luks-device LUKS device for token verification (enables GPT binding on PCR 5)
--no-gpt Disable GPT partition table binding (PCR 5)
--no-verify Skip policy verification
-v, --verbose Show verbose output from pcrlock tools
-c, --cleanup Remove old unused pcrlock NV indices from TPM

What it does:

  1. Configure masks — Masks noisy/unpredictable PCR components (firmware code/config, OS separator, NV-PCR separator, machine ID, root filesystem, shutdown, final). These systemd-specific components expect userspace PCR measurements that vanguard's custom init does not produce; unmasked they cause systemd-pcrlock make-policy to drop all PCRs from the protection mask.
  2. Regenerate firmware components — Runs systemd-pcrlock lock-firmware-code and lock-firmware-config (or the Varlink Lock method on systemd 262+) to refresh stale /var/lib/pcrlock.d/250-firmware-*-early.pcrlock.d/generated.pcrlock files from the current boot's event log. Without this, stale firmware components cause a cascade that drops all PCRs including PCR 7.
  3. Lock Secure Boot — Runs lock-secureboot-policy + lock-secureboot-authority (or Varlink Lock) to generate PCR 7 component files from current Secure Boot state.
  4. Lock GPT (with -l) — Binds the policy to the disk's GPT partition layout (PCR 5).
  5. Lock UKI — Creates multi-branch PCR 4 predictions for the UKI (lock-pe + lock-uki + event log extraction).
  6. Make policy — Runs systemd-pcrlock make-policy to generate the final policy JSON with a recovery PIN.
  7. Verify — Checks that required PCRs (7, and optionally 5) are present in the generated policy.

verify

Verify TPM2 pcrlock setup (PCRs, NV Index, LUKS token):

vanguard verify -p /boot/pcrlock.json [options]
Option Description
-p, --policy-path Path to pcrlock.json policy file (required)
-l, --luks-device LUKS device to verify (optional)

This checks:

  1. NV Index synchronization (TPM matches policy file)
  2. Current PCR values against policy expectations
  3. LUKS token validation (when -l specified)

status

Show system protection status with security layering:

vanguard status [options]
Option Description
--json Machine-readable JSON output
-v, --verbose Show full PCR hash values

Shows protection tier (HIGH/MEDIUM/LOW/WARNING), LUKS encryption status, TPM 2.0 presence and lockout state, PCRLock boot integrity with per-PCR classification (enforced/unbound), and Secure Boot (PCR 7) detection.

Architecture

Vanguard has a dual-binary design:

  • cmd/vanguard/ — CLI tool running on the build host, generates initramfs images
  • init/ — Init binary running inside the initramfs at boot (19-step sequence)
  • internal/ — Shared libraries: native Go TPM2 client, native Go LUKS implementation, CPIO archive writer, compression, pcrlock integration

Build produces 4 init variants via Go build tags from a single source tree:

Tag(s) Binary Behavior
(none) init Release: minimal output, passphrase fallback
debug init-debug Verbose output for troubleshooting
strict init-strict Token-only unlock, no passphrase fallback
debug,strict init-debug-strict Verbose + strict mode

The generator outputs a chained CPIO: an uncompressed early archive for firmware (available to built-in kernel drivers) followed by a zstd/gzip-compressed main archive. All init binaries are statically linked (CGO_ENABLED=0) with zero runtime dependencies.

No external binaries needed at boot — LUKS unlock and TPM2 operations use native Go implementations. The only external binaries included in the initramfs are lvm (for LVM activation), systemd-udevd/udevadm (device management), and dmsetup (DM rules).

Configuration File

Create /etc/vanguard.toml:

output = "/boot/initramfs-linux.img"
compression = "zstd"
debug = false

firmware = [
    "amd/amd_sev.fw",
    "amdgpu/vangogh_sos.bin",
]

modules = [
    "nvme",
    "xhci_pci",
]

Typical Setup

1. Partition Layout

/dev/nvme0n1
├── /dev/nvme0n1p1  ESP (FAT32, ~512MB)     — EFI System Partition
└── /dev/nvme0n1p2  LUKS encrypted           — Contains LVM
    └── LVM PV
        └── VG: gentoo
            ├── LV: root (ext4/xfs)
            ├── LV: home (ext4/xfs)
            └── LV: swap

2. Enroll TPM2

# Generate PCRLock policy (Secure Boot + UKI + GPT binding)
sudo vanguard update -u /boot/EFI/Gentoo/kernel.efi -l /dev/nvme0n1p2

# Enroll TPM2 token with pcrlock binding
sudo systemd-cryptenroll --wipe-slot=tpm2 --tpm2-device=auto \
  --tpm2-with-pin=yes \
  --tpm2-pcrlock=/boot/EFI/Gentoo/kernel.pcrlock.json \
  /dev/nvme0n1p2

3. Generate Initramfs

sudo vanguard generate -o /boot/initramfs-linux.img

4. Kernel Command Line

root=/dev/gentoo/root resume=/dev/gentoo/swap

See docs/kernel-parameters.md for all supported parameters.

5. Verify Protection Status

sudo vanguard status

Boot Sequence Overview

┌──────────────────────────────────────────────────────────────────┐
│   1. Console Setup          Set up early console I/O             │
│   2. Mount Filesystems      /proc, /sys, /dev, /run              │
│   3. Vconsole Config        Load keyboard layout/font            │
│   4. Mount /boot            Mount boot partition for policy      │
│   5. Init Boot Log          Start logging to /boot               │
│   6. Start udevd            Device discovery daemon              │
│   7. Load Modules           Kernel modules from image            │
│   8. Trigger udev Events    Firmware loading                     │
│   9. Load TPM Modules       tpm_crb, tpm_tis, tpm_tis_core      │
│  10. Setup PCRLock          Copy pcrlock.json for TPM2           │
│  11. Unlock LUKS            TPM2 → PIN → Passphrase              │
│  12. Activate LVM           Scan and activate volumes            │
│  13. Try Resume             Hibernate resume from swap           │
│  14. Find Root Device       cmdline → fstab → GPT autodiscovery  │
│  15. fsck                   Check root filesystem                │
│  16. Mount Root             Mount to /sysroot                    │
│ 16a. Mount Non-Root FS      Mount /home etc. from fstab          │
│ 16b. LVM Symlinks           Create persistent symlinks           │
│  17. Cleanup udev           Settle, trigger graphics, stop       │
│  18. Close Boot Log         Close log, unmount /boot             │
│  19. Switch Root            Hand off to real init                │
└──────────────────────────────────────────────────────────────────┘

See docs/boot-flow.md for detailed documentation.

Requirements

Build Requirements:

  • Go 1.25+
  • make

Runtime Dependencies (included in initramfs):

  • lvm2
  • systemd-udevd
  • systemd-pcrlock (for policy generation only, not runtime)

Optional (for fwupd coexistence on systemd 262+):

  • systemd 262+ — enables the io.systemd.PCRLock Varlink interface for Lock/MakePolicy calls. On older systemd, vanguard falls back to the systemd-pcrlock CLI automatically.
  • fwupd 2.1.7+ — the systemd-pcrlock fwupd plugin loosens systemd's pcrlock policy before firmware updates. Vanguard's policy is separate (different NV index) and must be regenerated manually before rebooting after a firmware update.

No external TPM or LUKS dependencies — Vanguard's init binary uses native Go implementations for all crypto and TPM2 operations.

Testing

# Run QEMU test with software TPM
./scripts/qemu-test.sh all-tpm

# Individual steps
./scripts/qemu-test.sh build       # Build initramfs
./scripts/qemu-test.sh disk        # Create test disk
./scripts/qemu-test.sh enroll-tpm  # Enroll TPM2 token
./scripts/qemu-test.sh tpm         # Boot with TPM

# Unit tests (no TPM hardware required)
go test ./internal/pcrlock/... -v  # Varlink client + pcrlock integration
go test ./internal/tpm/... -v      # TPM2 policy computation + auth
go test ./internal/luks/... -v     # LUKS header parsing
go test ./init/... -v              # Init token parsing

Security Features

Protection Layers

Layer Mechanism
Disk Encryption LUKS2 (aes-xts-plain64 or aes-xts-essiv:sha256) with Argon2id/PBKDF2 key derivation
TPM Binding Sealed keys bound to TPM with PCR policy enforcement
PIN Protection PBKDF2-derived authentication value for TPM2 tokens
Boot Integrity PCRLock with PolicyAuthorizeNV — enforces expected PCR values before unlock
Strict Mode Disables passphrase fallback when TPM2 token is present
Process Isolation Static Go binary init (CGO_ENABLED=0) — no dynamic linking vulnerabilities
Minimal Surface Only essential binaries and modules included; no interpreters or package managers

PCR Coverage

PCR Name Enforcement
2 external-code ✓ Enforced
3 external-config ✓ Enforced
4 boot-loader-code ✓ Enforced (multi-branch PolicyOR)
5 GPT partition table Optional (-l flag)
7 secure-boot-policy ✓ Enforced
13 sysexts — Unbound (all-zeros)
14 shim-policy — Unbound (all-zeros)
  • TPM dictionary attack lockout detection prevents brute-force PIN attacks
  • Kernel message suppression during password entry
  • Passphrase fallback with 3 attempts before halt (unless strict mode)
  • Boot logging to /boot/.vanguard.log for audit trail

License

MIT License — see LICENSE for details.

Contributing

Contributions welcome! Please open an issue or pull request on GitHub.

About

A minimal, security-focused initramfs generator for Linux systems with full disk encryption. Written in Go, Vanguard creates lightweight boot images optimized for LUKS + LVM + TPM2 setups.

Resources

Stars

Watchers

Forks

Releases

Contributors

Languages