The verification model
How C8s separates hardware evidence, mesh identity, workload authorization, and client policy acceptance, and binds them to a front-door connection.
Verification connects hardware evidence to a decision about an endpoint. Evidence can establish an image measurement or bind a public key; the verifier still needs independently trusted inputs to decide whether that image, cluster, workload, and routing policy are acceptable. The Certificate Distribution Service (CDS) issues pod credentials under the mesh certificate authority (CA). In C8s, verification happens at different events:
| Who verifies | When | What is checked |
|---|---|---|
| CDS | Certificate issuance and renewal | Challenge-bound hardware evidence and admitted node identity; sandbox admission for pod identities |
| Pod mesh endpoints | Each TLS handshake | The CDS-issued certificate chain, certificate purpose and validity, mesh protocol, and sandbox identity |
| An operator | Each explicit verification | Certificate or HTTP-delivered evidence against the operator's image, configuration, identity, and policy inputs |
| A front-door client | Attestation of its session or connection | Evidence and identity bound to that exchange, followed by the client's acceptance of the reported state |
A nonce is a fresh challenge that binds evidence to a particular exchange. A certificate's embedded evidence instead binds its public key and can be replayed within the authenticated certificate's validity window. Neither is continuous observation of a running process.
Service-to-service verification (RA-TLS)
Remote attestation TLS (RA-TLS) combines TLS authentication with attestation evidence. C8s uses it to authenticate the CDS and node inventory services. The ordinary pod mesh uses the identities CDS issues after its attestation and admission checks.
At issuance, CDS verifies evidence bound to the requester's public key and its challenge. A sandbox is the container runtime's execution unit for one pod. For a pod identity, CDS also checks a sandbox token and queries the node's authenticated inventory for the sandbox's container images. The issued leaf certificate, the pod certificate signed by the mesh CA, carries the sandbox ID.
Each workload allowlist entry describes permitted main and init containers and their startup rules. CDS adds a matched workload name and the allowlist version and digest when exactly one entry accounts for the sandbox's recorded workload-container admissions and that record includes every required main container. The inventory retains admissions for the sandbox's lifetime, including containers that have exited or been removed. Injected mesh and credential containers are handled separately. See the issuance flow.
An issuance request carries the fresh, challenge-bound evidence separately from its certificate signing request (CSR). The CSR can also contain evidence bound to the public key alone; CDS copies that evidence into the issued certificate when supplied. These are two distinct evidence objects. An evidence verifier inspecting the certificate must authenticate its signed body as well as validate its embedded evidence; the mesh CA signature vouches for its sandbox and workload claims.
The injected mesh endpoints use TLS 1.3 and check the peer's chain, purpose, validity, negotiated mesh protocol, and mandatory sandbox ID. They authenticate membership in this mesh without rechecking hardware evidence on each connection. The ordinary pod mesh applies no destination workload-name policy. The router adds that authorization for workload routes, as described under transitivity of trust.
Applications serve ordinary TCP or HTTP inside the pod. Platform containers hold the mesh credentials; admission rejects application mounts of the credential volume. These controls depend on the accepted node image and its enforcement, within the shared node trust boundary.
The verifier engine
c8s verify calls attestation-go in process to validate hardware evidence. It can obtain that
evidence from a serving certificate, HTTP discovery, a fresh front-door attestation exchange,
or a saved file. The JavaScript client calls a WebAssembly verifier and checks its returned
claims. Their interfaces and supported evidence forms are documented in the
CLI reference and
JavaScript reference.
Hardware-evidence validation and caller policy acceptance are separate checks. C8s compares verified claims with the expected image measurements and measurement-register values. The CLI rejects debug-enabled guests by default; its minimum SEV-SNP trusted computing base (TCB) component values default to zero. Selecting an acceptable patch level requires an explicit floor. Revocation and collateral checks depend on the verifier path and supplied inputs; a successful signature check alone does not establish them.
A result can be partial when evidence validates but another presented property remains unproven, such as a responder-chosen mesh CA or policy history without caller acceptance. Read the verdict's scope, warnings, and unproven properties together. A successful operator check establishes the evidence claims, bindings, and configured policies covered by that verification mode. Clients must independently verify the session or TLS connection carrying their data.
Whole-image matching
An image policy is a set of acceptable identities. C8s matches one entry completely, rather than accepting a launch digest from one entry and register values from another:
| Platform | Image values matched together |
|---|---|
| AMD SEV-SNP | The expected launch digest, with separate entries for the required build and VM shapes |
| Intel TDX | MRTD and RTMR[1]/RTMR[2] from the same image build |
MRTD is the TDX launch measurement; RTMRs are runtime measurement registers. C8s's TDX image policy uses RTMR[1] and RTMR[2] alongside MRTD to identify the guest image. RTMR[3] has a separate role: it can bind the operator-key seed and measured workload-policy history. An RTMR[3] value alone does not identify the image that extended it. See pinning multiple measurements for policy formats.
Image pins also need the applicable launch-configuration bindings. In particular, CDS checks
its required configuration file against its own verified launch evidence before serving.
That file supplies its initial operator keys, workload policy, inventory address ranges, and
certificate naming policy. Its node identities establish admission for a singleton CDS and
provide the default node set for Genesis, the signed command that starts a high-availability
(HA) CDS cluster. Genesis can select another initial node set. A CDS identity pin binds both
its image and the exact configuration bytes; the CLI requires this complete policy for a CDS
target, commonly supplied as cds-pin.json.
Three policies remain independent: the CDS identity a client accepts, the node identities CDS
admits, and the node or router identity a verifier expects. Later signed commands in an HA CDS
deployment can change the live admitted-node policy. Checking CDS's current /measurements
set requires an explicit --served-policy-file containing the independently intended current
policy. The launch pin establishes the measured configuration. The served-policy comparison
checks the current admitted-node set, including the set selected by Genesis or later signed
commands. See the trust root.
Measured policy history
Policy history is an additional, optional TDX check. The node's image-admission plugin,
nri-image-policy, uses a journal: an ordered record of measured policy digests. When policy
measurement is enabled, the plugin checks journal capacity and calls the journal's measurement
operation to extend RTMR[3] before applying a pulled policy. Measurement failure retains the
previous policy. This requires a supported deployment with the runtime journal and attestation
API mounts. Policy measurement is disabled in the stock baked image, and Helm rejects enabling
it with node.baked. On SNP, the measurement setting has no runtime register to extend.
A verifier starts replay from its pinned operator-key seed, the initial RTMR[3] value derived from the launch's operator public key. It replays the reported policy digests and authenticates the prefix ending at the attested RTMR[3] value. Reproducing that value proves a measurement history; accepting the policies in it is a separate decision. Acceptance covers every replayed digest and the policy under which the leaf was issued. The leaf's issuing-policy stamp needs an authenticated mesh CA, and current-history verification needs fresh nonce-bound evidence.
The CLI supports explicit policy-digest pins or signatures checked against separately supplied policy-acceptance keys. Its route/CDS operator-key option serves a different purpose. The JavaScript client accepts explicit policy pins and normally refuses partial history results. The CLI and JavaScript references describe the inputs and verdicts. A verdict without measured history does not establish which policies ran earlier.
What the front door exposes
The C8s Load Balancer, also called the router, runs nginx and cds-attest inside the
node confidential VM's trusted execution environment (TEE). It applies an operator-signed
route manifest fetched from CDS. That manifest selects the backends for application requests;
each backend has its own authentication requirements.
Front-door attestation is enabled by default. attest-pq establishes the application-layer
encrypted session described below, and tunnel carries its records. Native clients can use
attest-lb to bind evidence to the exact serving certificate they observed on their TLS
connection. Front-door TLS credential modes select the serving credential: cds uses a
CDS-issued certificate with its private key held in the TEE. The acme mode obtains the
certificate through an in-guest ACME client and also keeps its private key in the TEE. Both
support attest-lb. The webpki mode uses a host-visible Kubernetes Secret and rejects
attest-lb with external_tls; attest-pq remains available.
Discovery certificates, published routes, and allowlist documents supply material to verify.
Their arrival over ordinary HTTPS does not make them independent trust anchors. Obtain pins
through a trusted path, then check the fetched material against them. Protocol details belong
in the JavaScript reference and
cds-attest reference.
The chart's default Cross-Origin Resource Sharing (CORS) policy lets browser code from any origin read protocol endpoints without credentialed browser requests. Application routes have a separate CORS policy; the protocol default does not authorize browser access to every routed application.
The idea: over-encryption, not certificate extensions
The browser client verifies evidence returned in an HTTPS response, then establishes an encrypted channel carried over HTTPS. An outer TLS terminator can relay the exchange while remaining outside the channel's trust boundary:
Browser Outer TLS terminator Router in node TEE
| | |
| nonce + X-Wing public key | |
|----------------------------------+----------------------------->|
| | Create ciphertext and ID |
| | Attest exchange transcript|
| | Sign with mesh leaf key |
| evidence + ciphertext + ID + mesh chain + signature |
|<---------------------------------+------------------------------|
| Verify evidence, image, identity, transcript, and chosen policies|
| Derive channel keys | |
|----------------------------------+----------------------------->|
| encrypted application request |
|<---------------------------------+------------------------------|
| encrypted application response |The transcript is a hash of the protocol domain, front-door mode, exact mesh CA and leaf, both key-exchange messages, session ID, client nonce, and applied route digest. Hardware evidence binds this transcript through REPORTDATA or the platform's vTPM freshness anchor. The mesh leaf signs the same transcript, proving possession of that identity's private key.
These checks bind the exchange to the attested identity. Protection of router-side keys and plaintext also depends on the accepted guest image and its credential isolation. The client holds the other end's session keys. An outer terminator can still observe session identifiers, sequence numbers, sizes, and timing, and can interrupt the connection.
The post-quantum over-encryption channel
X-Wing combines X25519 and ML-KEM-768 for hybrid key establishment. The client supplies a fresh 32-byte nonce and encapsulation key. The router encapsulates to that key and creates a 16-byte session ID. After checking the returned evidence, identity proof, and caller policies, the client decapsulates the ciphertext to recover the shared secret.
Both parties use HKDF-SHA256 with the SHA-384 transcript hash as its salt. This binds the
derived AES-256-GCM keys and nonce prefixes to the verified exchange, with separate keys for
each direction. It also derives a 32-byte exporter, a channel-binding value the router forwards
to the backend as X-C8s-Exporter. The identity signature is ECDSA, so cluster authentication
remains classical even though key establishment is hybrid.
Each tunnel record seals the application method, path, headers, and body. The router opens
it inside the node TEE, selects the route using the sealed Host header and path, authenticates
the backend, and seals the response. Record authentication binds direction, session ID, and
sequence number; responses must match their request's sequence. The router rejects repeated
requests and sequences outside its 64-record replay window.
Routing changes and session lifetime
Attestation binds the applied route digest. The client accepts that routing state by pinning
its digest or checking the published manifest under trusted operator keys. The CLI requires
one of these for public front-door attestation modes. JavaScript permits an unverified route
policy unless the caller selects routeDigests or routeOperatorKeys; inspect routePolicy.
The session or connection binding records both the applied route digest and the allowlist
digest carried by the attested router certificate, when present. The transcript binds that
certificate, so its allowlist digest is bound through the certificate. Before forwarding later
requests, the router compares the current route and router allowlist digests with this binding.
A change refuses the request with HTTP 503 and route_digest_changed or router_digest_changed.
It ends a PQ session; a bound native TLS connection requires re-attestation. These admission
checks do not cancel an exchange already in progress.
PQ sessions have an idle timeout and an absolute lifetime, defaulting to five minutes and
five hours. Native connection bindings have separate capacity and idle-expiry limits. The
JavaScript client reports non-success tunnel HTTP responses as channel_error; transport
errors propagate. After session expiry or invalidation, the caller must reconnect. Application
requests are not replayed automatically.
Streaming responses
The tunnel buffers each backend response before sealing it. A streaming inference response therefore arrives as one completed record, subject to the 32 MiB response limit. Sealed requests are limited to 8 MiB.
The ordinary application path supports streaming. Browser clients using that path rely on its
outer TLS termination for confidentiality. A native client can instead verify attest-lb
against its own TLS connection and stream over that attested connection when the front-door
mode supports it. An operator's earlier verification of another connection does not provide
this binding for the client.
Why cluster identity is pinned
Accepted image and launch-configuration pins identify code and public launch inputs. Another genuine deployment can run the same public image and policy. A pinned mesh CA distinguishes the intended cluster from such a clone: the transcript commits the exact CA and leaf, and the leaf's private key signs it. Copying the public chain alone does not satisfy this proof.
The JavaScript client also permits canonical allowlist bytes as a deployment-class anchor. That checks the leaf's workload-policy stamp, but cannot distinguish clones with the same public inputs. A specific-cluster result uses the independently pinned mesh CA. The CLI requires a pinned CA to authenticate CA-issued certificate bodies; a responder-chosen CA in a fresh attestation bundle leaves deployment identity partial.
Image and launch-configuration pins, the cluster anchor, workload-policy acceptance, and route-policy acceptance answer different questions. Supply each one needed for the intended guarantee, including explicit acceptance of measured history when that feature is used.
Transitivity of trust
A consumer verifies the router and relies on its accepted code and policy to authenticate the next hop. That reliance has different scope for the two backend types:
| Backend type | What the router authenticates |
|---|---|
| Workload | The pod mesh identity under CDS's CA and the workload name required by the signed route; a router whose certificate carries an allowlist digest also requires the backend's digest to equal it |
| Address | The configured TLS server name and chain under the route's explicit CA anchors; it offers the router credential as a client identity and rejects a mesh-CA chain |
A route's workload name identifies a complete allowlist entry. Kubernetes Service discovery uses a separate identifier. The workload's certificate stamp records CDS's issuance decision, bounded by the certificate lifetime; it is not a continuous check of the backend's process state. The node's admission and mesh enforcement are part of the trusted implementation.
Address-backend authentication establishes the configured TLS identity. It establishes neither a C8s workload identity nor confidential execution at that backend. The router opens the client's request before forwarding it, so a claim that data stays within TEEs requires the chosen backend and every further hop to preserve that boundary. Ordinary mesh membership alone supplies no general workload authorization for those later hops.
See also
- c8s-verify (JavaScript) — client options, protocol results, and errors.
- Verify a deployment — operator verification procedures.
- The trust root — CDS authority, issuance, and credential isolation.