TEE Deployment
Trusted Execution Environments give chio a stronger story than a well-configured container can. Inside a TEE the kernel runs in hardware-isolated memory, the privileged host cannot read process state, and the signing identity is bound to a measurement of the code that produced it. The cost is real: lower throughput, harder debugging, and hardware lock-in. Most chio deployments do not need it. The ones that do, need it badly.
Source
Dockerfile.tee, crates/chio-tee/src/mode.rs, crates/chio-tee/src/config.rs, crates/chio-attest-verify/src/, and deploy/dashboards/loki/chio-tee.json.What TEE Actually Buys You
Three guarantees that ordinary container isolation cannot give you:
- Hardware-isolated execution. Encrypted-memory enclaves keep the kernel's working state opaque to the host operating system, the hypervisor, and the cloud control plane. A privileged operator on the host machine cannot read receipts, capability tokens, or signing material out of process memory.
- Attestation-bound signing keys. The kernel generates its Ed25519 signing keypair inside the TEE and never exports the secret. A relying party can verify, before trusting any receipt, that the public half was produced by a measured chio binary running in a measured TEE.
- Replay separation. The TEE side can re-evaluate kernel decisions independently and flag divergences. In
enforcemode it fail-closes when its replay disagrees with the kernel verdict.
TEE is not a panacea
Supported Hardware Backends
The chio TEE sidecar is hardware-agnostic in the same sense as confidential containers: the binary runs anywhere a measured Linux userland can run, and the attestation surface is provided by the platform. The verifier in chio-attest-verify consumes Sigstore-style attestation bundles and is the integration point for additional quote formats.
| Backend | Quote source | Typical hosting |
|---|---|---|
| Intel SGX | DCAP / ECDSA enclave quote | Bare metal, on-prem, Azure SGX |
| AMD SEV-SNP | SNP attestation report | Azure CVM, GCP Confidential VMs |
| Intel TDX | TD report + quote | Azure CVM, on-prem TDX hosts |
| AWS Nitro Enclaves | Nitro attestation document | EC2 instances with Nitro |
The choice is operational, not architectural: the chio binary, the receipt format, and the kernel logic are identical across all four. What changes is the quote your verifier accepts and the runtime that hosts the binary inside the enclave.
The Dockerfile.tee Image
Dockerfile.tee is a two-stage build that mirrors Dockerfile.sidecar so the path dependencies and Cargo.lock resolution stay identical to CI. Stage one compiles the chio-tee binary against the locked workspace; stage two ships an Alpine runtime with tini as PID 1.
# Stage 2: minimal runtime
FROM alpine:${ALPINE_VERSION} AS runtime
RUN apk add --no-cache ca-certificates tini \
&& addgroup -S -g 10001 chio \
&& adduser -S -u 10001 -G chio -h /home/chio -s /sbin/nologin chio \
&& mkdir -p /var/lib/chio/tee /etc/chio /run/chio-tee \
&& chown -R chio:chio /var/lib/chio /etc/chio /run/chio-tee /home/chio
COPY --from=builder /chio-tee /usr/local/bin/chio-tee
USER chio:chio
WORKDIR /home/chio
ENV CHIO_HOME=/var/lib/chio \
CHIO_TEE_CONFIG=/etc/chio/tee.toml \
CHIO_TEE_MODE=verdict-only \
RUST_LOG=info
ENTRYPOINT ["/sbin/tini", "--", "/usr/local/bin/chio-tee"]
CMD ["--help"]Three things in this image matter for TEE operators:
- Non-root, deterministic UID. The runtime user
chio:10001is fixed so that volume mounts attest the same uid:gid every time. Enclave measurement of process state stays deterministic. - Signed base layers. Both the Rust builder image and the Alpine runtime are pinned by digest in the Dockerfile. Builds are reproducible, and the measured artifact set inside the enclave is bounded.
- Default mode is conservative.
CHIO_TEE_MODE=verdict-onlyships in the image. The TEE side captures verdicts but does not enforce; you upgrade through the mode lattice deliberately.
The Mode Lattice
The TEE shadow runner participates in kernel decisions at three escalation levels. The lattice is enforced in crates/chio-tee/src/mode.rs: downgrades are unconditional, upgrades require a chio:tee/upgrade@1 capability token.
| Mode | Behavior | Use |
|---|---|---|
verdict-only | Capture kernel verdicts; no replay-side enforcement. | Default; safe rollout. |
shadow | Replay decisions inside the TEE; record divergences but do not block. | Detection without blast risk. |
enforce | Replay decisions and reject when the TEE-side replay disagrees with the kernel verdict. Fail-closed. | Regulated workloads. |
Mode resolution follows a four-layer precedence: CHIO_TEE_MODE wins, then sidecar TOML at CHIO_TEE_CONFIG (default /etc/chio/tee.toml), then the per-tenant manifest tenant.tee.mode, then the implicit verdict-only default. SIGUSR1 hot-toggles the resolved mode at runtime via ${CHIO_TEE_RUNTIME_DIR}/mode-request.
# Set mode at launch
$ docker run --rm \
-e CHIO_TEE_MODE=shadow \
-v /etc/chio:/etc/chio:ro \
chio-tee:latest
# Or via sidecar TOML
$ cat /etc/chio/tee.toml
[tee]
mode = "enforce"Attestation Flow
At launch the enclave runtime measures the chio-tee binary and produces a quote. The quote, plus the kernel-generated public signing key, plus a small set of platform claims, gets published as a Sigstore-style attestation bundle. The verifier in chio-attest-verify consumes that bundle, validates the signing chain to the platform root, and returns a public key the relying party can trust to sign receipts.
What the attestation actually proves is narrow but precise. It proves that the published public key was generated by a process whose binary measurement matches a chio-tee build you trust, running on a platform whose attestation root you trust, at a moment in time recorded in the quote. It does not prove that the binary is bug-free, that the platform vendor is honest, or that the operator running the enclave has not granted side-channel access. Those are separate trust assumptions.
What stays trusted
Signing Key Birth and Death
Inside a TEE deployment the chio kernel signing key is ephemeral by design. It is generated inside the enclave at launch, attested to the platform quote, and dies when the enclave terminates. There is no off-enclave key custody and no rotation runbook for the kernel signing material itself: a new enclave gets a new key, attested fresh.
- Generation. The keypair is produced by the same
Keypair::generate()path used by the non-TEE kernel; the difference is that the process memory holding the secret half is never readable from outside the enclave. - Binding. The public key is included in the platform quote payload, so the attestation chain commits to this specific public key, not just the binary.
- Continuity. Receipt continuity across enclave restarts comes from the Merkle checkpoint chain, not from the signing key. A new enclave gets a new key; the kernel checkpoint emitted by the old enclave references the previous checkpoint hash, so the chain stitches across the key transition.
For deployments that need long-lived signing identity (for example, an audit trail that must verify under one published key for years), the pattern is to anchor an external trusted-issuer key outside the TEE and have the enclave key sign under it as a delegated signer. See /docs/deployment/secrets-keys for the trusted-issuer key set and delegation patterns.
The chio-tee Loki Dashboard
The dashboard at deploy/dashboards/loki/chio-tee.json ships with the repo. Title: Chio TEE Loki receipt view. It is the operator-facing view for verdicts emitted by the TEE side and is filtered by receipt id, tenant, trace id, verdict, and TEE mode.
| Panel | What it shows |
|---|---|
| TEE records by verdict | Time series of records grouped by chio_verdict across chio-tee, chio-replay, and chio-otel-receipt-exporter services. |
| TEE mode and verdict density | Heatmap of chio_tee_mode × chio_verdict. Useful for spotting verdict drift right after a mode upgrade. |
| Receipt, trace, and tee log stream | Filterable raw log stream with prettified JSON, scoped to the same service set. |
| Receipt to trace lookup | Top-50 receipt rows pivoted to columns: receipt id, span id, trace id, policy ref, verdict, deny reason. Click through to Jaeger. |
The query backbone is a structured Loki LogQL pattern that all four panels share. The first panel uses:
sum by (chio_verdict) (
count_over_time(
{service_name=~"chio-tee|chio-replay|chio-otel-receipt-exporter"}
| json
| chio_tenant_id=~"$tenant_id"
| chio_receipt_id=~"$receipt_id"
| chio_verdict=~"$verdict"
[$__interval]
)
)This is the canonical LogQL form for the M10 attribute lock. Importing the dashboard into Grafana and pointing it at a Loki backend named Loki is the entire installation.
Deployment Patterns
Three production patterns cover almost every TEE chio deployment in the wild.
Confidential VM
The simplest path. Provision a confidential VM (Azure CVM, GCP Confidential VM, AWS EC2 with Nitro, or an on-prem TDX host), install Docker, and run the Dockerfile.tee image as you would any sidecar. The platform produces the attestation document; chio-tee includes its public key in the binding.
# Azure SEV-SNP example
$ az vm create \
--resource-group chio-prod \
--name chio-tee-01 \
--image Ubuntu2204 \
--security-type ConfidentialVM \
--enable-secure-boot true \
--enable-vtpm true \
...
# Then on the VM
$ docker run --rm -d \
--name chio-tee \
-e CHIO_TEE_MODE=shadow \
-v /etc/chio:/etc/chio:ro \
-v /var/lib/chio:/var/lib/chio \
chio-tee:latestEnclave Runtime (Occlum, Gramine)
For SGX deployments that want process-level isolation rather than full-VM, an enclave LibOS hosts the chio-tee binary inside an SGX enclave directly. Both Occlum and Gramine accept the same Alpine userland the runtime stage builds, so the only delta is the manifest file the LibOS uses to describe the enclave layout.
Nitro Enclave
On AWS, the enclave runs as a sibling EC2 process with no network device and no persistent disk. The parent EC2 instance proxies traffic in and out via vsock. Receipts produced inside the enclave reach the receipt store through that vsock channel; the store itself can live on the parent instance or further out.
Trade-offs
TEE deployments pay real costs that should be priced in before committing to one.
- Throughput. Encrypted memory and ocall transitions add per-request overhead. Rule of thumb: expect 15 to 30 percent throughput loss at the kernel hot path. Receipt signing is unaffected because it happens once per decision, not per byte of payload.
- Debugging. Production enclaves do not let you attach a debugger or read process memory. You debug by structured logs and receipts, which is what the chio-tee Loki dashboard exists to support. Plan for verbose tracing in pre-production and conservative tracing in production.
- Hardware lock-in. Each backend has its own quote format, attestation root, and provisioning workflow. Multi-cloud TEE is feasible but doubles the verifier configuration surface.
- Build reproducibility. The whole story falls apart if your binary measurement is not reproducible. Pin base images, lock toolchains, and build in CI rather than on a developer laptop.
When TEE Is Overkill
Most chio deployments do not need a TEE. The default trust model of a hardened container, a separate signing key custody path, and the receipt log + checkpoint chain is already strong. Skip TEE when:
- You operate the host yourself and trust your own privileged operators.
- Your tenants are within the same legal entity (single-org SaaS, internal platform).
- The auditing relying parties accept signed receipts under a KMS-managed key, without a per-process attestation.
When TEE Is Essential
On the other hand, four scenarios genuinely require it:
- Hostile multi-tenant infrastructure. You are running on infrastructure where the operator is adversarial or potentially adversarial. Confidential cloud deployments and bring-your-own-host scenarios are the obvious examples.
- Regulated industries with explicit TEE mandates. Some financial-services and healthcare frameworks now name TEE attestation as a required control for AI-mediated PHI or settlement-relevant decisions.
- Cross-organization receipts with no shared trust root. Two organizations want to share signed receipts but neither trusts the other's key custody. A TEE-attested public key is a third-party-rooted signing identity both sides can verify.
- High-value bilateral settlement. When receipts are economic instruments, the cost of a forged receipt is high enough that the throughput penalty stops mattering.
Related Reading
- Container Images for the non-TEE Dockerfile lineage and how Dockerfile.tee relates to Dockerfile.sidecar.
- Secrets & Signing Keys for trusted-issuer key sets, KMS integration, and the rotation runbook for non-TEE keys.
- Trust Model for what stays trusted in any chio deployment, with or without a TEE.
- Formal Assumptions for the precise list of assumptions the chio proofs leave unproved, including the TEE attestation root.