Home / Docs / Measured boot

Don't trust,
verify.

A Blackbox VM with measured boot never boots from its own disk. The firmware, the kernel, the initramfs that asks for your passphrase and the command line that carries your SSH key are all part of the AMD SEV-SNP launch measurement, and every one of them is rebuilt byte for byte from public sources. This page is how you check.

01 The hole this closes

SEV-SNP encrypts a VM's memory with a key the host never holds, and the CPU signs a launch measurement: a hash of everything loaded into the VM before it started. On an ordinary confidential VM that "everything" is the firmware and nothing else. The bootloader, the kernel and the initramfs live on the guest's own unencrypted /boot partition, which the host can rewrite whenever it likes. The initramfs is the program that asks for your LUKS passphrase. A host that swaps it for one that also emails the passphrase home has defeated the disk encryption without ever touching encrypted memory. That is the standard state of confidential VPS hosting, ours included until this release.

Measured boot removes the guest's disk from the boot path entirely. QEMU hands the firmware a kernel, an initramfs and a command line over fw_cfg with kernel-hashes=on; their SHA-256 hashes are written into a page that is part of the launch measurement, and the firmware is the AmdSevX64 build of OVMF, the one build that refuses to run a blob whose hash is not in that page and that cannot boot from disk at all. The page is filled by the host at launch, so the firmware check alone proves nothing to you; what proves it is that the page is measured, and the measurement is signed by the CPU. Change one byte of the initramfs and the launch measurement changes, and the CPU-signed report says so; nothing the host does can produce the published number for anything but the published bytes. Change nothing and the measurement is a number you can compute at home.

02 What is measured

  • Firmware: OVMF.amdsev.fd, built from edk2 OvmfPkg/AmdSev/AmdSevX64.dsc at a pinned tag with a pinned Debian toolchain.
  • Kernel: vmlinuz, extracted unmodified from Debian's signed linux-image package. The package hash is in the release manifest; fetch the same package from snapshot.debian.org and compare.
  • Initramfs: initrd.img, built with mkinitramfs from packages pinned to one snapshot.debian.org timestamp plus the scripts in the source tree. Two builds give identical bytes.
  • Command line: the exact string shown on your server's panel. It carries cryptopts= (where the LUKS root is), ip=, and bb.* parameters: your SSH public key, your addresses, your hostname and the instance id. Because it is measured, nobody can add a key to it without changing the number you check.
  • vCPU state: one initial register file per vCPU, so the count matters; the panel states it.
  • Guest policy: 0x30000: SMT allowed, debugging off, no migration agent. The verifier rejects anything else.

Not measured, on purpose: your root filesystem, which is yours and encrypted with a passphrase we never see. No seed ISO is attached to a measured VM at all; the initramfs writes the cloud-init seed from the measured command line.

03 How the initramfs proves itself

The initramfs is public and identical for every customer, so it cannot carry an SSH host key. On every boot it generates a fresh ed25519 key, requests an SNP attestation report from the CPU with REPORT_DATA set to the SHA-256 of that key, and serves the report in the SSH banner and through the attest command. OpenSSH shows you that same SHA-256 as the host key fingerprint. So: if the report's signature chains to AMD's root, its measurement equals the one you computed, and its REPORT_DATA equals the fingerprint your client just displayed, then the machine holding that key is a genuine SNP guest running exactly this image, and nothing in between can read what you type into it.

Every SSH login into the initramfs lands in a forced command with four verbs: attest (the report and its context as JSON), report (the raw report), unlock and encrypt. Password logins are disabled at build time; the only key allowed in is the one on the measured command line.

04 Verify before the passphrase

On any machine with Python 3, OpenSSH and internet access (the verifier fetches your VM's VCEK certificate from AMD's key server):

pip install sev-snp-measure cryptography
curl -sSO https://servury.com/downloads/blackbox/blackbox-verify
REL=2026.09
mkdir $REL && cd $REL
for f in OVMF.amdsev.fd vmlinuz initrd.img RELEASE.json SHA256SUMS; do curl -sSO https://servury.com/downloads/blackbox/$REL/$f; done
sha256sum -c SHA256SUMS && cd ..

python3 blackbox-verify --host YOUR.VM.IP --release ./$REL --vcpus 2

The verifier fetches the attestation over SSH with a throwaway known-hosts file, keyscans the host key itself, parses the report, checks the policy, checks that REPORT_DATA is the SHA-256 of the key on the wire, recomputes the launch measurement from the release directory and the command line the VM reports, and verifies the ECDSA P-384 signature against the VCEK certificate chained to AMD's ASK and ARK. It prints PASS and a known_hosts line you can pin for this boot, or FAIL with the reason. On FAIL, do not type a passphrase; the VM is not what it claims to be, and we would like to hear about it.

Nothing here relies on the panel. The panel shows the expected measurement and the command line for convenience, but the verifier computes both from what you downloaded and what the VM said, and the vCPU count is the only thing you take from us, which a wrong value can only make fail.

One detail for anyone scripting this themselves: the firmware's kernel loader appends initrd=initrd to what the guest sees in /proc/cmdline. The hash in the measurement covers the command line as QEMU passed it, without that suffix, and the verifier strips it.

By hand, without the tool: sev-snp-measure --mode snp --vcpus N --vcpu-type EPYC-v4 --guest-features 0x1 --ovmf OVMF.amdsev.fd --kernel vmlinuz --initrd initrd.img --append '<command line>' must print the measurement field of the report, and snpguest verify or any SNP report verifier of your choice checks the signature.

05 First boot: encrypt

A measured VM boots straight into the initramfs and waits. Nothing from its disk has run. Verify as above, then:

ssh root@YOUR.VM.IP encrypt

The script asks for a passphrase once (and its confirmation), checks the filesystem, shrinks it to make room for the LUKS2 header, encrypts the root partition in place (aes-xts-plain64, 512-bit key, argon2id), grows the partition and the LUKS volume to the whole disk, expands the filesystem, writes crypttab and fstab inside the encrypted root, and then lets the boot continue straight into your system with the volume it just opened. It refuses to claim success unless LUKS is really on disk, restores the filesystem size if anything fails before encryption, and resumes an encryption that was interrupted by a dropped connection. Choose a passphrase you can keep: it cannot be recovered by anyone, including us.

Every later boot stops in the initramfs with a new host key: verify again, then ssh root@YOUR.VM.IP unlock, enter the passphrase, and the system boots. Once running, the machine is a normal Debian or Ubuntu with your SSH key from the measured command line, its network configured by cloud-init from the seed the initramfs wrote, and a copy of the boot-time report at /run/blackbox/attest.json.

Type the passphrase only over SSH after a PASS. The serial console and the VNC console pass through the host like on any VM; they are there for you to watch the boot, not to type secrets into.

06 Rebuild everything yourself

The source tree for every release is published next to the artifacts (blackbox-images-RELEASE.tar.gz). On any Debian 13 machine with root and mmdebstrap:

tar xzf blackbox-images-$REL.tar.gz && cd blackbox-images
sh build/mkchroot.sh                       # pinned snapshot.debian.org chroot
git clone --depth 1 --branch edk2-stable202505 https://github.com/tianocore/edk2 /var/tmp/bb/src/edk2
git -C /var/tmp/bb/src/edk2 submodule update --init --depth 1 --recursive
cp build/build-firmware.sh build/build-initramfs.sh /var/tmp/bb/chroot/usr/local/bin/
build/in-chroot.sh sh -c 'apt-get update -qq && cd /out && mkdir -p pkgs && cd pkgs && apt-get download linux-image-KVER'
build/in-chroot.sh build-firmware.sh /out/firmware
build/in-chroot.sh build-initramfs.sh /out/initramfs
sha256sum /out/firmware/OVMF.amdsev.fd /out/initramfs/vmlinuz /out/initramfs/initrd.img

The three hashes must equal the ones in RELEASE.json. The manifest records the snapshot timestamp, the edk2 commit, the kernel package and its hash, and the SOURCE_DATE_EPOCH, which is everything that determines them. If you get a different byte, that is a bug in our recipe or evidence against us, and either way we want the report.

07 What this does not protect

  • The template before you encrypt it. Your root filesystem starts as our unencrypted Debian or Ubuntu image. Until you run encrypt, the host can read and write it, and a host that pre-installed something in the template would have it encrypted along with the rest. Encrypt at first boot, before the rootfs has ever run, and audit the image afterwards with debsums or your own tooling; the template is a stock cloud image plus the packages listed in the build script.
  • The console. Serial and VNC pass through the host. They can watch; do not type secrets into them.
  • Disk integrity. LUKS2 with XTS hides your data but does not authenticate it; a host can corrupt ciphertext blindly. It cannot read or forge them meaningfully.
  • Metadata. Traffic volume, packet headers, CPU usage, and the fact that the VM exists are visible to us as to any transit provider. Encrypted memory is not anonymity; that is what the rest of Servury is for.
  • Availability. We can stop or delete the machine. We cannot read it.
  • Kernel updates are ours. The kernel is supplied by the release, so apt upgrade inside the guest does not change what boots. New releases are published here with their hashes; the initramfs lends the guest its module tree when the guest's own does not match the running kernel.
  • Measured boot requires an IPv4 address for the initramfs network and a Linux template that supports SEV-SNP and encryption.

08 Releases

2026.09 (current)

Built 2026-09-05. Kernel 6.12.107+deb13-amd64 (linux-image-6.12.107+deb13-amd64_6.12.107-1_amd64.deb). Firmware edk2 edk2-stable202505 unknown. Debian snapshot 20260904T000000Z.

OVMF.amdsev.fd8731846cdbcbb6aa5c624238b839544b1553f4c5af874450f043321b3ef8958b
vmlinuz2b2358b37674d2505350528875bb17afae2a36522a9e8a9417eaca65a7da0e08
initrd.img46689fa645887affb5df1fbc7eb9c7253ea7444cc426e07fe17ab2b7804192e5
RELEASE.jsonSHA256SUMS · source tree

The verifier itself: blackbox-verify (Python, MIT). Questions, findings and mismatches: support, PGP key on the usual page.