Skip to main content
This is the real artifact: a bootable disk image that comes up as a configured Naive Tower. Locally we boot it under QEMU with a software TPM (swtpm), so systemd-cryptenroll PCR-7 sealing and the vault unlock run exactly as they will on NitroTPM or bare metal.

Prerequisites

  • qemu-system-x86_64, swtpm, packer, OVMF (UEFI firmware).
  • KVM makes this fast; on macOS it runs under QEMU TCG (works, slow).

1. Build the golden image

Packer runs the Ubuntu 24.04 autoinstall (ds=nocloud-net), lays down the GPT ESP / rootA / rootB / /data layout, installs Docker + gVisor (runsc), Tailscale (off), the preloaded image tarballs, and the firstboot units. Output: image/output/naive-tower.raw.

2. Boot it

On first boot you’ll watch:
  1. /data sealed to the TPMsystemd-cryptenroll --tpm2-pcrs=7 creates a LUKS2 volume bound to the vTPM and prints a one-time owner recovery key (store it). Subsequent boots auto-unlock; no passphrase.
  2. The region comes upnaive-region.service runs docker compose up with vaultd (reveal compiled out), the governor, api, gateway, and the runsc-sandboxed agent runtime.
  3. A claim QR + code rendered to the console by the device-agent.
curl http://localhost:3000/health returns 200 once /data is unlocked and the region is live.

3. Claim it against a local control plane

Run the CP (the API in cloud mode) on your workstation:
Scan the QR (or open the claim URL) and claim as the owner. KYC runs via Footprint; without a sandbox key set NAIVE_DEV_KYC_BYPASS=1 on the CP — a loud, logged, dev-only bypass that is refused in Tower/prod builds (the KYC leg is otherwise BLOCKED). The device polls, attests (PCR-7 quote; CP verification is beta), provisions, and comes up live in sandbox.

4. Prove it