Home / Blog / Security

Remote Attestation, Explained - How a Calimero node proves what it runs before it gets keys

What an Intel TDX quote contains, what it proves and what it doesn't, and the five checks every Calimero node passes before it is trusted with a key.

Remote Attestation, Explained - How a Calimero node proves what it runs before it gets keysRemote Attestation, Explained - How a Calimero node proves what it runs before it gets keys

The question every security review asks

Sooner or later, every team that sells software to a serious customer gets the same question from a security reviewer: what exactly runs on the machine that holds our data, and who can see it?

The usual answer is a promise. A SOC 2 report, a list of access controls, a description of who holds the production credentials. All of it amounts to "trust us": trust the vendor's staff, its cloud provider, its hiring process and its incident response.

Remote attestation replaces that promise with a proof. The machine itself answers the question, in a statement signed by its processor, which anyone can check without asking the vendor. This post explains what that statement contains, what it proves, what it doesn't, and how every Calimero node uses it before it is trusted with a single key.


Confidential VMs, in one paragraph

Calimero nodes run in Intel TDX confidential VMs. TDX (Trust Domain Extensions) is a processor feature that keeps a virtual machine's memory encrypted with a key the processor holds. The host operating system, the hypervisor and the people who run the data centre can stop the VM, but they cannot read its memory or change its code while it runs.

Isolation is only half of it. When a TDX VM boots, the processor measures it: it records hashes of the firmware, kernel and image into registers called MRTD and RTMR0–3. Those measurements name exactly what booted. Change one byte of the image and the measurements change.

Note: A confidential VM on its own protects one machine. Proving which machine you are talking to, and that it runs the code you expect, is what attestation adds.


What a quote contains

A quote is the processor's signed statement about a running VM. It has two parts that matter:

  • The measurements: the MRTD and RTMR values recorded at boot, which name the exact image.
  • 64 bytes of report data: bytes the VM chooses and the processor signs along with everything else.

The quote is signed by keys rooted in Intel, not by the VM and not by the operator. Anyone can verify that signature offline against Intel's published collateral (the DCAP verification flow), so checking a quote does not require trusting whoever forwarded it.

On a Calimero node, you ask for one with a fresh random nonce:

GET /attestation?nonce=<32 bytes, hex>

The answer carries the quote, the node's transport key, and the release the node says it runs. The interesting part is how the 64 bytes of report data are filled:

report_data = nonce ‖ SHA-256("calimero.tee-attest.transport-key.v1" ‖ app_hash ‖ transport_key)

The first 32 bytes are your nonce, so the quote was made for your request and cannot be replayed from yesterday. The second 32 bytes commit to the node's transport key, an X25519 key the node generates at start-up and keeps only in memory. Because the processor signed both together, a valid quote tells you: this key belongs to a process running inside a VM with these measurements.

Depending on what the caller asks for, the same second half can instead bind an app's code hash, the node's receipt key, or a record of where the node got its storage keys.


Measurements mean nothing without a policy

A quote proves what booted. It does not say whether that is good. For that, you need something to compare the measurements against.

Every Calimero node image comes from a signed mero-tee release. Each release publishes the measurements of its images in a file signed through Sigstore by the release workflow. When a client verifies a node, it:

  1. Reads the release the node names, and refuses it if it is older than a minimum version.
  2. Fetches that release's published measurements and checks their signature.
  3. Verifies the quote itself against Intel's collateral, and refuses debug VMs, whose memory the host can read.
  4. Checks the platform's security status (the TCB status must be up to date unless the caller allows otherwise).
  5. Requires the quote's MRTD and RTMRs to match one of the release's allowed image profiles.

Only when all of that passes does the client open a sealed session to the transport key. If any step fails, it sends nothing.


Five checks before a node gets a key

The same logic decides whether a node may hold data at all. A Calimero node does not start with its keys. It earns them:

StepWhat happens
1. Signed releaseEach node image release publishes its measurements, signed by the release workflow.
2. Node bootsThe node starts in an Intel TDX confidential VM from a read-only image, with no SSH, serial console or rescue shell.
3. Node provesThe hardware signs a quote over the node's release, bound to a fresh nonce.
4. Key serviceThe attested key service (mero-kms, itself running in TDX) checks the quote against the release policy.
5. Keys releasedOnly now does the node receive its storage key, and data unlocks inside it.

A node that fails any step never gets keys, so it can never open the data. The node also keeps a record of what it verified about the key service it took each key from, and can bind that record into its own quote, so you can check that its keys came from a key service on a signed release too.


Traffic that ends inside the node

The usual way to serve a web app terminates TLS at a load balancer or proxy. Even if the application runs in a confidential VM, the proxy in front of it sees every request in plaintext.

Calimero clients do it differently. The browser library (mero-js), the Rust and Python clients and the meroctl CLI all run the verification above before they send anything, then seal each request end to end to the transport key the quote vouched for. The key was made inside the VM and never leaves it, so the session ends inside the node and nowhere else. Session keys are ephemeral, which gives forward secrecy.

Nodes judge each other the same way. When one node opens a channel to a peer, it verifies the peer's quote under its own policy, and proves its own attested key in the handshake. A node only sends an app's data to a peer whose verified release that app has approved.


Receipts: proving where an answer came from

Attestation also works after the fact. Every successful call to a Calimero app returns a receipt: the answering node's signature over the app, the log position and a hash of the result. The key that signs receipts is itself attested, together with the rules the cluster was deployed under.

So anyone who holds a node's receipt-key attestation can later prove, offline, that a genuine node of this cluster, running this release, returned this answer. A client can also ask every replica of an app for its attestation at once and check the whole cluster in one go.


What attestation does not prove

It is worth being precise. Remote attestation proves which code runs and that it runs in protected hardware. It does not prove:

  • that the code is free of bugs. That is what open source, audits and testing are for, and why the Calimero node and verifier are open source;
  • that the processor vendor is trustworthy. TDX's guarantees rest on Intel's hardware and signing keys;
  • that the operator sees nothing at all. Running a fleet means seeing that it runs: on Calimero Cloud, we see health, resource use, which release each node runs, and billing counts. We cannot read data inside a sealed node, log in to one, or get a key for one without proof.

That last point is the shift that matters: the operator's power is limited by the hardware and the release policy, not by the operator's good behaviour.


Check a node yourself

You don't have to take any of this on our word. Quotes are verifiable offline against Intel-signed collateral, with the open-source attestation verifier or with the JavaScript, Rust and Python clients. The security page walks through each check, and the protocol documentation describes every field.

That is the answer to give the next security review: not "trust us", but "here is how to verify us".

Your customers want control. You want to ship.

Start on Calimero Cloud, or build on the open-source runtime.