Contents
The five modes at a glance.
The packages/attestation module ships parsers for four vendor TEEs and a no-TEE docker fallback. Every deploy produces an attestation document that the verifier writes into the receipt. The five modes are not interchangeable; they sit on a spectrum of vendor coupling, regulatory standing, and operational cost.
| mode | tee | attestation | vendor |
|---|---|---|---|
| fly | none / Nitro on opt-in | image sha + region pin | Fly.io |
| aws-nitro | Nitro Enclaves | COSE_Sign1 + PCR0 SHA-384 | AWS |
| gcp-cvm | Confidential VM (SEV-SNP) | 1184-byte binary report | Google Cloud + AMD |
| azure-cvm | Confidential VM (TDX or SNP) | TDX quote or MAA JWT | Azure + Intel/AMD |
| docker | none | image sha256 only | your registry |
The fly target is operationally the cheapest. A region pin and an image SHA are the entire attestation. It's a fast deploy to a fast platform, and the trust model is the same trust model you already have with any platform-as-a-service provider. For a workload where the threat is operational mistakes and the regulator does not require hardware-rooted attestation, this is the right tier.
The three middle modes (aws-nitro, gcp-cvm, azure-cvm) produce a hardware-rooted attestation document. A measurement of the running code lands inside a signed envelope that originates from silicon. The vendor's attestation service signs the document with a key that chains to a vendor-controlled root certificate. The verifier's job is to check the chain, the freshness, and the measurement against an expected value.
The docker target is the escape hatch. The attestation is an image SHA and a registry signature, nothing more. There is no TEE. The operator chooses this mode when the deploy is on a private network they already control, when the regulator does not require a hardware root, or when the operational complexity of running Nitro or CVM is not worth the marginal trust gain.
Attestation format per mode.
The four hardware-rooted formats have different shapes. The receipt-chain code parses each one into a common structure and records the canonical form in the artifact's audit log.
aws-nitro: COSE_Sign1 + PCR0 SHA-384
Nitro Enclaves produce a COSE_Sign1 envelope. The payload is a CBOR map containing the PCR set (PCR0 is the enclave image SHA-384, PCR1 the bootloader, PCR2 the OS), the public key the enclave was launched with, a user-supplied nonce, and a timestamp. The signature is over the payload with a per-region attestation key. The verifier walks the chain to the AWS Nitro root certificate, then checks PCR0 against the expected enclave image hash.
# the receipt records the canonical form { "mode": "aws-nitro", "pcr0": "a1b2...384-hex", "pcr1": "c3d4...384-hex", "pcr2": "e5f6...384-hex", "signed_at": 1747200000, "signed_by": "nitro-region-us-east-1" }
gcp-cvm: SEV-SNP 1184-byte report
Confidential VM on Google Cloud (using AMD SEV-SNP) produces a 1184-byte attestation report defined by the AMD SEV-SNP specification. The report contains the measurement (a SHA-384 over the VM's initial memory), the launch digest, the policy bits, the chip ID, and a TCB version. The signature is from an AMD-signed VCEK (Versioned Chip Endorsement Key) that chains to AMD's ARK and ASK root certificates. Google's Confidential Computing API returns the raw report; the verifier parses it.
azure-cvm: TDX quote or MAA JWT
Azure Confidential VMs use either Intel TDX (most current SKUs) or AMD SEV-SNP. The TDX quote is a binary structure similar in spirit to SGX quotes; it contains the measurement of the trust domain, the TD's runtime state, and a signature from an Intel-rooted PCK. Azure also offers a higher-level alternative: the Microsoft Azure Attestation service (MAA) returns a JWT after server-side verification. The JWT format is operationally easier to consume; the binary quote is what an auditor who does not trust MAA will want.
docker: image sha256 only
The docker target's attestation is the image digest from the registry. There is no hardware root. The verifier records the SHA, the registry name, and the registry signature (Docker Content Trust or a Sigstore cosign signature, if the operator configured one). This is the lowest tier; it's intended for environments where the trust comes from elsewhere (a private network, a regulator-approved hosting agreement, an existing third-party attestation).
The TOFU pinning model.
kolm's BYOC verifier does not maintain a curated list of vendor root certificates. It uses trust-on-first-use. The first attestation document received from a given deploy is pinned: the PCR set, the measurement, the launch digest, the image SHA. Subsequent attestations from the same deploy have to match the pinned values on the fields that should be stable. A mismatch is flagged in the audit log and the deploy is marked as drifted.
TOFU is a pragmatic choice, not a cryptographic certainty. The argument is: a kolm deployment is a long-lived single artifact on a single piece of hardware running a single image. The thing that changes is the measurement, and the only legitimate reason for a measurement to change is an operator-authorized image update. If the operator is consulting the audit log when an update lands (the workflow), the TOFU pinning gives them a clear signal: "this attestation is new, here is the diff, sign or roll back."
The verifier records every pinning event with a timestamp. The audit log answers the auditor's question of "when did this measurement first appear?" with a per-deploy timeline. A measurement that has been stable for three months and then changes without an authorized image update is the thing the audit log is designed to surface.
TOFU does not give you a guarantee that the measurement is correct on its first appearance. It gives you a guarantee that the measurement is unchanged across the life of the deploy. Pair the first-use pinning with an out-of-band check (the auditor independently computes the expected enclave image hash) and the chain closes.
The kolm cloud CLI.
Five verbs. The flag names below are the actual flags exposed by cli/kolm.js.
$ kolm cloud targets available targets: fly Fly.io machines needs: KOLM_FLY_TOKEN aws-nitro AWS Nitro Enclaves needs: KOLM_AWS_PROFILE gcp-cvm GCP Confidential VM (SEV-SNP) needs: KOLM_GCP_PROJECT azure-cvm Azure CVM (TDX/SNP) needs: KOLM_AZURE_TENANT docker Docker (no TEE) needs: KOLM_DOCKER_REGISTRY $ kolm cloud deploy --target aws-nitro --artifact support_ticket_router-1.0.0 \ --region us-east-1 --name router-prod [deploy] target=aws-nitro region=us-east-1 [deploy] building enclave image (PCR0 expected: a1b2...) [deploy] launching enclave on m5n.xlarge [deploy] fetching first attestation (Nitro COSE_Sign1) [deploy] PCR0 matched; pinned as deploy=dep_8f3a2c [deploy] endpoint: https://router-prod.nitro.example [deploy] check it with: kolm cloud show dep_8f3a2c $ kolm cloud show dep_8f3a2c deployment: dep_8f3a2c target: aws-nitro region: us-east-1 status: running artifact: support_ticket_router-1.0.0 pcr0: a1b2... pinned 2026-05-14 09:12 UTC attestations: 47 verified, 0 mismatched $ kolm cloud destroy dep_8f3a2c [destroy] stopping enclave dep_8f3a2c [destroy] deployment status -> destroyed
The deploy verb takes a --target flag with one of the five tier names, an --artifact flag pointing at a registered .kolm, and optional flags for region, name, team, and output path. The targets verb prints the active set with the env var each one expects. The show verb prints the current attestation state and the pinning timestamp. The destroy verb tears the deploy down and writes a final audit-log entry.
When to pick which.
The matrix has four axes: who the regulator is, how much latency the workload tolerates, what the per-hour cost ceiling is, and what vendor commitments the buyer already has.
Fly wins when the regulator does not require a hardware root, latency is the binding constraint, and the operator wants the cheapest per-hour bill. Fly's machines start in seconds and the operator does not have to learn a new vendor console. The attestation is weak; for workloads where the artifact's receipt chain plus a platform-level trust story is enough, that's fine.
aws-nitro wins when the buyer already has an AWS commitment and the workload is regulated. FedRAMP-aligned, FFIEC-aware, HIPAA-on-AWS shops have years of AWS controls work behind them; adding a Nitro Enclave is a smaller change than introducing a new cloud. The Nitro attestation format is the most mature of the four; the COSE_Sign1 envelope is parseable from any language with a CBOR library.
gcp-cvm wins when the buyer is on Google Cloud and the workload runs against BigQuery, GCS, or Vertex. The SEV-SNP report is verifiable end-to-end with AMD's root certificates. Latency is similar to Nitro; cost is in the same range. The selection often comes down to which cloud the data is already in.
azure-cvm wins when the buyer is in the Microsoft ecosystem. The MAA JWT path is the most operationally friendly of the four (a JWT is easier than a binary quote); the binary TDX path is available for buyers whose regulator does not trust the MAA service. Government cloud shops (Azure Government, Azure for Sovereign) often have the strongest reason to be here.
docker wins when the trust story is provided by the network, not the silicon. Private on-prem, regulator-bounded environments where the operator already runs Kubernetes, internal staging environments where the threat model is "an engineer accidentally leaks data" rather than "a cloud provider is compromised". The image SHA plus a registry signature is enough.
Honest limits.
Three things the TEE story does not give you.
Vendor-rooted attestation depends on trusting the vendor. An aws-nitro attestation chains to a Nitro Attestation Service root that AWS controls. A gcp-cvm SEV-SNP report chains to AMD's root, with Google in the middle of the path that delivered it. An azure-cvm TDX quote chains to Intel. If the threat model includes the cloud provider itself, or the silicon vendor itself, the TEE attestation does not close it. The honest framing is: the TEE makes the cloud provider's operations team materially weaker as an adversary, while doing nothing about the cloud provider's compliance team if a subpoena or a national-security letter is the threat.
TOFU is pragmatic, not cryptographic certainty. The first measurement the verifier sees is the baseline. If the deploy was compromised before that first measurement was pinned, the pinning happily preserves the compromise. The mitigation is an out-of-band check: the operator independently computes the expected PCR0 or measurement from the enclave image they built, and confirms the pinning matches. This is operational discipline; the verifier records the steps so the auditor can replay them.
Performance and cost are non-trivial. Nitro Enclaves run on a slice of the parent EC2 instance; you pay for the parent. CVMs are typically priced 10-30% above the equivalent non-confidential SKU and are not available in every region. TDX is currently more limited geographically than SEV-SNP. The decision is not "is the attestation strong enough" in isolation; it's "is the attestation strong enough for the cost and latency we can absorb."
For most workloads we have shipped, the right answer is a mix. Production lives on a hardware-rooted target (aws-nitro or gcp-cvm) where the regulator wants a chain. Staging lives on docker or fly. Internal demo lives on docker. The same artifact runs on all of them; the receipt chain records the deploy mode and the attestation document, and the audit log shows what was sent where.
When the network is the threat model. The pre-flight cache plan, the offline switches, and the operational realities of a static artifact.
read next Receipt chains →How the attestation document lands inside the receipt and what the verifier checks alongside it.
docs kolm cloud reference →Full CLI surface for the cloud verbs: targets, deploy, list, show, destroy.
security Threat model →What the attestation chain protects, what it does not, and where the operator's controls have to fill the gap.