When people hear "TPM attestation" they tend to think about hardware roots of trust and tamper-resistant chips soldered to motherboards, or even built-into the same die as the CPU. That's not what we're doing. lockboot only runs on selected cloud providers with virtual TPMs, where the root of trust is the cloud provider's hypervisor, and we think that's actually fine for most applications.
Here's how it works and why.
Quick primer: Secure Boot and TPMs
UEFI Secure Boot ensures that every piece of code loaded during boot is signed by a trusted authority. In a traditional boot chain, this verification cascades: the firmware verifies the bootloader, and the bootloader in turn verifies the kernel and other components it loads. If any signature check fails, boot halts.
A TPM (Trusted Platform Module) complements Secure Boot by recording what booted. As each component loads, its measurement (a cryptographic hash) is extended into the TPM's Platform Configuration Registers (PCRs). PCR extension is a one-way accumulation: PCR[n] = H(PCR[n] || measurement). You can't roll back a PCR to a previous value, so the final PCR state is a tamper-evident log of the entire boot chain.
Secure Boot answers "was this boot authorized?" TPM measurements answer "what exactly booted?" Together they let a remote verifier confirm both, or allow you to detect and prevent tampering.
A single binary is simpler
A traditional boot chain has many links — bootloader, kernel, initramfs, command line — each verified and measured separately, with their own PCR entries. lockboot collapses all of them into a Unified Kernel Image (UKI): a single UEFI PE binary containing the bootloader stub, kernel, initramfs, and command line. The firmware loads and measures one file, and Secure Boot verifies one signature. Fewer moving parts means fewer measurements to reason about and fewer places where the chain can diverge from what you expected.
We go one step further when building cloud images, we configure the UEFI Secure Boot database to accept only a single signing key as the authorized signer of our UKI. This key is ephemerally generated during the GitHub Actions release workflow and destroyed immediately after signing.
GitHub's artifact attestation provides verifiable proof that the image was built via CI and that no human had access to the key material. We also set UEFI DeployedMode, which prevents transitioning to Setup Mode — the only unauthenticated path to enrolling new Secure Boot keys. Since the signing key no longer exists and DeployedMode blocks the fallback path, no one (including the VM owner) can modify the Secure Boot database after provisioning.
This matters because our trust model requires that the operator of a VM cannot tamper with what boots on it.
The boot sequence
lockboot (a UKI) is measured and booted by the UEFI firmware. After the kernel hands off to userspace, stage1 runs as PID 1. Before it does anything with user-provided code, it:
- Fetches configuration from the cloud metadata service
- Downloads the stage2 binary and verifies its SHA256 checksum
- Creates or retrieves a restricted Attestation Key (AK) in the vTPM
- Generates a TPM attestation with nonce
H(H(binary) || H(config))— a signed snapshot of the current PCR state, bound to the specific workload about to run — and saves the attestation document to disk - Extends PCR 14 with the hash of the stage2 binary
- Extends PCR 15 with the hash of the configuration
exec()s stage2, replacing itself as PID 1
The attestation in step 4 captures the virgin state — the PCR values before any user-provided code or configuration has been measured in. The binary and config are already downloaded and verified at this point, so their hashes can be committed as the attestation nonce. A verifier gets both: the virgin PCR state proving a clean boot, and the nonce proving which binary and config were about to be loaded.
Stage2 inherits the saved attestation document and access to the AK. It can present the stage1 attestation to prove its boot lineage, and produce its own TPM2_Quotes with fresh nonces — signed by the same AK, but reflecting the current PCR state with stage2 and its configuration measured in.
Why restricted keys matter
The AK is a restricted signing key. This is a TPM 2.0 constraint that means the key can only sign digests that the TPM itself produces internally. When the AK signs a TPM2_Quote, the quote contains the actual PCR values at signing time — generated by the TPM, not by software.
This matters because after step 7, stage2 has full control of the system. It has access to the AK handle. But it can only produce quotes reflecting the current PCR state — with stage2 already measured into PCR 14. It cannot forge a quote showing virgin-state PCRs.
Without this constraint, the trust model collapses. Stage2 could simply ask the AK to sign a digest that says "PCRs are clean" and the attestation would prove nothing. The restricted key property is what makes the ordering (attest first, then measure, then execute) actually meaningful.
The generic trust model
Regardless of cloud provider, the verification follows the same pattern:
- Authenticate the AK — prove that this attestation key belongs to a real cloud vTPM, not a software emulator. Each provider does this differently (see below), but the result is the same: a verified AK public key.
- Verify the TPM Quote — check that the Quote's ECDSA signature is valid under that AK, confirming the PCR values and nonce are authentic.
- Policy decisions — the verifier decides whether the PCR values and nonce are acceptable. This is application-specific.
The cloud provider's job is step 1: binding an AK to a real vTPM. vaporTPM handles the cryptographic verification for steps 1 and 2, and leaves step 3 to your application.
Choosing cloud providers
The adversary in our model is the VM operator. Anyone can pay for cloud infrastructure, and we need a remote verifier to confirm they're running the expected code even though they control the VM. Not every cloud platform qualifies — we only target providers that meet three requirements:
- A vTPM with a verifiable trust chain — a cryptographic path from the cloud provider's root CA to the AK on the VM. This is what lets a remote verifier confirm the AK belongs to a real vTPM, not a software emulator.
- No memory snapshots — the provider must not allow the VM's memory to be dumped or cloned in a way that would let an attacker extract secrets or replay state.
- Restricted vTPM operations — just as the TPM protocol restricts what a key can do (a restricted signing key can only sign TPM-generated digests), the cloud provider restricts what the user can do with the VM. These constraints are what make the trust model sound.
This is the same pattern at different layers: the TPM restricts key usage, the cloud provider restricts VM operations, and both restrictions are what make attestation meaningful rather than ceremonial.
Currently we support AWS EC2 with Nitro vTPMs and GCP Confidential VMs. Note the distinction on GCP: regular Shielded VMs have a vTPM, but only Confidential VMs (across SEV, SEV-SNP, and TDX) get an AK certificate attested by Google with a verifiable chain to their root CA. The trust model is the same regardless of which underlying confidential computing technology GCP uses.
AWS Nitro
On regular EC2 instances with Nitro vTPMs, the trust chain works through the Nitro Security Module (NSM) — a hardware component that can sign attestation documents independently of the vTPM.
How the AK gets bound: stage1 creates an ECC P-256 AK in the vTPM's endorsement hierarchy, then asks the NSM to produce a COSE Sign1 attestation document that includes the AK's public key, the nonce, and all 24 PCR values (SHA-384). The NSM signs this with a P-384 key whose certificate chains back to the AWS Nitro root CA.
The trust chain looks like:
AWS Nitro Root CA (P-384, self-signed)
└─ Intermediate CA
└─ Leaf certificate (signs the COSE document)
└─ COSE Sign1 payload:
- AK public key (P-256)
- nonce
- all 24 PCR values (SHA-384)
What verification checks:
- Verify the COSE Sign1 signature and certificate chain back to the AWS Nitro root CA
- Extract the AK public key from the authenticated COSE payload
- Verify the TPM Quote's ECDSA signature using that AK
- Cross-check: the nonce and PCR values in the COSE document must match the nonce and PCR digest in the Quote
The Nitro attestation document itself proves VM state, signed by AWS hardware. The AK then becomes a persistent handle for subsequent quotes — a verifier can reason "this AK was attested in a clean state with config X, so later quotes from this AK come from a system that booted from that trusted state."
GCP Confidential VM
On GCP, the trust chain is certificate-based rather than document-based. Google provisions the AK and issues a certificate for it.
How the AK gets bound: Google pre-provisions an ECC P-256 AK in the vTPM and stores both an AK template and an AK certificate in TPM NV RAM. The certificate is signed by a project-specific intermediate CA, which chains to Google's EK/AK root CA (RSA-4096). stage1 recreates the AK from the stored template and retrieves the certificate chain.
The trust chain looks like:
Google EK/AK Root CA (RSA-4096, self-signed)
└─ Project Intermediate CA
└─ AK Leaf Certificate
└─ AK public key (P-256, signs TPM Quotes)
What verification checks:
- Validate the AK certificate chain back to Google's EK/AK root CA
- Extract the AK public key from the authenticated leaf certificate
- Verify the TPM Quote's ECDSA signature using that AK
- Verify the nonce and PCR digest (SHA-256) in the Quote
The key difference from Nitro: on GCP, the certificate is the platform binding. There's no separate attestation document — Google's signature on the AK certificate is what proves this key lives in a real GCP vTPM. The Quote then proves the PCR state, signed by a Google-certified key.
What this doesn't protect against
This is categorically weaker than hardware confidential computing (TDX, SEV-SNP), and we should be honest about that.
The trust boundary is the cloud provider. Cloud vTPMs run inside the hypervisor. Our attestation verifies the chain of trust back to the cloud provider, not to the silicon. A sufficiently motivated adversary who compromises the hypervisor — or a compelled cloud provider — could read secrets from VM memory, modify execution, or forge attestation state.
On GCP, our supported Confidential VMs do run on hardware with memory encryption (SEV, SEV-SNP, or TDX), but lockboot doesn't verify the hardware attestation. We require Confidential VMs because they provide a Google-signed AK certificate chain, not because we rely on the memory encryption. The hardware protection is a bonus, not something we attest.
With a full TDX or SEV-SNP attestation flow, the CPU enforces memory encryption and the attestation chain extends to the silicon. That's a meaningfully stronger guarantee. We're explicitly choosing to trust the cloud provider's software stack rather than verify hardware-level isolation.
Kernel hardening
The VM operator controls stage2 and runs it as root. Since the kernel command line is embedded in the signed UKI, the operator cannot change these parameters — but they can run arbitrary code with root privileges. The kernel hardening flags close the paths an operator could use to extract secrets or undermine the attestation model.
Preventing memory extraction:
hibernate=no— On AWS, hibernation writes guest memory to the root EBS volume, which the operator controls. This disables hibernation entirely.lockdown=confidentiality— Enables the kernel lockdown LSM, which blocks access to/dev/mem,/proc/kcore, loading unsigned kernel modules, and unsigned kexec. This is the broadest single mitigation.crashkernel=0— Reserves no memory for kdump. AWS exposes a diagnostic interrupt API that lets the operator send an NMI to trigger a kernel panic. With no crash kernel loaded and kexec blocked by lockdown, the panic produces no memory dump.debugfs=off— Disables the debugfs filesystem entirely. Lockdown restricts some debugfs access, but this removes the surface altogether.kernel.sysrq=0(set via sysctl before stage1) — Disables Magic SysRq via keyboard and serial console. The operator can get interactive serial access via the cloud provider's API and send a BREAK signal followed by a command character. Without this, SysRq is fully enabled at boot (CONFIG_MAGIC_SYSRQ_DEFAULT_ENABLE=0x01) and never restricted since we don't run systemd. SysRq+l/m/p would dump kernel state to the console (readable viaGetConsoleOutput), and SysRq+c would trigger a panic. Kernel lockdown does not block SysRq.
Reducing kernel exploit surface:
The operator's remaining avenue is exploiting a kernel vulnerability to bypass lockdown. These flags make that harder:
oops=panic— Halt on kernel oops rather than continuing in a potentially exploitable state.iommu.strict=1— Strict IOMMU TLB invalidation on DMA unmap, preventing DMA-based attacks from virtual devices.slab_nomerge— Prevents slab cache merging, making slab-based kernel exploits harder to build.randomize_kstack_offset=on— Randomizes the kernel stack offset on each syscall entry.init_on_alloc=1— Zero-fills memory on allocation, preventing info leaks from recycled memory.vsyscall=none— (x86_64 only) Removes the legacy vsyscall page, eliminating a fixed-address ROP gadget.
Why it's sufficient
But for many applications, you're already trusting the cloud provider. You're running your workload on their machines, using their networking, storing data on their disks. The vTPM attestation model doesn't ask you to trust anything you weren't already trusting.
What it gives you is verifiable boot state. You can prove to a remote verifier that a specific binary with a specific configuration booted on a real cloud instance, and that the attestation was captured before any user code ran. That's useful for:
- Proving to customers that their workload runs the code they expect
- Building audit trails for compliance
- Establishing identity for service-to-service authentication
- Anchoring key material to verified system state
And the practical advantage of cloud vTPMs is that the implementation surface is small. There are a handful of cloud vTPM implementations versus hundreds of physical TPM vendors with varying firmware quality, errata, and key provisioning practices. With a limited number of well-documented vTPMs, we get a relatively neat mental model that lets us build on top of it.
We're not claiming this is confidential computing. We're saying that if you trust your cloud provider — and you almost certainly already do — vTPM attestation gives you a useful set of guarantees on top of that trust.