Skip to main content

Module identity

Module identity 

Source
Expand description

The tunnel’s identity proof: the seed’s wire contract, the Noise pattern, and the pin.

Here rather than on either side for ARCH-2’s reason, and the stakes are higher than for the close codes: the host derives a public key from a seed and the daemon derives what must be the same public key from the same seed. A derivation spelled twice is a derivation that can disagree, and a disagreement surfaces as a handshake that fails with no way to tell a wrong pin from a wrong derivation.

Following this crate’s own rule (see the crate docs), the base64 encoding is not here: the seed travels as a String field and each side encodes with the shared base64 crate, exactly as the exec payloads do. What is here is the part that must agree — the key names, the length, the pattern, and which seeds are refused.

§What this proves, and what platform-layer mTLS cannot

TLS terminates at the AWS-managed endpoint proxy and the service model has no client-certificate parameter anywhere: CreateMicrovmAuthToken takes microvmIdentifier, allowedPorts, and expirationInMinutes, and nothing else. So there is no way to present a certificate to the VM through the platform, and endpoint auth is the JWE alone.

The JWE is scoped to one microvmId and the proxy enforces that scope, so an authenticated connection already binds to VM identity as attested by AWS. A caller who trusts the proxy needs nothing here. This module is for the caller who wants that binding without trusting the proxy, and it works because we control both endpoints: the proof terminates in the daemon rather than at the proxy.

§Noise KK rather than TLS, on a measured constraint

Issue #70’s layer 3 called for rustls with a per-VM certificate pinned by SPKI. That is not available to the daemon, and the reason is the shipping target rather than a preference. agentd ships as a static aarch64-unknown-linux-musl binary, and both rustls crypto providers compile C: aws-lc-sys and ring each drive cc-rs, which looks for aarch64-linux-musl-gcc. Measured 2026-08-29 on the devbox, and .github/workflows/ci.yml installs gcc-aarch64-linux-gnu — a gnu cross compiler, not the musl one cc-rs asks for. Both providers fail the daemon’s release build with error occurred in cc-rs: failed to find tool "aarch64-linux-musl-gcc", so putting rustls in the daemon would trade a working shipping artifact for an identity feature.

Noise KK gives the same three properties with no PKI and no C:

  • Mutual authentication. KK means both statics are known to both sides before the handshake, which is exactly the situation here — the host generated the seed, so it knows the daemon’s key, and the daemon is told the host’s key in the same payload. Each side proves possession of its own static, so the daemon learns the peer is the launching host rather than another token holder.
  • Pinning by construction. There is no name, no CA, and no chain to get wrong: the remote static key is the pin. A wrong pin cannot be “accepted anyway” by a verifier that forgot a check, because the key is mixed into the handshake hash and a mismatch fails decryption. That is a stronger position than a custom certificate verifier, which is code that can be written wrong.
  • Confidentiality past the proxy. ChaCha20-Poly1305 over the whole stream, so the bytes the relay carries are opaque to the endpoint that carries them.

snow is the crate, at 26M downloads the most-used Noise implementation in the ecosystem, and it cross-compiles to the shipping target with no C compiler — measured, with default-features = false, which is load-bearing: snow’s std feature reads ring/std rather than ring?/std, so enabling it force-enables the very C dependency the daemon cannot build.

§The honest limit, restated here because this is where a reader will look

This proves the far end is agentd in the VM the caller launched. It does not prove the VM is uncompromised: the workload runs as uid 0 and can in principle ptrace the daemon and read the derived key out of its memory. Same class as the other entries on docs/TRUST.md’s unenforced list. It is documented rather than overclaimed.

Enums§

SeedError
Why some bytes are not a usable identity seed.

Constants§

HOST_PUBLIC_KEY_KEY
The payload key carrying the host’s public key, which the daemon pins in return.
IDENTITY_PAYLOAD_BYTES
How many bytes the identity material adds to the run-hook payload.
NOISE_PATTERN
The Noise handshake pattern, spelled once for both sides.
SEED_BYTES
The length of a seed, a static secret, and a public key. All 32 bytes, on x25519.
SEED_KEY
The payload key carrying the VM’s own seed.

Functions§

seed_from_bytes
Checks decoded bytes into a seed, refusing the two shapes that are not one.