c8s

module
v0.2.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 23, 2026 License: AGPL-3.0

README

c8s

CI

c8s is confidential Kubernetes. It runs Kubernetes workloads inside hardware-backed Trusted Execution Environments, so that the data they process (model weights, prompts, responses, datasets, credentials) stays encrypted in memory the entire time it is in the cluster, and that property is cryptographically provable to a third party over the network.

Encryption at rest and in transit are solved problems. Encryption in use is not: the moment a workload runs, its secrets sit in plaintext memory, readable by whoever operates the machine underneath it. Confidential computing closes that gap. Modern CPUs (AMD SEV-SNP, Intel TDX) can run a virtual machine whose memory is encrypted with keys held by the hardware, measure exactly what booted into it, and sign that measurement so a remote party can verify it. The infrastructure operator, the hypervisor, and the Kubernetes control plane no longer need to be trusted: they schedule the workload, but they cannot see inside it.

c8s applies that model to Kubernetes end to end, following five principles at every layer:

  1. Encrypt the runtime. Workloads run in hardware-encrypted memory.
  2. Measure the code. The hardware computes a launch digest over exactly what booted.
  3. Bind identity to measurement. Certificates issue only after the measurement verifies.
  4. Verify before connecting. Peers require attestation-rooted identity before any traffic flows.
  5. Secure the egress. Pod-originated TCP to pod and Service destinations is intercepted and wrapped in RA-TLS; TCP to non-pod external destinations is neither redirected nor dropped (it leaves the node plaintext). Non-TCP and unmeshed inbound fail closed rather than flowing in the clear. The exceptions are cluster DNS (UDP/53 to the cluster DNS server, the sanctioned name-resolution path) and the in-guest attestation service's plain HTTPS to AMD KDS.

c8s is built by Confidential AI as the substrate for private AI: inference, fine-tuning, training, and agents where the infrastructure operator never sees the data. The platform itself is workload-agnostic: anything that runs on Kubernetes can run confidentially.

Features

  • Hardware-attested workload identity. The Certificate Distribution Service (CDS) verifies TEE attestation evidence (AMD SEV-SNP, Intel TDX) and signs workload certificates with a mesh CA whose key never leaves the TEE. No verified measurement, no certificate. Issued leaves carry the evidence CDS accepted and the pod's sandbox ID, so a relying party can ask which workload is behind a key, not just whether it is a genuine TEE.

  • RA-TLS mesh. A transparent L4 proxy wraps traffic between workloads in mutual TLS rooted in hardware attestation. Plaintext never crosses the pod boundary.

  • Two confidential shapes. Run the whole node as one confidential VM (node-as-CVM), or run every pod as its own confidential VM (pod-as-CVM, via Kata Containers). See Architecture.

  • Measured boot end to end. Node images boot via IGVM with dm-verity; confidential pods boot a sealed guest image whose launch digest covers the entire in-guest security stack.

  • Container image and command-line allowlisting. Every container is enforced against a CDS-served allowlist with two layers: a floor of image digests admitted by digest alone, and named workload entries that additionally pin the command line each image may run with — and, in the guest, the bind-mount destinations and environment variable names. Enforced by an NRI plugin on the host under node-as-CVM, and by an in-guest policy-monitor under pod-as-CVM, where the host cannot tamper with it.

  • Attestation-gated secrets. CDS releases an application secret only once a pod's running containers resolve to a single allowlist entry carrying a grant for that path. An injected sidecar writes the values to a memory-backed volume every container mounts read-only. Works in both shapes: the sidecar redeems its sandbox token from the node's admission inventory, or from the in-guest policy-monitor under pod-as-CVM.

  • Encrypted volumes. Data too large to be a secret — model weights, in practice — encrypted at rest on host-visible storage (erofs, dm-verity, dm-crypt) and opened only inside the TEE. The key travels as a secret through the release path above, so possession of the volume implies nothing without attestation. On node-as-CVM the volumed node agent ships disabled — c8s install --volumes deploys it; under pod-as-CVM volumed runs inside each guest, baked into the measured image.

  • Fail-closed admission. A mutating webhook injects certificate sidecars and Kata RuntimeClasses; a ValidatingAdmissionPolicy rejects anything that escapes injection. The bootstrap ordering fails closed, never open.

  • Confidential GPUs. NVIDIA GPU passthrough into confidential pods on SEV-SNP and TDX hosts, with GPU CC mode. The attestation service verifies NVIDIA GPU and NVSwitch evidence; it is not wired into the c8s certificate flow end to end, see Known gaps.

  • Verifiable from a browser. A challenge-response protocol and a post-quantum over-encrypted channel let end users verify the cluster with no special client, via c8s-verify.

  • One-command install. c8s install --cvm-mode=<shape> brings all of this to an existing cluster (vanilla Kubernetes or RKE2, including AKS confidential node pools, where both SEV-SNP and Intel TDX attest through the Azure vTPM).

Architecture

The most consequential choice in c8s is the unit of trust and attestation. c8s supports both answers.

Node-as-CVM

The entire Kubernetes node is one confidential VM. Pods are ordinary containers inside it. A verifier checks the node's launch digest; everything on the node is inside that one boundary, including the kubelet. Every pod shares that boundary, so node-as-CVM is single-tenant: it isolates the node from the host, not workloads from each other. This is the simplest and densest shape, and the only one available on managed services without nested virtualization (for example Azure AKS).

                             NODE-AS-CVM
              one launch digest covers the whole node

════════════ TEE boundary (SEV-SNP / TDX encrypted memory) ════════════

  ┌────────────── Kubernetes node = one confidential VM ──────────────┐
  │                                                                   │
  │   ┌─────────┐   ┌─────────┐   ┌─────────┐      ┌───────────────┐  │
  │   │  pod A  │   │  pod B  │   │  pod C  │  ... │ kubelet, CNI, │  │
  │   │ (runc)  │   │ (runc)  │   │ (runc)  │      │ containerd    │  │
  │   └─────────┘   └─────────┘   └─────────┘      └───────────────┘  │
  │                                                                   │
  │   measured boot: IGVM + UKI + dm-verity node image                │
  └───────────────────────────────────────────────────────────────────┘

═══════════════════════════════════════════════════════════════════════

  HOST / HYPERVISOR (untrusted)
  the cloud or bare-metal operator sees only ciphertext
Pod-as-CVM

Each pod is its own confidential VM (via the Kata kata-qemu-snp or kata-qemu-tdx runtime). The node is just a launchpad and is fully adversarial. Every pod carries its own launch digest, so each workload proves its exact state to a verifier independently, and tenants on the same node are isolated from each other by hardware memory encryption. The security services each pod relies on (attestation, mesh, image policy) are baked into the measured guest image, out of the host's reach.

                              POD-AS-CVM
               every pod carries its own launch digest

════════════ TEE boundary (per-pod SEV-SNP / TDX encrypted memory) ═══════════

  ┌────── kata-qemu-snp/tdx CVM ──────┐  ┌────── kata-qemu-snp/tdx CVM ──────┐
  │ CDS                               │  │ workload                          │
  │   RA-TLS serving cert             │  │   + get-cert sidecar              │
  │   (SNP / TDX evidence)            │  │   (leaf cert from CDS)            │
  │                                   │  │                                   │
  │ baked into the measured image:    │  │ baked into the measured image:    │
  │   attestation-service, ratls-mesh │  │   attestation-service, ratls-mesh │
  │   policy-monitor                  │  │   policy-monitor                  │
  └───────────────────────────────────┘  └───────────────────────────────────┘

══════════════════════════════════════════════════════════════════════════════

  HOST (adversarial)
  ┌──────────────┐  ┌─────────────┐  ┌───────────────────┐  ┌─────────────┐
  │ c8s operator │  │ kata-deploy │  │ kata-image-puller │  │ containerd  │
  │ + webhook    │  │             │  │                   │  │ + kata shim │
  └──────────────┘  └─────────────┘  └───────────────────┘  └─────────────┘

In short: node-as-CVM is the all-or-nothing model (verify the node once, trust everything on it, one tenant per node), pod-as-CVM is the mutual-distrust model (the platform and the workloads do not trust each other, and each pod attests independently). The full comparison, including density, latency, and platform support, is in the docs and docs/install-flows.md.

Quickstart

Install c8s onto an existing cluster. The full walkthrough is docs/QUICKSTART.md; the hosted version with provisioning guides is at confidential.ai/docs/c8s.

Prerequisites
  • A Kubernetes cluster (vanilla or RKE2) with platform-admin permissions.
  • Nodes with the TEE hardware for your chosen shape: an AMD SEV-SNP or Intel TDX host for pod-as-CVM, or SEV-SNP / TDX confidential VMs as nodes for node-as-CVM (see the first-cluster tutorial). Node kernels must be recent enough for the TEE (AMD SEV-SNP ≥ 6.11, Intel TDX ≥ 6.16), which also satisfies the Linux ≥ 6.5 SO_PEERPIDFD the admission inventory relies on — see docs/QUICKSTART.md.
  • Helm 3, kubectl, and crane on PATH.
  • Go 1.26+ to build the CLI.
Install
# Build and install the c8s CLI
git clone https://github.com/confidential-dot-ai/c8s
cd c8s
make install

# Label the node that will run CDS
kubectl label node <cds-node> role=cds

# Generate the operator keypair whose public half authorizes allowlist writes
openssl ecparam -name prime256v1 -genkey -noout -out operator.key
openssl ec -in operator.key -pubout -out operator.pub

# Install the platform (node-as-CVM) and point the bundled TLS load balancer
# at your workload
c8s install --cvm-mode=node --hardware-platform=sev-snp --namespace c8s-system \
  --operator-keys operator.pub \
  --workload-ref vllm=vllm/deployment/serving:8000 \
  --upstream vllm

--cvm-mode is required and has no default — node, gke, and aks are the node-as-CVM shapes, pod is pod-as-CVM. --hardware-platform is required the same way: sev-snp or tdx. An unstated shape would silently mismatch the cluster it lands on, so the install refuses to guess.

--workload-ref adopts an existing workload as a confidential workload and resolves its images into the bootstrap allowlist (see existing workload adoption). If you would rather not trust install-time digest resolution, pass --resolve-digests=false and allowlist the digests yourself — see Managing the image allowlist.

Opt workloads in

Application teams opt in by annotating their pod templates:

metadata:
  annotations:
    confidential.ai/cw: api

The annotation value (api here) is a workload id you choose; the certificate SAN and the c8s-<id> headless Service are derived from it.

The webhook injects c8s get-cert as a native sidecar, which fetches an attestation-bound certificate from CDS and renews it. Certificates land in /etc/c8s/certs.

Pod-as-CVM

--cvm-mode=pod installs the Kata runtime and enforces it: every in-scope workload pod becomes a confidential VM, and non-Kata pods are rejected at admission. Pin the kata guest launch digest(s) from c8s kata measure — one per pod shape you run — because an in-guest get-cert refuses to reach a CDS no measurement pins, so an unpinned pod-mode install leaves workloads dead at init:

c8s install --cvm-mode=pod --hardware-platform=sev-snp --namespace c8s-system \
  --operator-keys operator.pub \
  --measurements <cds-guest-digest>,<workload-guest-digest> \
  --workload-ref vllm=vllm/deployment/serving:8000 \
  --upstream vllm

See docs/kata.md for the runtime details and docs/DEMO.md for a minimal demo flow.

Production notes
  • Pin measurements. The chart's RA-TLS handshakes accept any TEE-attested peer until you pin cds.measurements and ratlsMesh.measurements to the expected launch digests. Leave them empty only on a trusted network.

  • Pin operator keys. Pass --operator-keys at install time or allowlist writes stay disabled. Leaving writes disabled and re-deploying CDS on every allowlist change works too, but each restart mints a fresh mesh CA, forcing downstream consumers onto a new root of trust. See Managing the allowlist.

A note on QEMU
  • Pod-as-CVM needs no host QEMU. kata-deploy ships the kata-static payload, which bundles the TEE-capable QEMU builds that kata-qemu-snp and kata-qemu-tdx use. Do not point Kata at a distro QEMU.

  • Node-as-CVM needs QEMU 10.1 or newer, built with --enable-igvm. Booting a measured node image via IGVM requires upstream QEMU's IGVM support, which most distributions do not ship. Check for it with qemu-system-x86_64 -object igvm-cfg,help.

Verifying a cluster from outside

Anyone can verify that a c8s endpoint really terminates inside attested hardware, without trusting the operator's word for it.

Browsers cannot inspect TLS certificates mid-handshake, so RA-TLS alone is not browser-verifiable. The c8s-verify npm package instead runs a challenge-response protocol: the client sends a fresh nonce, the TEE returns a hardware-signed attestation report binding that nonce and an ephemeral public key, and all further traffic flows over a post-quantum over-encrypted channel (ML-KEM) inside the regular TLS session. A malicious TLS-terminating proxy in front of the real endpoint cannot forge it. The wire contract is PROTOCOL.md.

Operators and CLIs can verify directly: c8s cds verify checks a CDS's attestation and reports the operator keys it pins.

Components

Component Description Docs
cmd/cds Certificate Distribution Service - verifies TEE attestation evidence, issues EAR tokens, signs workload CSRs with an in-process mesh CA, and serves the allowlist and secret-release APIs operator docs
cmd/c8s Operator and install CLI for CRDs, status mirroring, webhook injection, and the embedded Helm chart operator docs
cmd/get-cert CLI tool and init-container for TEE-attested certificate provisioning README
cmd/ratls-mesh Transparent L4 proxy wrapping inter-node K8s traffic in RA-TLS README
cmd/nri-image-policy NRI plugin enforcing the image and argv allowlist on the host; also the node's admission inventory allowlist
cmd/policy-monitor The same enforcement and inventory in-guest, baked into the pod-as-CVM image image policy
cmd/volumed Encrypted-volume agent — opens volumes into a pod's mount namespace, as a node DaemonSet or in-guest (--guest) under pod-as-CVM volumes

Libraries

Package Description
pkg/ratls RA-TLS library for hardware-attested mTLS (AMD SEV-SNP, Intel TDX) — see docs/ratls.md
pkg/ratls/cdsclient CDS attestation client for certificate provisioning
pkg/attestclient High-level client for the CDS attestation flow
pkg/attestationclient Low-level HTTP client for the attestation-api
pkg/allowlistclient CRUD client for the CDS allowlist API
pkg/allowlist Allowlist types, argv policy, and secret grants
pkg/workloadclaims Sandbox-token fetch and the admission-inventory socket contract
pkg/overenc Post-quantum over-encryption channel and its identity transcript
pkg/operatorauth Operator-key signing and verification for allowlist and secret writes
pkg/types Shared request/response types
pkg/issuerapi Certificate issuer API types
pkg/earsigner EAR token-signing key lifecycle, rotation, and JWKS serving
pkg/jwks JWKS parsing and key selection
pkg/runtimemeasure TDX image-pin manifests and RTMR[3] measurement replay
pkg/certutil Certificate utility functions

Repository layout

api/               CRD types
cmd/               Binaries: c8s, get-cert, ratls-mesh, nri-image-policy,
                   policy-monitor, volumed, rtmr3-measurer (cmd/cds is only
                   the Dockerfile for the `c8s cds` subcommand,
                   internal/cmds/cds)
internal/          Operator, webhook, attestation, mesh CA, secret store,
                   embedded Helm chart
pkg/               Public Go libraries (see Libraries above)
kata-guest-base/   Confidential guest image recipe for pod-as-CVM
node-guest-image/  The node-image definition for node-as-CVM (new home;
                   phase 0 — nothing consumes it from here yet)
docs/              Design and operator docs
samples/           Example manifests
scripts/           Dev and CI helpers
test/              Integration tests: docker-compose get-cert flow
                   (test/integration) and the kind cluster harness
                   (test/integration/cluster, see docs/integration-tests.md)

Build

Requires Go 1.26+.

# Build the c8s binary for the container images (linux/amd64)
make build

# Build and install the c8s CLI for your host platform, onto PATH
make install

# Run tests
make test

# Mutation-test the changes vs origin/main (BASE=<ref> to override)
make mutation-check

# Lint (format check + vet)
make lint

# Clean build artifacts
make clean

Managing the image allowlist

CDS serves the image-digest allowlist that nri-image-policy (host) and policy-monitor (in-guest) enforce on every node. The c8s allowlist command reads and mutates it. By default, tls-lb publishes the complete /allowlist API and verifies CDS's attestation before forwarding requests. When tls-lb uses the chart default CDS-issued public certificate (tlsLb.publicTLS.secretName is empty, discovery mode cds), point the CLI at the same tls-lb URL used for application traffic; no port-forward is required.

TLS_LB=https://<tls-lb-host>

# Reads are unauthenticated
c8s allowlist export --url "$TLS_LB" \
  --measurements <tls-lb-launch-digest> > allowlist.json
c8s allowlist diff allowlist.json --url "$TLS_LB" \
  --measurements <tls-lb-launch-digest>

# Writes are signed with the operator key
c8s allowlist add sha256:<digest> registry.example.com/app@sha256:<digest> \
  --url "$TLS_LB" --measurements <tls-lb-launch-digest> \
  --operator-key operator.key
c8s allowlist upload allowlist.json \
  --url "$TLS_LB" --measurements <tls-lb-launch-digest> \
  --operator-key operator.key

--measurements identifies the trusted build of the endpoint you connected to. For the default public route, use the tls-lb launch digest; the CLI reads tls-lb's discovery document and verifies its attestation automatically. Direct CDS URLs remain supported, in which case pin the CDS launch digest.

An empty set accepts any attested endpoint. Reads run with a warning; anything that signs with the operator key — every c8s allowlist write and c8s secrets put/explain — is refused, because the credential and its payload would go to whatever answered. A plaintext --insecure dev endpoint is exempt: it already declares that nothing about it is attested.

Do not point this CLI at tls-lb when tlsLb.publicTLS.secretName is set. That front door uses WebPKI (public_tls.mode=webpki), and its public certificate is not cryptographically bound to the discovery attestation, so the CLI deliberately refuses it. Use a direct CDS RA-TLS URL and the CDS launch digest; if CDS is not otherwise routable, use a local port-forward:

kubectl port-forward -n c8s-system svc/c8s-cds 8443:8443 &
c8s allowlist export --url https://localhost:8443 \
  --measurements <cds-launch-digest>

Writes are authorized by an operator EC keypair whose public half CDS pins at install time. Generate one and pin it:

openssl ecparam -name prime256v1 -genkey -noout -out operator.key
openssl ec -in operator.key -pubout -out operator.pub

c8s install --operator-keys operator.pub   # plus your other install flags

Installing without --operator-keys leaves allowlist writes disabled, and c8s install refuses that on the default path unless you pass --force to acknowledge. Supply the private key to the CLI by flag (--operator-key) or environment (C8S_OPERATOR_KEY). Write tokens are short-lived and bound to the request body, so a captured token cannot be replayed against a different payload. The private key remains on the operator machine: tls-lb forwards only the signed request and CDS verifies it against the pinned public key.

Set tlsLb.allowlist.enabled=false to remove the built-in public route. A direct CDS connection, including a local port-forward for debugging, can still be passed explicitly with --url.

Verify CDS's root of trust — its launch measurement and the operator key set it serves — before exposing public ingress, using your own install inputs (the operator public-key bundle). The key list is fetched over the attested serving certificate, so it cannot be substituted in transit (docs/ratls.md):

c8s cds verify https://<cds>:8443 \
  --measurements <launch-digest> \
  --operator-keys operator.pub

A swapped key set fails this closed. The check protects the verifier that runs it, so run it continuously (CI), not only at bootstrap.

Two caveats worth knowing before production: revocation is currently coarse (remove the key from cds.operatorKeys and re-install), and this check protects only verifiers that run it. For GitOps consumers, c8s render-values --operator-keys operator.pub embeds the PEM content (the chart value takes content, never a file path); the chart wiring is described in docs/operator.md.

Docker images

All images are published to GHCR on pushes to main. Release-worthy merges also receive stable vX.Y.Z, X.Y.Z, and X.Y aliases in that same workflow run. Per-role image names remain stable, but each image copies the same multi-mode c8s binary and sets an appropriate entrypoint. See docs/releases.md for the version policy.

The measured node-guest-base artifacts follow the same root release with platform-qualified exact aliases such as rke2-tdx-v0.1.0 and rke2-snp-cdi-v0.1.0; they intentionally have no ambiguous bare or moving SemVer alias.

Image Base Notes
ghcr.io/confidential-dot-ai/c8s-operator distroless Multi-mode c8s binary for operator/install and non-node roles
ghcr.io/confidential-dot-ai/cds distroless
ghcr.io/confidential-dot-ai/get-cert distroless
ghcr.io/confidential-dot-ai/ratls-mesh debian-slim Needs iptables
ghcr.io/confidential-dot-ai/nri-image-policy debian-slim
ghcr.io/confidential-dot-ai/volumed debian-slim Needs cryptsetup/veritysetup

The chart also deploys ghcr.io/confidential-dot-ai/attestation-api, the TEE evidence verification service, which is built and published from attestation-rs.

Known gaps and open items

c8s is built around a strong threat model, and we would rather list the holes than let you discover them:

  • Measurements are not pinned by default. Until cds.measurements and ratlsMesh.measurements are set, the mesh accepts any attested peer. Fine for demos, mandatory homework for production.

  • CDS is a singleton by default. The mesh CA key lives only in CDS process memory; a restart mints a new CA and workloads re-bootstrap. Attested handoff to a successor replica exists behind cds.handoff.enabled — one active CDS at a time, not active/active.

  • Mesh peers are verified by CA chain, not per-peer measurement. Leaves carry the evidence CDS verified at issuance, and VerifyPolicy has a RequireCAEvidence mode that re-checks it — measurement included — on every connection, but no shipped profile enables it. There are no SPIFFE-style URI SANs, and per-workload peer policy is not enforced.

  • A workload's sandbox identity is CA-vouched, not hardware-bound. The sandbox ID in a leaf is signed in by the mesh CA on the word of an on-node admission inventory; it is not folded into the TEE report. Any process that can bind the node's privileged inventory port can vouch for a sandbox it does not run.

  • The image allowlist gates digest and command line, not the rest of the pod spec. Each container's command prefix and args remainder are enforced against the effective argv, and bind-mount destinations and env variable names are enforceable in the guest; capabilities and the remaining pod-spec fields are not. Nothing enforces which images run together — every running image must be allowlisted, but no gate requires the set in one pod to match a single workload entry.

  • Secrets and encrypted volumes under pod-as-CVM carry weaker guarantees than on a node. Both work — the injected fetchers redeem their sandbox token from the in-guest policy-monitor over loopback, and volumed --guest opens devices inside the pod's own CVM — but the sandbox ID a release is gated on is a host-written CRI annotation there, not a value the kernel read, and the allowlist enforcement it consults is in-guest software rather than a host hook. A deployment whose threat model cannot accept either should stay on node-as-CVM.

  • Init containers cannot consume a released secret. The secret volume is mounted into every container in the pod, but CDS releases only once every main container is running — that is when the sandbox matches a whole workload entry. An ordinary init container runs to completion before that point, so it sees an empty directory, and one that blocks waiting for its file deadlocks the pod it gates. Secrets are consumable from main containers, which must wait for the file rather than read it at startup. The injected fetcher is a native sidecar for this reason: it is the one entry in initContainers that keeps running alongside the workload.

  • On TDX, c8s allowlist writes do not reach running confidential pods. In-guest policy-monitor refuses to refresh from CDS unless C8S_CDS_MEASUREMENTS pins the CDS launch digest. On SEV-SNP the webhook delivers that pin in the pod's launch-committed init-data document and running guests pick up writes within one refresh interval; on TDX the guest does not accept the pin, so refresh stays disabled and each guest enforces only the seed baked into its measured image — admitting a new workload image inside a TDX confidential pod means rebuilding the guest image. Installs with no pinned measurements, and the chart-managed pods in the release namespace (which get no init-data), enforce the seed alone on either platform. The gating is deliberately fail-closed — "any attested TEE" is not good enough here, because the host can boot its own CVM from the same guest image and serve an allowlist of its choosing.

  • Root workloads are intercepted but cannot egress to non-mesh peers. In-guest egress exemptions are scoped to the attestation service and the mesh proxy by systemd cgroup (a root workload is in no exemption cgroup), so TCP from a root tenant is redirected into the mesh (which fails for non-mesh destinations) and non-TCP is dropped. Run workloads as non-root so legitimate traffic is mesh-routed.

  • Pod-as-CVM picks one CPU TEE per install. Both SEV-SNP and TDX are supported, but --hardware-platform selects one for the whole cluster; mixed SNP+TDX clusters are not. Pod-as-CVM is also unavailable on Azure, which does not expose nested virtualization.

  • GPU attestation is not wired end to end. GPU passthrough into confidential pods works, and a locked guest fails closed on a non-CC GPU. attestation-rs verifies NVIDIA GPU and NVSwitch evidence (SPDM via NRAS, nonce-bound to the CPU TEE evidence), but c8s does not collect GPU evidence in the guest or require it at certificate issuance, so no positive GPU attestation reaches the relying party.

  • The browser over-encryption channel does not stream. Requests and responses are buffered per envelope; responses over 32 MiB fail rather than stream.

  • Operator key revocation is coarse. No CRL/OCSP; revoking an operator key means removing it and re-installing.

Roadmap

The direction of travel:

  • GPU attestation end to end. Collect GPU evidence in the guest and require it at certificate issuance, so a positive GPU attestation reaches the relying party rather than stopping at the attestation service.

  • In-TEE volume encryption. Stream plaintext into a CVM that generates the key, writes the encrypted volume, and commits the key straight to the secret store, so the party supplying the data never holds the key that opens it. c8s volume create encrypts on the operator's machine, which means the key is generated outside the TEE and escrowed to a local file.

  • IGVM support for Kata. Move the per-pod runtime's measured boot to IGVM, unifying pod-as-CVM and node-as-CVM on one measured-boot format.

  • Encrypted RDMA. Encrypted GPU-to-GPU and node-to-node RDMA for confidential multi-node training and inference.

Standing on the shoulders of the community

c8s exists because a lot of excellent open work came before it, and we want to be loud about that:

  • Kata Containers is the foundation of our pod-as-CVM shape: the runtime, kata-deploy, and the guest tooling are outstanding engineering, and the maintainers have built something genuinely rare: VMs with the operational feel of containers.

  • Confidential Containers pioneered the confidential pod model that c8s builds on, including the guest-pull design that keeps container images out of the host's hands.

  • The Confidential Computing Consortium and the wider ecosystem (the AMD SEV-SNP and Intel TDX stacks, the IGVM format, OVMF, and the NVIDIA confidential computing work) provide the hardware and firmware bedrock all of this stands on.

Where we fix or extend something upstream, we aim to contribute it back.

Contributing and security

Please, before you open an issue or a PR, read CONTRIBUTING.md. It is short, and it explains the contribution terms (you sign the CLA on your first PR), the review bar, our policy on LLM-assisted contributions, and the requirement that commits be signed.

And before you report anything security-shaped, read SECURITY.md. c8s is trust infrastructure: attestation bypasses, policy bypasses, and certificate mis-issuance are security issues. Do not open public issues for them. Email security@confidential.ai instead.

For anything else: hello@confidential.ai.

Licence

c8s is licensed under the GNU Affero General Public License v3.0. Contributions are accepted under the terms in CONTRIBUTING.md.

Directories

Path Synopsis
api
v1alpha2
Package v1alpha2 contains the confidential.ai/v1alpha2 CRD types.
Package v1alpha2 contains the confidential.ai/v1alpha2 CRD types.
cmd
c8s command
Command c8s is the operator-side binary for the confidential Kubernetes stack.
Command c8s is the operator-side binary for the confidential Kubernetes stack.
get-cert command
Command get-cert is a thin wrapper around the `c8s get-cert` cobra subcommand for `go build ./cmd/get-cert` users and the historical image entrypoint.
Command get-cert is a thin wrapper around the `c8s get-cert` cobra subcommand for `go build ./cmd/get-cert` users and the historical image entrypoint.
nri-image-policy command
Command nri-image-policy is a thin wrapper around the `c8s nri-image-policy` cobra subcommand.
Command nri-image-policy is a thin wrapper around the `c8s nri-image-policy` cobra subcommand.
policy-monitor command
Command policy-monitor is the thin wrapper around the `c8s policy-monitor` cobra subcommand.
Command policy-monitor is the thin wrapper around the `c8s policy-monitor` cobra subcommand.
ratls-mesh command
Command ratls-mesh is a thin wrapper around the `c8s ratls-mesh` cobra subcommand.
Command ratls-mesh is a thin wrapper around the `c8s ratls-mesh` cobra subcommand.
rtmr3-measurer command
Command rtmr3-measurer is the thin wrapper around the c8s rtmr3-measurer entry point (mirrors cmd/policy-monitor/main.go).
Command rtmr3-measurer is the thin wrapper around the c8s rtmr3-measurer entry point (mirrors cmd/policy-monitor/main.go).
volumed command
Command volumed is the thin wrapper around the `c8s volumed` cobra subcommand, for the copy baked into the kata guest rootfs.
Command volumed is the thin wrapper around the `c8s volumed` cobra subcommand, for the copy baked into the kata guest rootfs.
internal
audit
Package audit provides structured audit logging for policy decisions.
Package audit provides structured audit logging for policy decisions.
cmds/allowlist
Package allowlist implements the `c8s allowlist` operator CLI for reading and mutating the CDS-served image allowlist that nri-image-policy enforces on every node.
Package allowlist implements the `c8s allowlist` operator CLI for reading and mutating the CDS-served image allowlist that nri-image-policy enforces on every node.
cmds/allowlistproxy
Package allowlistproxy implements the loopback proxy used by tls-lb to publish CDS's allowlist API.
Package allowlistproxy implements the loopback proxy used by tls-lb to publish CDS's allowlist API.
cmds/attestproxy
Package attestproxy implements the node-local front door to the attestation-api.
Package attestproxy implements the node-local front door to the attestation-api.
cmds/cds
Package cds implements the Certificate Distribution Service subcommand: the c8s trust root (attestation, EAR issuance, mesh CA, leaf signing, handoff).
Package cds implements the Certificate Distribution Service subcommand: the c8s trust root (attestation, EAR issuance, mesh CA, leaf signing, handoff).
cmds/cdsattest
Package cdsattest implements the tls-lb attestation + over-encryption sidecar: the *dynamic* client-facing endpoints of the c8s-verify protocol.
Package cdsattest implements the tls-lb attestation + over-encryption sidecar: the *dynamic* client-facing endpoints of the c8s-verify protocol.
cmds/cdsconn
Package cdsconn builds what an operator CLI needs to reach CDS: an HTTP client that has verified the endpoint's attestation, and the operator credential that signs a write.
Package cdsconn builds what an operator CLI needs to reach CDS: an HTTP client that has verified the endpoint's attestation, and the operator credential that signs a write.
cmds/cmdsutil
Package cmdsutil holds tiny helpers shared across the c8s subcommand packages under internal/cmds/.
Package cmdsutil holds tiny helpers shared across the c8s subcommand packages under internal/cmds/.
cmds/credrelease
Package credrelease implements the in-guest credential-release service (B4 of the operator-key design).
Package credrelease implements the in-guest credential-release service (B4 of the operator-key design).
cmds/getcert
Package getcert implements the get-cert subcommand: it requests a TLS certificate from CDS by proving the caller runs inside a TEE.
Package getcert implements the get-cert subcommand: it requests a TLS certificate from CDS by proving the caller runs inside a TEE.
cmds/getkubeconfig
Package getkubeconfig implements the operator-side client (B4 client) that obtains a kube credential from a measured CVM: it attests the node, confirms the full measured identity — on TDX the image tuple (MRTD, RTMR[1], RTMR[2]) plus the RTMR[3] chain seeded by the operator's key and extended by the expected workload images; on SEV-SNP the pinned per-SMP launch digest plus the operator-key HOSTDATA binding — then exchanges a CSR for a short-lived kube client cert over the cred-release endpoint and assembles a kubeconfig.
Package getkubeconfig implements the operator-side client (B4 client) that obtains a kube credential from a measured CVM: it attests the node, confirms the full measured identity — on TDX the image tuple (MRTD, RTMR[1], RTMR[2]) plus the RTMR[3] chain seeded by the operator's key and extended by the expected workload images; on SEV-SNP the pinned per-SMP launch digest plus the operator-key HOSTDATA binding — then exchanges a CSR for a short-lived kube client cert over the cred-release endpoint and assembles a kubeconfig.
cmds/getsecret
Package getsecret implements the get-secret subcommand: the sidecar that fetches a workload's secrets from CDS and writes them into the pod.
Package getsecret implements the get-secret subcommand: the sidecar that fetches a workload's secrets from CDS and writes them into the pod.
cmds/getvolume
Package getvolume implements the get-volume subcommand: the sidecar that fetches a volume's key blob from CDS and hands it to the node's volumed, which opens the device and mounts it into this pod.
Package getvolume implements the get-volume subcommand: the sidecar that fetches a volume's key blob from CDS and hands it to the node's volumed, which opens the device and mounts it into this pod.
cmds/katameasure
Package katameasure implements `c8s kata measure`: the offline predictor for a kata confidential guest's launch measurement, on SEV-SNP and on TDX.
Package katameasure implements `c8s kata measure`: the offline predictor for a kata confidential guest's launch measurement, on SEV-SNP and on TDX.
cmds/nri-image-policy
Package nriimagepolicy is an NRI plugin that validates container images against a digest allowlist.
Package nriimagepolicy is an NRI plugin that validates container images against a digest allowlist.
cmds/policymonitor
Package policymonitor implements the in-VM container-digest enforcement daemon baked into kata-guest-base.
Package policymonitor implements the in-VM container-digest enforcement daemon baked into kata-guest-base.
cmds/probefile
Package probefile implements the probe-file subcommand: a tiny file-existence helper for distroless containers.
Package probefile implements the probe-file subcommand: a tiny file-existence helper for distroless containers.
cmds/requesthandoff
Package requesthandoff implements `c8s cds request-handoff`: the client side of the attested mesh-CA handoff (/handoff), runnable standalone as a live-cluster rollout-continuity probe.
Package requesthandoff implements `c8s cds request-handoff`: the client side of the attested mesh-CA handoff (/handoff), runnable standalone as a live-cluster rollout-continuity probe.
cmds/rtmr3measurer
Package rtmr3measurer is the in-VM workload measurer: it scans kata-agent's container bundles under /run/kata-containers and extends TDX RTMR[3] with each deployed workload's image digest, binding WHICH container ran into the guest's attestation — dynamically, for any image, with no baked allowlist.
Package rtmr3measurer is the in-VM workload measurer: it scans kata-agent's container bundles under /run/kata-containers and extends TDX RTMR[3] with each deployed workload's image digest, binding WHICH container ran into the guest's attestation — dynamically, for any image, with no baked allowlist.
cmds/secrets
Package secrets implements the `c8s secrets` operator CLI for the CDS secret store.
Package secrets implements the `c8s secrets` operator CLI for the CDS secret store.
cmds/sidecar
Package sidecar holds the CDS-release plumbing shared by the get-secret and get-volume sidecars: the config they render from the webhook, the mTLS client bound to the pod's leaf, the challenge/sandbox-token dance around each store request, and the retry loop that turns "not released yet" into bounded patience.
Package sidecar holds the CDS-release plumbing shared by the get-secret and get-volume sidecars: the config they render from the webhook, the mTLS client bound to the pod's leaf, the challenge/sandbox-token dance around each store request, and the retry loop that turns "not released yet" into bounded patience.
cmds/volume
Package volume implements the `c8s volume` operator CLI: building an encrypted, integrity-protected block image and putting its key into the CDS secret store.
Package volume implements the `c8s volume` operator CLI: building an encrypted, integrity-protected block image and putting its key into the CDS secret store.
cmds/volumed
Package volumed implements the node agent that opens encrypted volumes for the pods on it.
Package volumed implements the node agent that opens encrypted volumes for the pods on it.
containerd
Package containerd provides tag-to-digest resolution via the containerd image store.
Package containerd provides tag-to-digest resolution via the containerd image store.
controller
Package controller hosts the controller-runtime manager, the slim ConfidentialWorkload status-mirror reconciler, and the admission webhook.
Package controller hosts the controller-runtime manager, the slim ConfidentialWorkload status-mirror reconciler, and the admission webhook.
crane
Package crane wraps the crane CLI (github.com/google/go-containerregistry): digest resolution, image config, manifest existence, and the error shapes callers key behaviour on.
Package crane wraps the crane CLI (github.com/google/go-containerregistry): digest resolution, image config, manifest existence, and the error shapes callers key behaviour on.
crane/cranetest
Package cranetest installs a crane CLI stub on PATH for tests of crane-backed commands, so they run without a registry or the real binary.
Package cranetest installs a crane CLI stub on PATH for tests of crane-backed commands, so they run without a registry or the real binary.
ear
fileutil
Package fileutil holds small filesystem helpers shared across c8s commands.
Package fileutil holds small filesystem helpers shared across c8s commands.
helmchart
Package helmchart bundles the c8s Helm chart into the Go binary so `c8s install` is a single-file install tool — no side chart download.
Package helmchart bundles the c8s Helm chart into the Go binary so `c8s install` is a single-file install tool — no side chart download.
httputil
Package httputil holds small HTTP-handler utilities shared across c8s internal packages.
Package httputil holds small HTTP-handler utilities shared across c8s internal packages.
issuer
Package issuer generates CA keypairs and signs workload X.509 certificates in-process.
Package issuer generates CA keypairs and signs workload X.509 certificates in-process.
kataspec
Package kataspec reads the parts of kata-agent's on-disk container bundle that c8s makes trust decisions on.
Package kataspec reads the parts of kata-agent's on-disk container bundle that c8s makes trust decisions on.
lbdiscovery
Package lbdiscovery consumes the tls-lb front-door discovery contract (types.DiscoveryDocument, served at /v1/discovery, written by get-cert).
Package lbdiscovery consumes the tls-lb front-door discovery contract (types.DiscoveryDocument, served at /v1/discovery, written by get-cert).
localverify
Package localverify verifies attestation evidence in-process with attestation-go (the Go port of the attestation-rs engine the cluster runs), auto-detecting the platform from the envelope tag.
Package localverify verifies attestation evidence in-process with attestation-go (the Go port of the attestation-rs engine the cluster runs), auto-detecting the platform from the envelope tag.
sandboxledger
Package sandboxledger records which node's admission inventory vouched for a pod sandbox, so a later decision about that sandbox asks the same inventory rather than one the requester names.
Package sandboxledger records which node's admission inventory vouched for a pod sandbox, so a later decision about that sandbox asks the same inventory rather than one the requester names.
secrets
Package secrets holds the CDS secret store and the policy that gates access to it.
Package secrets holds the CDS secret store and the policy that gates access to it.
testattest
Package testattest serves a fake attestation-api for tests.
Package testattest serves a fake attestation-api for tests.
version
Package version exposes the c8s build version.
Package version exposes the c8s build version.
webhook
Package webhook contains the mutating admission webhook that injects the c8s get-cert containers into pods opted in by annotation.
Package webhook contains the mutating admission webhook that injects the c8s get-cert containers into pods opted in by annotation.
node-guest-image
c8s/systemfloor command
Command systemfloor regenerates the RKE2 system-image floor in image-policy.yaml.in: the always_allow entries that admit the node's baked system components (rke2 static pods, Cilium, CoreDNS, local-path-storage).
Command systemfloor regenerates the RKE2 system-image floor in image-policy.yaml.in: the always_allow entries that admit the node's baked system components (rke2 static pods, Cilium, CoreDNS, local-path-storage).
pkg
allowlist
Package allowlist defines the CDS-served image allowlist and its deterministic canonical serialization.
Package allowlist defines the CDS-served image allowlist and its deterministic canonical serialization.
allowlistclient
Package allowlistclient is the HTTP client for the CDS allowlist API.
Package allowlistclient is the HTTP client for the CDS allowlist API.
certutil
Package certutil provides common helper functions shared across the ratls project: serial number generation, fingerprinting, PEM encoding, and more.
Package certutil provides common helper functions shared across the ratls project: serial number generation, fingerprinting, PEM encoding, and more.
earsigner
Package earsigner manages the EAR token-signing key lifecycle with overlap-based rotation and JWKS serving.
Package earsigner manages the EAR token-signing key lifecycle with overlap-based rotation and JWKS serving.
initdata
Package initdata builds and reads the kata init-data document c8s delivers into a confidential guest.
Package initdata builds and reads the kata init-data document c8s delivers into a confidential guest.
issuerapi
Package issuerapi defines the wire types for the CDS signing/handoff HTTP API.
Package issuerapi defines the wire types for the CDS signing/handoff HTTP API.
jwks
Package jwks wraps go-jose to produce JWK Sets from ECDSA public keys.
Package jwks wraps go-jose to produce JWK Sets from ECDSA public keys.
operatorauth
Package operatorauth implements the operator-credential scheme that authorizes c8s allowlist mutations (POST/PUT/DELETE /allowlist).
Package operatorauth implements the operator-credential scheme that authorizes c8s allowlist mutations (POST/PUT/DELETE /allowlist).
overenc
Package overenc implements the c8s-verify post-quantum over-encryption channel that terminates inside the Load Balancer's TEE.
Package overenc implements the c8s-verify post-quantum over-encryption channel that terminates inside the Load Balancer's TEE.
ratls
Package ratls implements RA-TLS (Remote Attestation TLS) for AMD SEV-SNP and Intel TDX.
Package ratls implements RA-TLS (Remote Attestation TLS) for AMD SEV-SNP and Intel TDX.
ratls/cdsclient
Package cdsclient implements certificate provisioning via the CDS attestation-api.
Package cdsclient implements certificate provisioning via the CDS attestation-api.
resources
Package resources defines the c8s resource path constants used in the EAR-driven access-control model: a resourceMap maps each attested launch measurement to the list of resources that measurement is authorised for.
Package resources defines the c8s resource path constants used in the EAR-driven access-control model: a resourceMap maps each attested launch measurement to the list of resources that measurement is authorised for.
runtimemeasure
Package runtimemeasure pins the c8s conventions for runtime measurement: what a guest extends into its runtime measurement register after launch, and in what order.
Package runtimemeasure pins the c8s conventions for runtime measurement: what a guest extends into its runtime measurement register after launch, and in what order.
snpmeasure
Package snpmeasure computes the SEV-SNP launch measurement (launch digest) of a QEMU guest offline, from the firmware and boot artifacts, before the guest is ever started.
Package snpmeasure computes the SEV-SNP launch measurement (launch digest) of a QEMU guest offline, from the firmware and boot artifacts, before the guest is ever started.
tdxmeasure
Package tdxmeasure computes the Intel TDX build-time measurement (MRTD) of a kata confidential guest offline, from the TDVF firmware image, before the guest is ever started.
Package tdxmeasure computes the Intel TDX build-time measurement (MRTD) of a kata confidential guest offline, from the TDVF firmware image, before the guest is ever started.
workloadclaims
Package workloadclaims implements the admission-inventory API: the component that admitted a pod's containers (nri-image-policy on node-CVM, policy-monitor in a kata guest) is the arbiter of both what runs in a pod sandbox and which sandbox a process belongs to.
Package workloadclaims implements the admission-inventory API: the component that admitted a pod's containers (nri-image-policy on node-CVM, policy-monitor in a kata guest) is the arbiter of both what runs in a pod sandbox and which sandbox a process belongs to.
test
integration/cluster/optoken command
optoken mints the operator Authorization header for a CDS write, using the production signer (pkg/operatorauth).
optoken mints the operator Authorization header for a CDS write, using the production signer (pkg/operatorauth).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL