TEE-gated lattices
audience: integrators
Some lattices require integrators to run their agent inside a TDX enclave; most do not. This page explains the two postures and when each applies.
Two postures
Open read, TDX-gated write. The common case. Reading the
lattice’s public surface (every organism’s read / watch /
outcomes stream) requires no TEE; writing to it
(Zipnet::submit, Offer::bid) is gated by a lattice-issued
ticket. Integrator agents run on ordinary hardware; the ticket
is the proof the lattice operator has vetted the agent.
TDX-gated write with attestation. For anonymity-sensitive
deployments the lattice operator requires the submitting agent
itself to run inside TDX. The organism’s write-side ticket
validator additionally requires a valid TDX quote on the
agent’s PeerEntry. This is the posture the zipnet v2 TDX path
takes; lattices that want to extend the same property to
bundles adopt it for offer too.
Which posture your lattice uses
The operator’s fact sheet (see handshake-with-operator.md) names the posture. If the operator publishes MR_TDs for any organism’s write-side, that organism is TDX-gated on writes. If MR_TDs are published only for the organism’s committee, writes are still open.
Compiling for TDX
When the lattice requires you to run in TDX, compile your agent
with the tee-tdx feature enabled on the relevant organism
crates and on mosaik itself:
[dependencies]
mosaik = { version = "=0.3.17", features = ["tee-tdx"] }
zipnet = { version = "0.1", features = ["tee-tdx"] }
offer = { version = "0.1", features = ["tee-tdx"] }
# ... as needed ...
[features]
tdx-builder-ubuntu = ["mosaik/tdx-builder-ubuntu"]
In your build.rs:
fn main() {
#[cfg(feature = "tdx-builder-ubuntu")]
mosaik::tee::tdx::build::ubuntu()
.with_default_memory_size("4G")
.build();
}
cargo build --release --features tdx-builder-ubuntu produces a
reproducible initramfs, OVMF, kernel, and a MR_TD hex file.
You publish your MR_TD to your operator (so they can pin it in
the write-side ticket validator) and boot your agent from the
resulting image.
See the mosaik TDX tutorial for the full walk- through; the flow is identical to zipnet’s v2 TDX path.
What MR_TD pinning gets you
When the write-side ticket validator pins your MR_TD:
- Your agent cannot be silently swapped for a different binary without the lattice operator updating the ticket.
- A compromised host that is not running your published image cannot submit as your agent.
- The lattice operator can revoke your ticket by rotating the pinned MR_TD without touching your agent’s secret key.
What it does not get you:
- Protection against your own bugs. TDX measures the image, not the correctness of the code inside it.
- Privacy of your code from the operator — they see the MR_TD, and reproducible builds mean they could build the same image themselves. TDX’s property is integrity, not code confidentiality.
- Cross-organism attestation. Each organism’s ticket pins its own MR_TD; there is no notion of “the agent as a whole is attested”. If you need coupling (e.g. “the same TDX image submits to zipnet and offer”), publish one MR_TD and pin it on both organisms.
When MR_TDs rotate
Lattice operators rotate MR_TDs when they upgrade their
committee image or revoke a compromised key. When your organism
crate’s pinned MR_TD differs from the committee’s current one,
your next verb() call returns Attestation error. Rotate
your own image or your own build if your published MR_TD
changed; if only the operator’s changed, wait for their new
LatticeConfig release.
You are not required to pin anything
If the lattice is not TDX-gated on your write side (the
default), do not compile with tee-tdx. Compiling with it
when the lattice does not require it is a no-op — the ticket
validator chain simply ignores the unused TDX ticket — but it
adds build-time overhead you do not need.
Next reading
- Connecting to a lattice — where the TDX-enabled build slots in.
- mosaik TDX — the full image-builder reference.
- zipnet TEE-gated deployments — a worked example of the pattern on one organism.