CLI Reference
Type, default, and effect for every flag of every c8s command — install and uninstall, the CDS, allowlist, secrets and volumes, the in-pod fetchers, and the node-side daemons.
One section per command, mirroring the flag definitions in the c8s source. Each table lists every flag of the command above it.
The c8s binary also responds to the symlink aliases get-cert, ratls-mesh, and
nri-image-policy (each auto-prepends the matching subcommand).
c8s install
Install the c8s operator, CRDs, attestation-api, and component charts via Helm. Flags are registered with cobra/pflag.
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--namespace | string | c8s-system | No | namespace to install into |
--release | string | c8s | No | Helm release name |
-f, --values | string slice | nil | No | values files (repeatable) |
--wait | bool | true | No | wait for the release to become ready (helm --wait) |
--install-crds | bool | true | No | install chart CRDs (false passes helm --skip-crds) |
--webhook-cert-fs-group | int64 | 65532 | No | fsGroup for injected certificate volume |
--webhook-get-cert-renew-interval | duration | 6h | No | renewal interval for injected workload certificates |
--webhook-get-cert-run-as-user | int64 | 65532 | No | runAsUser for injected get-cert containers |
--webhook-get-cert-run-as-group | int64 | 65532 | No | runAsGroup for injected get-cert containers |
--webhook-get-cert-run-as-non-root | bool | true | No | set runAsNonRoot for injected get-cert containers |
--single-node | bool | false | No | single-node / single-CVM cluster: clear the dedicated-CDS-node selector and taint toleration so every node is CDS-eligible (no role=cds label or dedicated node needed). Sets cds.node.selector={} and cds.node.tolerations=[] |
--volumes | bool | false | No | Deploy volumed, the node agent for encrypted volumes. |
--cvm-mode | string | "" | Yes | Deployment shape: bare-metal (self-managed confidential node), gke (GKE confidential nodes), or aks (Azure vTPM nodes). All modes use one node CVM as the trust domain. |
--hardware-platform | string | "" | Yes | CPU-level TEE hardware (orthogonal to --cvm-mode): sev-snp (/dev/sev-guest) or tdx (Intel TDX, /dev/tdx-guest). Under --cvm-mode=aks both ride the Azure vTPM (/dev/tpm0, no guest device): sev-snp selects the az-snp shape, tdx selects az-tdx |
--image-tag | string | "" | No | component image tag to resolve digests at (default: the CLI build version, or main for an unstamped build); override to pin a specific branch/tag/release |
--resolve-digests | bool | true | No | resolve each component image tag to its registry digest (via crane), pin it, and add the resolved images to the NRI allowlist. Pass --resolve-digests=false when supplying digests via -f |
--attest | bool | true | No | deploy the router attestation sidecar that serves /.well-known/c8s/ (browser and CLI verification via c8s-verify); --attest=false sets router.attest.enabled=false and omits it |
--node-cidr | string slice | nil | No | CIDR(s) containing node sandbox inventories; by default CDS derives one host route per node. |
--measurements | string slice | nil | No | Expected node CVM launch measurement(s), pinned into CDS and ratls-mesh; empty leaves measurement pinning disabled (unsafe). Cannot be combined with --measurements-config. |
--measurements-config | string | "" | No | path to a measurements config listing the VM images this cluster runs, each matched as a whole image. Templated down to cds and ratlsMesh, and fanned out flat so every component keeps pinning. Cannot be combined with --measurements or --rtmrs |
--rtmrs | string slice | nil | No | TDX RTMR pin(s) <index>=<sha384-hex> completing --measurements on --hardware-platform=tdx (repeatable / comma-separated); sets cds.rtmrs and ratlsMesh.rtmrs. RTMR[1] is the guest kernel, RTMR[2] the command line carrying the dm-verity root hash; without them the measurement pin covers TDVF firmware only. Ignored for SEV-SNP evidence. Cannot be combined with --measurements-config |
--image-pull-secret | string | "" | No | name of an existing kubernetes.io/dockerconfigjson Secret in the release namespace; the chart appends it to every component's imagePullSecrets, so all pods pull the c8s images from an authenticated registry from first start. The Secret is never created or managed by the install — install fails fast when it is missing or has the wrong type |
--workload-ref | string slice | nil | No | existing workload to adopt as a confidential workload, as <cw-id>=<namespace>/<kind>/<name>[:<port>]; repeatable. Kind is any resource exposing a pod template at spec.template (deployment, statefulset, daemonset, or an operator CRD such as <kind>.<group>); install patches the pod template with confidential.ai/cw=<cw-id> once c8s is ready. The optional :<port> is the router upstream port, required on the ref --upstream selects |
--upstream | string | "" | No | confidential.ai/cw id of the adopted --workload-ref workload router routes its catch-all to; derives the mesh-wrapped upstream c8s-<id>.<ns>.svc.cluster.local:<port> from that ref's :<port>. Without this or a verified-https router.upstream, router renders no catch-all route until one is attached |
--operator-keys | string | "" | No | path to a PEM bundle of operator EC public keys that authorize c8s allowlist writes; sets cds.operatorKeys. Without it, allowlist writes are disabled (reads still served). See creating the operator credential |
--force | bool | false | No | Proceed past guarded install prompts, including missing operator keys or a platform image-policy floor that would deny system pods. |
c8s uninstall
Uninstall the c8s Helm release and sweep c8s host artifacts, including image-policy and mesh state. Requires Helm and kubectl on PATH.
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--namespace | string | c8s-system | No | namespace the release was installed into |
--release | string | c8s | No | Helm release name |
--wait | bool | true | No | Wait for the Helm release deletion to finish. |
--host-sweep | bool | true | No | Sweep c8s host artifacts after deleting the release. |
--host-sweep-only | bool | false | No | skip the helm uninstall and run only the host sweep — for a cluster whose release is already gone (e.g. a previous bare helm uninstall) but whose nodes still carry c8s artifacts. Uses the chart defaults and the distro detected from the cluster when the release values are unavailable |
--force | bool | false | No | Allow uninstall while pods hold c8s encrypted volumes; open mappings can block cleanup. |
--delete-crds | bool | false | No | also delete the ConfidentialWorkload CRD — this deletes every ConfidentialWorkload object in the cluster with it |
--delete-namespace | bool | false | No | also delete the release namespace (and everything left in it, e.g. an operator-created image pull Secret) |
c8s render-values
Print the resolved Helm values an install would apply, to stdout — without contacting a
cluster. Useful for feeding a GitOps consumer (e.g. a Flux HelmRelease's valuesFrom) instead
of recomputing digests and device mappings. Unlike install, the host distro is not autodetected —
pass --distro to pin it. Still needs the registry reachable for the default digest resolution
(--resolve-digests=true).
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--distro | string | "" | No | host Kubernetes distro (k8s | rke2); install autodetects it, render-values does not, so pass it to pin the value (unset leaves the chart default) |
--single-node | bool | false | No | single-node / single-CVM cluster: clear the dedicated-CDS-node selector and toleration (cds.node.selector={}, cds.node.tolerations=[]) |
--volumes | bool | false | No | Deploy volumed, the node agent for encrypted volumes. |
--cvm-mode | string | "" | Yes | Deployment shape: bare-metal (self-managed confidential node), gke (GKE confidential nodes), or aks (Azure vTPM nodes). All modes use one node CVM as the trust domain. |
--hardware-platform | string | "" | Yes | CPU-level TEE hardware (orthogonal to --cvm-mode): sev-snp (/dev/sev-guest) or tdx (Intel TDX, /dev/tdx-guest). Under --cvm-mode=aks both ride the Azure vTPM (/dev/tpm0): sev-snp renders az-snp, tdx renders az-tdx |
--measurements | string slice | nil | No | Expected node CVM launch measurement(s), pinned into CDS and ratls-mesh; empty leaves measurement pinning disabled (unsafe). Cannot be combined with --measurements-config. |
--measurements-config | string | "" | No | path to a measurements config listing the VM images this cluster runs, each matched as a whole image; emits cds.measurementsConfig + ratlsMesh.measurementsConfig and the flat pins alongside. Cannot be combined with --measurements or --rtmrs |
--rtmrs | string slice | nil | No | TDX RTMR pin(s) <index>=<sha384-hex> completing --measurements on --hardware-platform=tdx (repeatable / comma-separated); emits cds.rtmrs + ratlsMesh.rtmrs. Ignored for SEV-SNP evidence. Cannot be combined with --measurements-config |
--resolve-digests | bool | true | No | resolve each component image tag to its registry digest (via crane), pin it, and enable the NRI allowlist derivation |
--image-tag | string | "" | No | component image tag to resolve digests at (default: the CLI build version, or main) |
--image-pull-secret | string | "" | No | name of an existing dockerconfigjson Secret the chart wires into every component's imagePullSecrets |
--operator-keys | string | "" | No | path to a PEM bundle of operator EC public keys that authorize c8s allowlist writes; the file's content is embedded as cds.operatorKeys in the emitted values (the chart value is PEM content, never a path) |
--install-crds | bool | true | No | emit values for chart CRDs (false sets statusMirror.enabled=false, matching install --install-crds=false) |
--workload-ref | string slice | nil | No | adopted workload as <cw-id>=<namespace>/<kind>/<name>[:<port>]; repeatable. Used here only to derive --upstream's address (render-values patches nothing) |
--upstream | string | "" | No | confidential.ai/cw id of the adopted --workload-ref workload router routes its catch-all to; derives router.upstream.address c8s-<id>.<ns>.svc.cluster.local:<port> from that ref's :<port> |
c8s operator
Run the c8s controller-manager and admission webhook.
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--metrics-bind-address | string | :8080 | No | address for Prometheus metrics |
--health-probe-bind-address | string | :8081 | No | address for health/readyz probes |
--leader-elect | bool | true | No | enable leader election for HA |
--leader-election-namespace | string | c8s-system | No | namespace holding the leader-election Lease |
--status-mirror-enabled | bool | true | No | enable CRD-backed ConfidentialWorkload status mirror controller |
--get-cert-image | string | "" | No | image reference the webhook injects for get-cert containers (empty = webhook disabled) |
--cds-url | string | "" | No | CDS Service URL the injected get-cert containers POST to |
--attestation-api-url | string | "" | No | attestation-api endpoint (empty = no verification) |
--cds-measurements | string slice | nil | No | SHA-384 hex launch measurement(s) the injected secret fetcher requires CDS to present (repeatable; empty pins none) |
--cds-rtmrs | string slice | nil | No | TDX RTMR pin(s) <index>=<sha384-hex> the injected sidecars additionally hold CDS to (repeatable; ignored for SEV-SNP evidence, empty pins no registers) |
--measurements-config | string | "" | No | path to a measurements config listing the VM images this cluster runs; any listed image may serve as CDS, and the injected sidecars carry the digests flat. Cannot be combined with --cds-measurements or --cds-rtmrs |
--exclude-namespaces | string slice | nil | No | extra namespaces the startup reinject sweep skips (mirrors webhook.extraExcluded) |
--webhook-config-name | string | "" | No | MutatingWebhookConfiguration to patch caBundle (empty = skip) |
--webhook-service-name | string | "" | No | webhook Service name (defaults to c8s) |
--webhook-service-namespace | string | "" | No | webhook Service namespace (defaults to --leader-election-namespace) |
--cert-fs-group | int64 | 65532 | No | fsGroup applied to injected pods when unset (-1 disables mutation) |
--get-cert-renew-interval | duration | 2h | No | renewal interval for injected workload certificates |
--get-cert-run-as-user | int64 | 65532 | No | runAsUser for injected get-cert containers |
--get-cert-run-as-group | int64 | 65532 | No | runAsGroup for injected get-cert containers |
--get-cert-run-as-non-root | bool | true | No | set runAsNonRoot for injected get-cert containers |
--workload-claims-host-dir | string | "" | No | host directory holding the nri-image-policy inventory socket (Node-as-CVM); when set, the webhook mounts it into the c8s-cert container and injects --workload-claims so get-cert redeems a sandbox token |
c8s cds
Run the Certificate Distribution Service (CDS). Requires --ratls-platform,
--attestation-api-url, and --allowlist-db.
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--host | string | 0.0.0.0 | No | listen host |
-p, --port | int | 8443 | No | listen port |
--log-level | string | info | No | log level: debug, info, warn, error |
--attestation-api-url | string | "" | Yes | URL of the attestation-api service |
--ca-common-name | string | c8s Mesh CA | No | common name for the in-memory generated mesh CA |
--ca-cert-validity | duration | 8760h | No | validity period of the in-memory mesh CA certificate |
--measurements | string slice | nil | No | SHA-384 hex launch measurements allowed to call /attest (repeatable / comma-separated); empty = no pinning (UNSAFE) |
--measurements-config | string | "" | No | path to a measurements config listing the VM images this cluster runs, each matched as a whole image (launch digest plus, on TDX, that image's registers). Every listed image may call /attest, and the same file pins CDS for the components that dial it, so any listed image may serve as CDS. Cannot be combined with --measurements or --rtmrs |
--rtmrs | string slice | nil | No | TDX RTMR pins <index>=<sha384-hex> required of TDX callers on /attest and /attest-key (repeatable); RTMR[1] pins the guest kernel, RTMR[2] the command line carrying the dm-verity root hash. SNP evidence is unaffected; empty leaves the TDX reference values covering TDVF firmware only (UNSAFE) |
--jwt-clock-skew | int64 | 30 | No | EAR JWT exp/nbf/iat clock-skew tolerance in seconds; also applied to operator write tokens |
--cert-ttl | duration | 24h | No | TTL of the leaf and EAR /attest issues, capped at the built-in 24h leaf ceiling |
--named-cert-ttl | duration | 6h | No | upper bound on the TTL of a leaf carrying a matched-workload stamp (never applied to membership-only leaves); must be positive and may only shorten the built-in 6h ceiling |
--challenge-ttl | duration | 1m | No | lifetime of an attestation challenge nonce; issuance and /secrets keep separate pools |
--request-timeout | duration | 5s | No | per-request timeout on /attest and /sign-csr, and on the inventory callback (0 disables) |
--max-request-size | int64 | 65536 | No | max request body bytes on write endpoints; must be positive |
--read-timeout | duration | 10s | No | HTTP server read timeout |
--read-header-timeout | duration | 5s | No | HTTP server read-header timeout |
--write-timeout | duration | 10s | No | HTTP server write timeout |
--idle-timeout | duration | 20s | No | HTTP server idle timeout |
--max-header-bytes | int | 1048576 | No | maximum HTTP request header bytes |
--san-validation | bool | true | No | require CSR IP SANs to equal the request source IP (false rejects CSRs carrying IP SANs) |
--dns-san-pattern | string slice | nil | No | regex a CSR's DNS SANs may match in full; repeatable, and a SAN passes if it matches any one. The chart always supplies the in-cluster Service DNS pattern and appends a public hostname when router fronts a routed domain. A CSR carrying DNS SANs is rejected when none are set |
--allowed-cn-pattern | string | "" | No | regex the CSR Subject CN must match in full (empty disables) |
--readiness-interval | duration | 10s | No | interval of the attestation-api health check behind /readyz; must be positive |
--min-ca-validity | duration | 1h | No | /readyz fails when the loaded mesh CA has less than this remaining lifetime |
--allowlist-db | string | "" | Yes | path to the allowlist SQLite database |
--allowlist-persistent | bool | false | No | whether --allowlist-db is on durable storage; false makes the CDS warn at startup that operator-added digests and the mesh CA do not survive a restart |
--sandbox-inventory-cidr | string slice | nil | No | CIDR(s) holding the node addresses the CDS may dial for a sandbox's admission inventory (repeatable); it is what stops a workload pointing the callback at its own pod IP. Unset, the CDS derives one host route per node from the live node list and refuses sandbox tokens until that syncs |
--allowlist-seed | string | "" | No | path to a JSON allowlist (version + digests map) seeded into the store at startup before serving; missing digests are added, existing entries are left untouched (empty disables seeding) |
--operator-keys | string | "" | No | path to a PEM bundle of pinned operator EC public keys; /allowlist writes (POST/PUT/DELETE) require an operator token signed by one of them (empty = writes disabled, reads still served) |
--rate-limit | float64 | 10 | No | max requests per second per source IP on attestation endpoints |
--rate-burst | int | 20 | No | max burst size per source IP |
--rate-limiter-max-entries | int | 10000 | No | max entries in the per-IP rate limiter; once full, a new source is refused until entries idle out |
--rate-limiter-evict-interval | duration | 1m | No | interval for per-IP rate limiter eviction sweep |
--rate-limiter-idle-timeout | duration | 5m | No | idle duration before a per-IP rate limiter entry is evicted |
--secrets-max-paths | int | 1024 | No | max distinct secret paths held in memory across every workload; must be positive |
--secrets-max-paths-per-workload | int | 64 | No | max secret paths one allowlist entry may hold; must be positive and below --secrets-max-paths |
--secrets-max-value-bytes | int | 4096 | No | max bytes in one secret value; must be at least 32, the size of every value the CDS generates |
--sandbox-ledger-max-entries | int | 10000 | No | max sandbox-to-inventory bindings held in memory; must be positive |
--ratls-platform | string | "" | Yes | TEE platform for the RA-TLS serving cert: sev-snp or tdx (the snp/az-snp/gcp-snp and az-tdx/gcp-tdx aliases are normalized) |
--ratls-cert-ttl | duration | 24h | No | TTL of the RA-TLS serving certificate the CDS presents |
c8s allowlist
Read and mutate the CDS-served allowlist that nri-image-policy enforces. It
has two layers: a floor of image digests admitted by digest alone, and named workload
entries that pin an init/main container set with per-container argv and path policy. Reads are
unauthenticated; writes are signed with the operator EC private key whose public half the CDS
pins (cds.operatorKeys, set by install --operator-keys). See
The Allowlist for usage.
| Subcommand | Arguments | Purpose |
|---|---|---|
list | — | list the current allowlist floor and workload entries |
export | [file] | write the full allowlist as canonical JSON to a file (default stdout) for backup or re-upload |
diff | <file> | show how an allowlist file differs from the live allowlist |
lint | <file|-> | validate an allowlist file and report semantic findings; never contacts the CDS |
inspect-image | <ref> | resolve an image reference via crane and print its digest plus baked Entrypoint/Cmd; registry-only |
add | <digest> <image> | add a single image digest to the floor (operator key required) |
remove | <digest> [<digest>...] | remove one or more image digests from the floor (operator key required) |
upload | <file> | atomically replace the entire allowlist — floor and workload entries — with the contents of a file (operator key required) |
workload list | — | list workload entries |
workload get | <name> | print one workload entry as canonical JSON |
workload derive | <name> <file|-> | print a workload entry built from a Pod, Deployment, StatefulSet or DaemonSet given as JSON; contacts nothing |
workload apply | <file|-> | upsert workload entries from a file, each replaced whole (operator key required) |
workload edit | <name> | fetch a workload entry, edit it in $EDITOR, and apply the result (operator key required) |
workload delete | <name> [<name>...] | delete one or more workload entries (operator key required) |
Persistent flags, registered on every subcommand:
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--url | string | "" | Yes | router or direct CDS base URL; required by every subcommand that contacts the CDS (lint and inspect-image do not). A router front door is accepted only when its discovery document reports public_tls.mode=cds; a WebPKI front door is refused. A direct URL is verified by RA-TLS on the CDS serving cert. Plaintext http:// is refused without --insecure |
--measurements | string slice | nil | No | allowed SHA-384 hex launch measurement(s) of the attested endpoint (repeatable / comma-separated) — the router's value for a front door, the CDS's value for a direct URL; empty accepts any attested build on a read (UNSAFE) and is refused on a write |
--measurements-file | string | "" | No | file of allowed launch measurements, one hex digest per line; merged with --measurements |
--timeout | duration | 15s | No | per-request timeout |
--operator-key | string | "" | No | operator EC private key PEM file whose public key is pinned on CDS via --operator-keys (env C8S_OPERATOR_KEY; the flag wins); required for writes |
-o, --output | string | text | No | output format: text or json |
--insecure | bool | false | No | dev/test only: allow a plaintext http:// CDS URL, skipping RA-TLS attestation of CDS |
Per-subcommand flags:
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--exit-code | bool | false | No | diff only: exit non-zero when the file and the live allowlist differ |
--online | bool | false | No | lint only: also check each digest exists in its registry via crane |
--strict | bool | false | No | lint, upload: treat lint warnings as fatal (lint errors already fail on their own) |
--cvm-mode | string | "" | No | lint only: deployment-mode hint for warnings about mount and environment policies; use the mode targeted by the allowlist |
--dry-run | bool | false | No | add, remove: print the intended change without calling CDS; upload: show the diff without replacing the allowlist; workload apply: show the diff without writing any entry |
--force | bool | false | No | upload only: upload even if core c8s components are missing from the file |
--require | string slice | nil | No | upload only: component identifiers that must appear in the uploaded image refs (overrides the default set cds, ratls-mesh, nri-image-policy, attestation-api, nginx) |
--label | string | "" | No | workload derive only: label written into the derived entry |
--secret-read | string array | nil | No | workload derive only: grant read on this secret path (repeatable); with none the derived entry carries no secrets block |
--env | string | "" | No | workload derive only: environment policy for every container, any or deny |
--env-file | string | "" | No | workload derive only: JSON file mapping container names to explicit environment policies, including exact values |
c8s secrets
Write operator-supplied values into the CDS secret store, and report why a sandbox does or does
not receive them. CDS releases a value to a pod when the containers running in that pod's sandbox
match a workload entry whose secrets grant covers the path; the grant is written with
c8s allowlist workload apply. Values are held in the CDS process and nowhere
else, so a CDS restart empties the store. See Secrets.
| Subcommand | Arguments | Purpose |
|---|---|---|
put | <path> | store a value at a secret path, read from stdin or --from-file |
explain | — | print the release decision CDS reaches for one sandbox |
put sends the bytes exactly as read, including any trailing newline, and prints the byte count.
Both subcommands sign their request with the operator EC private key whose public half the CDS
pins (cds.operatorKeys, set by install --operator-keys).
Persistent flags, registered on every subcommand:
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--url | string | "" | Yes | router or direct CDS base URL. A router front door is accepted only when its discovery document reports public_tls.mode=cds; a direct URL is verified by RA-TLS on the CDS serving cert. Plaintext http:// is refused without --insecure |
--measurements | string slice | nil | No | allowed SHA-384 hex launch measurement(s) of the attested endpoint (repeatable / comma-separated) — the router's value for a front door, the CDS's value for a direct URL; empty accepts any attested build on a read (UNSAFE) and is refused on a write |
--measurements-file | string | "" | No | file of allowed launch measurements, one hex digest per line; merged with --measurements |
--timeout | duration | 15s | No | per-request timeout |
--operator-key | string | "" | No | operator EC private key PEM file whose public key is pinned on CDS via --operator-keys (env C8S_OPERATOR_KEY; the flag wins). Both subcommands sign, so one of the two must be set |
--insecure | bool | false | No | dev/test only: allow a plaintext http:// CDS URL, skipping RA-TLS attestation of CDS |
Per-subcommand flags:
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--from-file | string | "" | No | put only: read the value from this file instead of stdin |
--overwrite | bool | false | No | put only: replace a value already at the path. Without it an occupied path is refused, and the error names what is there |
--mesh-ca | string | "" | Yes | put only: PEM bundle of the mesh CA this CDS must serve, the same anchor c8s verify --mesh-ca takes. The write is refused unless every certificate CDS serves at /ca is in the bundle. Required unless --force; a plaintext --insecure endpoint is exempt |
--force | bool | false | No | put only: write without checking the CDS mesh CA against --mesh-ca. Unrelated to --overwrite |
--dry-run | bool | false | No | put only: print the intended change without calling CDS |
--sandbox | string | "" | Yes | explain only: sandbox ID to report on. It is carried on the pod's certificate; c8s verify prints it |
--json | bool | false | No | explain only: print the raw report as JSON |
c8s volume
Build an encrypted volume, store its key in the CDS secret store, and present the image to a node
as a disk. create packages --source into an erofs image, formats a dm-verity tree over it,
encrypts the pair to --out, writes the key blob to --escrow-out, and puts the key at --path
in the store; with --mutable it builds a writable ext4 of --size instead, with no integrity
protection. It then prints the pod annotations and the allowlist grant to apply; it modifies no
workload. The image is ciphertext and can reach the node by any route, including through the
untrusted host, attached as a raw block device with disk serial c8s-vol-<name>. create needs
mkfs.erofs and veritysetup on PATH, or mkfs.ext4 with --mutable. The key exists in
exactly two places — the CDS process and the escrow file — and a key path is create-only: CDS
refuses a --path that already holds a value. See
Volumes.
| Subcommand | Arguments | Purpose |
|---|---|---|
create | — | build an encrypted volume image and store its key |
attach | <name> | present a volume image on this node as a disk with serial c8s-vol-<name>, through LIO's loopback target |
detach | <name> | remove a volume's disk from this node, leaving the image and the stored key alone |
attach and detach run on the node as root, and are needed only where the hypervisor cannot
give a disk a serial of its own — a QEMU/KVM node attaches the image with virtio-blk instead.
Persistent flags, registered on every subcommand:
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--url | string | "" | Yes | router or direct CDS base URL, verified as for c8s secrets; required by create and not read under --dry-run. attach and detach inherit it and never contact CDS |
--measurements | string slice | nil | No | allowed SHA-384 hex launch measurement(s) of the attested endpoint (repeatable / comma-separated); empty accepts any attested build on a read (UNSAFE) and is refused on the store write |
--measurements-file | string | "" | No | file of allowed launch measurements, one hex digest per line; merged with --measurements |
--timeout | duration | 15s | No | per-request timeout |
--operator-key | string | "" | No | operator EC private key PEM file whose public key is pinned on CDS via --operator-keys (env C8S_OPERATOR_KEY; the flag wins); required for the store write |
--insecure | bool | false | No | dev/test only: allow a plaintext http:// CDS URL, skipping RA-TLS attestation of CDS |
create flags:
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--name | string | "" | Yes | volume name; forms the device serial c8s-vol-<name>, so a DNS-1123 label of at most 12 characters |
--source | string | "" | Yes | directory whose contents become the volume; required for an immutable volume, an optional preload with --mutable |
--mutable | bool | false | No | build a writable ext4 volume instead of an immutable, dm-verity-protected one. A mutable volume has no integrity protection: the host can flip bits or roll it back undetected |
--size | string | "" | No | mutable filesystem size, e.g. 50Gi; inferred from --source when one is given, required with --mutable and no --source, and refused without --mutable |
--out | string | "" | Yes | path the encrypted image is written to; must not exist |
--path | string | "" | Yes | secret-store path for the key, e.g. /tenant-a/volumes/weights; absolute, clean, no wildcards |
--escrow-out | string | "" | Yes | path the key blob is written to, mode 0600; must not exist. It is the only copy of the key outside CDS |
--node | string | "" | No | node holding the device; emitted as a nodeSelector on the printed annotations |
--work-dir | string | "" | No | directory for build intermediates (default: a temp dir); they are removed either way |
--dry-run | bool | false | No | build the image and write the escrow file, but do not call CDS |
attach and detach flags:
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--image | string | "" | Yes | attach only: path on this node to the encrypted image. The device serves the file opened here, not the path |
--config-root | string | /sys/kernel/config | No | configfs mount LIO is driven through |
--json | bool | false | No | attach only: print the name and serial as JSON |
c8s cds-attest
Run the router attestation + over-encryption sidecar (the c8s-verify/v1 server side). Fronted
by the router nginx (chart flag router.attest.enabled), it serves the LB's attestation at
/.well-known/c8s/attest-pq (encrypted session) and /.well-known/c8s/attest-lb (ordinary TLS),
runs the post-quantum handshake, and forwards decrypted tunnel traffic to the backend. It's a
chart-managed component, not normally run by hand — see
Consumer Verification for the protocol.
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--session-max-age | duration | — | No | Absolute lifetime of an attestation session. |
--host | string | 127.0.0.1 | No | listen host (loopback: nginx proxies to it) |
-p, --port | int | 8800 | No | listen port |
--log-level | string | info | No | log level: debug, info, warn, error |
--attestation-api-url | string | "" | No | attestation-api URL (production evidence source); one of --attestation-api-url or --evidence-fixture must be set |
--platform | string | "" | Yes | TEE platform: snp | az-snp | az-tdx | tdx |
--generation | string | genoa | No | AMD processor generation for the browser's bare-SNP verifier (--platform snp only, ignored otherwise): milan | genoa | turin |
--serving-cert-file | string | "" | No | path to the LB serving-leaf PEM (the cert nginx presents); in cds front-door mode /.well-known/c8s/attest-lb binds report_data to this exact leaf DER, re-read per request to follow get-cert rotation |
--mesh-identity-cert-file | string | "" | No | TEE-held mesh leaf PEM whose possession both attestation endpoints prove, re-read per request. Separate from --serving-cert-file, which may name a host-visible public TLS credential |
--mesh-identity-key-file | string | "" | No | TEE-held mesh leaf private key matching --mesh-identity-cert-file, re-read per request |
--mesh-identity-ca-file | string | "" | No | mesh CA bundle that issued the identity leaf, re-read per request. All three --mesh-identity-* flags must be set; otherwise /.well-known/c8s/attest-pq returns 501 binding_unavailable |
--expected-workload | string | "" | No | gate /readyz on the mesh identity leaf carrying a matched-workload stamp with this exact name; empty keeps /readyz unconditionally 200 |
--evidence-fixture | string | "" | No | dev only: serve recorded TEE evidence from this file instead of the attestation-api |
--session-ttl | duration | 5m | No | pending-handshake TTL and established-session idle TTL |
--read-header-timeout | duration | 5s | No | HTTP read-header timeout |
--upstream | string | "" | No | backend base URL to forward decrypted traffic to (http:// rides the RA-TLS mesh; https:// does mTLS). Empty uses an echo backend (demo) |
--upstream-ca | string | "" | No | PEM CA bundle to verify an https upstream (the mesh CA) |
--upstream-cert | string | "" | No | client cert presented to an https upstream (the CDS-issued LB cert) |
--upstream-key | string | "" | No | client key for --upstream-cert |
--upstream-server-name | string | "" | No | SNI / verification name for an https upstream |
c8s allowlist-proxy
Publish the CDS allowlist API through router. Public TLS terminates at the router nginx; this
process makes the second trust hop, verifying CDS's RA-TLS serving certificate before forwarding
the request. Path, query, and Authorization header are forwarded byte-for-byte, so the operator
token's method/path/body binding survives the hop. It routes /allowlist and /allowlist/ to
CDS, answers /healthz itself, and binds loopback only. A chart-managed component, not run by
hand — see c8s allowlist for the client side.
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--host | string | 127.0.0.1 | No | listen host; must be a loopback IP (nginx is the public listener) |
-p, --port | int | 8801 | No | listen port; 1–65535 |
--cds-url | string | "" | Yes | CDS base URL; must be an https (RA-TLS) origin with no credentials, path, query, or fragment |
--cds-measurements | string slice | nil | No | allowed CDS SHA-384 hex launch measurement(s) (repeatable / comma-separated); empty accepts any attested CDS (UNSAFE) |
--cds-rtmrs | string slice | nil | No | TDX RTMR pin(s) <index>=<sha384-hex> CDS must additionally satisfy (repeatable / comma-separated); ignored when CDS presents SNP evidence, and empty pins no registers |
--measurements-config | string | "" | No | path to a measurements config listing the VM images this cluster runs, each matched as a whole image; any listed image may serve as CDS. Cannot be combined with --cds-measurements or --cds-rtmrs |
--attestation-api-url | string | "" | No | attestation-api URL used to verify CDS evidence |
--request-timeout | duration | 30s | No | timeout for one request to CDS; must be positive |
--read-header-timeout | duration | 5s | No | HTTP request-header timeout; must be positive |
c8s verify
Verify a deployed component's TEE attestation evidence (AMD SEV-SNP or Intel TDX) against the
hardware signature chain plus a measurement, TCB, and policy check. Verification runs
in-process with attestation-go (the Go port of the attestation-rs engine the cluster runs)
— no container runtime is needed; a bare SEV-SNP report needs outbound HTTPS to AMD KDS
(kdsintf.amd.com) to fetch its VCEK, bounded by --timeout. Takes a
[target] (a URL or host:port) as its positional argument, or --url. c8s cds verify is the
same command with CDS presets (--kind cds, default port 8443); --mode stays auto, which
resolves to ratls-cert for a CDS target. See the
verification guide for the end-to-end workflow.
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--url | string | "" | No | target URL or host:port (alternative to the positional argument) |
--kind | string | auto | No | component being verified: cds, lb, workload, or auto |
--mode | string | auto | No | evidence mode: auto, ratls-cert, discovery, or attest-pq; any other value is a usage error |
--discovery-path | string | /v1/discovery | No | path of the LB discovery document (discovery mode) |
--server-name | string | "" | No | TLS SNI server name (for port-forward / routed domains) |
--timeout | duration | 15s | No | per-attempt timeout (evidence fetch and AMD KDS collateral fetch) |
--from-file | string | "" | No | verify evidence from a saved PEM certificate or attestation-response JSON instead of dialing |
--measurements | string slice | nil | No | allowed SHA-384 hex launch measurement(s) (repeatable / comma-separated); empty = no pinning (UNSAFE). On TDX this pins MRTD only, so it covers the firmware alone; cannot be combined with --image-manifest or --measurements-config |
--measurements-file | string | "" | No | file of allowed launch measurements, one hex digest per line; feeds the same allowlist as --measurements and carries the same exclusions |
--image-manifest | string | "" | No | build-artifact manifest of the expected TDX guest image (JSON object with mrtd, rtmr1, rtmr2, each 96 lowercase hex chars); pins all three registers exactly against that one manifest. Cannot be combined with --measurements, --measurements-file, --measurements-config, or a by-hand --rtmr 1=/--rtmr 2=. TDX evidence only — a policy error against SEV-SNP evidence |
--expected-rtmr3 | string | "" | No | DEPRECATED — use --rtmr 3=<sha384-hex>, which is the identical pin under identical rules. Retained so existing invocations keep working |
--operator-pkey | string | "" | No | path to the operator public key PEM (the verbatim bytes the guest initrd hashed); derives the RTMR[3] pin as the bare operator-key seed SHA-384(0x00*48 ‖ SHA-384(pubkey)). Requires --image-manifest, and excludes the other two RTMR[3] spellings. TDX evidence only — a policy error against SEV-SNP evidence |
--rtmr | string slice | nil | No | expected TDX runtime measurement register(s) as <index>=<sha384-hex> (repeatable / comma-separated). Index 0 is rejected, 1 and 2 cannot be combined with --image-manifest, and 3 requires it. TDX evidence only — a policy error against SEV-SNP evidence |
--measurements-config | string | "" | No | measurements config listing the VM images this cluster runs; pins the target to those images and, for --kind cds, additionally fails unless the set served at /measurements is identical. Cannot be combined with --measurements, --measurements-file, or --image-manifest |
--operator-keys | string | "" | No | PEM bundle of expected operator public keys; verification fails unless the key set the attested target serves at /operator-keys matches it (--kind cds targets) |
--sandbox-id | string | "" | No | expected CRI pod sandbox ID on the target's leaf; requires --mesh-ca |
--workload | string | "" | No | expected matched-workload name on the target's leaf; requires --mesh-ca, since CDS's signature on the leaf is what vouches for the stamp |
--allowlist | string | "" | No | file holding the exact canonical allowlist bytes as served by GET /allowlist; the leaf's stamped policy digest must equal SHA-256 of those bytes and the stamped name must resolve in the document. Requires --mesh-ca |
--mesh-ca | string | "" | No | PEM bundle of the CDS mesh CA; when set, the target's leaf must chain to it, which is what authenticates the reported sandbox ID. In attest-pq mode it also upgrades a responder-chosen chain anchor from a partial verdict to a verified one |
--init-data | string | "" | No | expected init-data digest: SHA-256 hex of the init-data document the target guest must carry; verification fails unless the evidence commits exactly this digest |
--allow-debug | bool | false | No | accept debug-enabled guests |
--min-tcb-bootloader | uint | 0 | No | minimum bootloader TCB component (0–255); SEV-SNP evidence only, a policy error against TDX evidence |
--min-tcb-tee | uint | 0 | No | minimum TEE TCB component (0–255); SEV-SNP evidence only, a policy error against TDX evidence |
--min-tcb-snp | uint | 0 | No | minimum SNP firmware TCB component (0–255); SEV-SNP evidence only, a policy error against TDX evidence |
--min-tcb-microcode | uint | 0 | No | minimum microcode TCB component (0–255); SEV-SNP evidence only, a policy error against TDX evidence |
--expected-report-data | string | "" | No | hex REPORTDATA / TPM-nonce anchor override for bare evidence files (1–64 bytes, exactly as bound by the producer) |
-o, --output | string | text | No | output format: text or json |
--show-evidence | bool | false | No | print the raw report fields |
Exit codes are a CI contract: 0 verified · 1 usage · 2 verification/policy failed · 3
evidence unavailable (unreachable / unparseable) · 4 partially verified — the evidence verified,
but a property it presents is not proven (a serving key the evidence does not attest, no observable
handshake, or a responder-chosen chain anchor).
c8s measurements
Work with measurements config files. A measurements config pins the VM images a cluster
accepts; each entry is one image, matched as a whole — a launch digest together with the
runtime registers measured from the same build. One file describes one platform: tee is
either sev-snp or tdx, and a cluster mixing SNP and TDX images is not supported.
derive reads the manifest.json of each built confidential-os-builder image and writes the
config. An SEV-SNP image contributes one entry per vCPU variant, named <image>-smp<N>, because
the launch digest covers one VMSA page per vCPU — so even a single-image SNP cluster needs a
multi-entry config. A TDX image contributes one entry: its MRTD with RTMR[1] and RTMR[2].
RTMR[0] is never pinned, since it varies with the vCPU and memory shape.
lint loads a config, reports the platform and the entry count, and takes no flags.
derive flags:
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--tee | string | "" | No | platform to derive for, sev-snp or tdx; required when an image is built for both |
--out | string | "" | No | write the config to this path instead of stdout |
c8s get-cert
Obtain a signed certificate via the CDS attestation flow. Generates an ECDSA P-256 key (or loads
--key), builds a CSR for --san, and exchanges it for a signed chain over RA-TLS. Requires
--cds-url, --attestation-api-url, and --san.
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--ca-watch-interval | duration | — | No | Interval for refreshing the CDS CA certificate. |
--cds-url | string | "" | Yes | URL of the CDS service (e.g. https://cds:8443); the scheme must be https, since CDS is reached over RA-TLS |
--cds-measurements | string | "" | No | comma-separated SHA-384 hex launch measurements for CDS RA-TLS verification (empty = accept any attested CDS, and refused outright with --workload-claims-guest, where the host writes the argv) |
--cds-rtmrs | string | "" | No | comma-separated TDX RTMR pins <index>=<sha384-hex> (index 1, 2, or 3) CDS's RA-TLS certificate must additionally satisfy; ignored when CDS presents SEV-SNP evidence (empty = launch-digest pinning only) |
--attestation-api-url | string | "" | Yes | URL of the node-local attestation-api (e.g. http://localhost:8400, or unix:// plus the on-node socket path the chart wires) |
-o, --out | string | "" | No | path to write the signed certificate chain PEM (stdout if omitted) |
--ca-out | string | "" | No | path to write just the mesh CA bundle PEM (the issuer certs trailing the leaf in the CDS chain), e.g. for nginx to serve at a discovery endpoint without a separate ConfigMap |
--key | string | "" | No | path to a PEM private key to use for the CSR (ephemeral if omitted) |
--key-out | string | "" | No | path to write the generated private key PEM (ephemeral keys only); an existing key at this path is reused |
--san | string | "" | Yes | Subject Alternative Name for the certificate (IP address or RFC 1123 hostname; wildcards rejected) |
-v, --verbose | bool | false | No | enable debug logging |
--renew-interval | duration | 0 | No | re-obtain the certificate at this interval (0 = run once and exit) |
--renew-jitter-percent | int | 20 | No | shorten each renewal delay by a random amount up to this percentage so certificates issued together do not renew in lockstep; 0 disables jitter (valid range: 0–99) |
--unnamed-renew-interval | duration | 30s | No | with --workload-claims and --renew-interval, renew this often (plus jitter) while the installed leaf carries no matched-workload stamp, then settle back to --renew-interval once named; 0 disables the fast poll, and any other value below 1s is rejected |
--initial-retry-timeout | duration | 2m | No | retry the first certificate request in-process for up to this long before failing, so a transient CDS/mesh outage during a roll does not crash the init container into kubelet backoff (0 = try once) |
--initial-retry-interval | duration | 2s | No | delay between in-process retries of the first certificate request |
--reload-nginx | bool | true | No | SIGHUP nginx after certificate renewal or watched file changes |
--continue-on-initial-error | bool | false | No | in renewal mode, keep running when the first certificate request fails, retrying on a capped backoff until a certificate is issued; requires --renew-interval |
--reload-watch | string array | nil | No | file path to poll for changes and reload nginx when it changes (repeatable); requires --renew-interval |
--reload-watch-interval | duration | 1m | No | poll interval for --reload-watch paths; must be positive when --reload-watch is set |
--discovery-out | string | "" | No | path to write JSON discovery metadata for the issued certificate and attestation evidence |
--discovery-cds-cert-url | string | "" | No | public URL path where the CDS certificate PEM is served |
--discovery-mesh-ca-url | string | "" | No | public URL path where the mesh CA PEM is served |
--discovery-public-tls-mode | string | cds | No | public TLS mode to report in discovery metadata: cds or webpki |
--workload-claims | bool | false | No | Request an inventory-signed sandbox token from the node NRI plugin before certificate issuance. |
--workload-claims-timeout | duration | 5s | No | timeout for the admission inventory request |
c8s get-secret
Fetch the secrets this pod is granted and write each one to a file under --out-dir. Injected by
the webhook as a native sidecar. It authenticates to CDS with the pod's CDS-issued certificate and
a sandbox token redeemed from the node's admission inventory at a compiled-in endpoint, and CDS
releases only once every main container in the sandbox is running — earlier attempts are refused
and retried, so the files appear shortly after the workload starts and a consumer must wait for
them. A path the store does not hold yet is created with a CDS-generated value, which does not
survive a CDS restart. After writing, the process idles until the pod is torn down. See
Secrets.
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--cds-url | string | "" | Yes | base URL of CDS; must be https (RA-TLS) |
--attestation-api-url | string | "" | Yes | local attestation-api used to verify CDS's RA-TLS certificate; http(s):// or unix:// plus an absolute socket path |
--measurements | string slice | nil | No | SHA-384 hex launch measurement(s) CDS must present (repeatable / comma-separated); empty pins none (UNSAFE) and is refused under --workload-claims-guest |
--rtmrs | string slice | nil | No | TDX RTMR pin(s) <index>=<sha384-hex> CDS must also satisfy (repeatable / comma-separated); ignored when CDS presents SEV-SNP evidence, and empty pins no registers |
--cert | string | /run/c8s/certs/tls.crt | No | the pod's CDS-issued certificate, presented to CDS |
--key | string | /run/c8s/certs/tls.key | No | private key for --cert |
--secret | string slice | nil | Yes | NAME=/store/path to fetch; NAME is the filename written under --out-dir (repeatable). At least one is required, each NAME must be distinct and must not be a path |
--out-dir | string | /run/c8s/secrets | No | directory the secret files are written to; must be memory-backed |
--file-mode | string | 0640 | No | octal mode for the written files |
--attempts | int | 60 | No | how many times to try before failing; must be positive |
--retry-interval | duration | 5s | No | wait between attempts; must be positive |
--request-timeout | duration | 10s | No | per-request timeout against CDS; must be positive |
--inventory-timeout | duration | 5s | No | timeout for redeeming a sandbox token from the node's admission inventory; must be positive |
c8s get-volume
Fetch the key for each encrypted volume this pod is granted and hand it to
c8s volumed, which opens the device and mounts it into this pod — read-only for
an immutable volume, read-write for a mutable one. Injected by the webhook as a native sidecar,
with the same authentication, release rule, and retry behavior as
c8s get-secret: the volume appears shortly after the workload starts. The key
must already be in the store, put there by c8s volume create; nothing here creates
one. Linux only — the subcommand is registered only in Linux builds of the CLI. See
Volumes.
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--cds-url | string | "" | Yes | base URL of CDS; must be https (RA-TLS) |
--attestation-api-url | string | "" | Yes | local attestation-api used to verify CDS's RA-TLS certificate; http(s):// or unix:// plus an absolute socket path |
--measurements | string slice | nil | No | SHA-384 hex launch measurement(s) CDS must present (repeatable / comma-separated); empty pins none (UNSAFE) and is refused under --workload-claims-guest |
--rtmrs | string slice | nil | No | TDX RTMR pin(s) <index>=<sha384-hex> CDS must also satisfy (repeatable / comma-separated); ignored when CDS presents SEV-SNP evidence, and empty pins no registers |
--cert | string | /run/c8s/certs/tls.crt | No | the pod's CDS-issued certificate, presented to CDS |
--key | string | /run/c8s/certs/tls.key | No | private key for --cert |
--volume | string slice | nil | Yes | NAME=/store/path to open; NAME selects the device by serial c8s-vol-<name> and names the mounted volume (repeatable). At least one is required and each NAME must be distinct |
--socket-dir | string | /run/c8s/workload-claims | No | directory holding the node agent's socket, as this pod sees it; unused under --workload-claims-guest, where the daemon is in the guest |
--attempts | int | 60 | No | how many times to try before failing; must be positive |
--retry-interval | duration | 5s | No | wait between attempts; must be positive |
--request-timeout | duration | 10s | No | per-request timeout against CDS and the node agent; must be positive |
--inventory-timeout | duration | 5s | No | timeout for redeeming a sandbox token from the node's admission inventory; must be positive |
c8s volumed
Agent that opens encrypted volumes for the pods it serves. An injected
c8s get-volume sidecar hands it a key over volumed.sock, created inside the
admission inventory's socket directory; the daemon resolves the calling pod from kernel peer
credentials, opens dm-crypt, stacks dm-verity for an immutable volume, and mounts the result into
that pod and no other — read-only erofs when verified, read-write ext4 when mutable. The mount
target is never taken from what the caller reports about itself. Teardown is driven by the pod's
cgroup slice disappearing.
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--socket-dir | string | "" | Yes | host directory holding the admission inventory's socket, where this daemon creates volumed.sock. No default: the in-pod path a sidecar sees is not where the daemon serves. Required for the node shape, unused under --guest |
--kubelet-root | string | /var/lib/kubelet | No | kubelet's root directory, holding per-pod volume directories |
--cgroup-root | string | /sys/fs/cgroup | No | cgroup mount, where a pod's slice going away is what triggers teardown |
--reap-interval | duration | 15s | No | how often to tear down volumes whose pod has gone; must be positive |
--max-mounts | int | 64 | No | maximum volumes open at once; must be positive |
c8s cred-release
Issue a short-lived kube client certificate to a caller that proves possession of the operator key
whose public half was bound into the CVM's launch identity. It serves POST /release-credential
over RA-TLS — the endpoint c8s get-kubeconfig consumes — signing the
caller's CSR with the cluster's client CA and returning a kubeconfig anchored to the serving CA.
Both TEE platforms are served, and only the binding differs: on TDX the staged operator public key
must hash to the RTMR[3] the measured initrd extended, SHA-384(0x00*48 ‖ SHA-384(pubkey)), read
back from the guest's own tdx_guest sysfs; on SEV-SNP it must equal the HOSTDATA the launcher
committed at launch, SHA-256(pubkey), taken from a self-report the local attestation-api
verified. Startup fails closed on a mismatch, and --platform is required because RA-TLS is
mandatory here. Baked as a systemd unit in the c8s node image; not run by hand. The CA defaults are
the RKE2 paths — on kubeadm, set all three to /etc/kubernetes/pki/ca.crt and ca.key.
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--listen | string | :8443 | No | HTTPS (RA-TLS) bind address |
--attestation-api-url | string | http://127.0.0.1:8400 | No | local attestation-api base URL: the source of the RA-TLS serving cert's quote and, on SEV-SNP, of the verified HOSTDATA self-report |
--platform | string | "" | Yes | TEE platform: tdx or snp; selects the operator-key binding checked at startup |
--client-ca-cert | string | /var/lib/rancher/rke2/server/tls/client-ca.crt | No | cluster client-CA cert that signs kube client certs |
--client-ca-key | string | /var/lib/rancher/rke2/server/tls/client-ca.key | No | cluster client-CA key |
--server-ca-cert | string | /var/lib/rancher/rke2/server/tls/server-ca.crt | No | CA that signs the apiserver serving cert; embedded in the released kubeconfig |
--cert-ttl | duration | 24h | No | lifetime of issued operator certs |
--cert-org | string | system:masters | No | Kubernetes group (cert Subject O) for the issued cert |
--cert-cn | string | operator | No | Kubernetes user (cert Subject CN) for the issued cert |
c8s get-kubeconfig
Obtain an operator kubeconfig from a measured c8s CVM. The --image-manifest shape selects the
platform and the gate pins every value it carries: on TDX the image tuple (MRTD, RTMR[1], RTMR[2])
plus RTMR[3] as the operator-key seed extended by each --workload-image digest in first-extend
order; on SEV-SNP the reported launch digest must be one of the manifest's per-vCPU-count
snp_variants digests and HOSTDATA must equal SHA-256 of the operator public key. SEV-SNP has no
runtime-extend register, so --workload-image is rejected there. A locally generated CSR is then
exchanged for a short-lived kube client certificate over the node's
cred-release endpoint, and the kubeconfig is written to --out with mode
0600. Verification runs in-process with attestation-go, including the RA-TLS check on the
cred-release dial. Requires --operator-key, --image-manifest, and --out, plus either
--node, --vmi, or all of --attest-url, --release-url, and --apiserver-url.
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--node | string | "" | No | guest host/IP that fills --attest-url, --release-url, and --apiserver-url with the standard ports (8400/8443/6443); each explicit URL flag overrides it. Mutually exclusive with --vmi |
--vmi | string | "" | No | guest as a KubeVirt VMI [namespace/]name; its address is resolved through the current kubeconfig and used as --node, with the namespace defaulting to the kubeconfig context's. Mutually exclusive with --node |
--attest-url | string | "" | No | attestation-api /attest URL |
--release-url | string | "" | No | cred-release base URL |
--apiserver-url | string | "" | No | apiserver URL written into the kubeconfig |
--operator-key | string | "" | Yes | operator ECDSA private key PEM; its public half is the one bound into the node's launch identity (TDX RTMR[3], SEV-SNP HOSTDATA), and it signs the credential-release request |
--image-manifest | string | "" | Yes | provenanced build-artifact manifest of the expected guest image — TDX: mrtd/rtmr1/rtmr2; SEV-SNP: snp_variants. Its shape selects the platform, and every value it carries is pinned |
--workload-image | string array | nil | No | digest-pinned image ref (sha256:<hex> or name@sha256:<hex>; tags rejected) the node's measurer is expected to have extended into RTMR[3]; repeatable, in first-extend order, each image given once. Omit for a node that runs no measured workloads. TDX only |
--context | string | c8s | No | kubeconfig cluster/context/user name |
--tls-server-name | string | c8s-cvm | No | kubeconfig tls-server-name: pins apiserver certificate verification to this SAN (baked into the node image's tls-san) instead of the dialed IP. Empty omits the field |
--out | string | "" | Yes | path the kubeconfig is written to, mode 0600 |
--timeout | duration | 30s | No | per-step network timeout |
--release-wait | duration | 2m | No | how long to keep retrying while cred-release is not yet listening, since it comes up after the attest step; 0 fails on the first refused dial |
c8s ratls-mesh
Run the RA-TLS L4 mesh proxy or its iptables side commands.
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--kubeconfig | string | "" | No | Kubeconfig for pod resolver API access; empty uses the in-cluster service account. |
--platform | string | auto | No | TEE platform: sev-snp, tdx, or auto (probes /dev/{tdx_guest,sev-guest}) |
--attestation-api-url | string | "" | Yes | URL of the local attestation-api (e.g. http://localhost:8400) |
--outbound-port | int | 15001 | No | outbound listener port (intercepted app traffic) |
--inbound-port | int | 15006 | No | inbound listener port (RA-TLS from peer nodes) |
--node-ip | string | "" | No | this node's IP; falls back to the NODE_IP env var, and startup fails if neither is set |
--cert-dns-san | string | "" | No | DNS SAN placed on the CDS-issued mesh cert (must match CDS --dns-san-pattern; empty omits SANs). Not used for peer verification, which is attestation-based |
--log-level | string | info | No | log level: debug, info, warn, error |
--dial-timeout | duration | 5s | No | plain TCP dial timeout |
--tls-dial-timeout | duration | 10s | No | RA-TLS dial timeout |
--dest-header-timeout | duration | 5s | No | inbound destination header read timeout |
--drain-timeout | duration | 30s | No | graceful shutdown drain timeout |
--keepalive | duration | 30s | No | TCP keepalive interval (0 to disable) |
--idle-timeout | duration | 0 | No | close connections idle longer than this (0=disabled) |
--max-conns | int | 0 | No | max concurrent connections (0=unlimited) |
--max-conns-per-source | int | 0 | No | max concurrent connections per source IP (0=unlimited) |
--health-port | int | 15021 | No | health/metrics HTTP port |
--measurements | string | "" | No | comma-separated hex SHA-384 launch measurements that mesh peers must match (empty = accept any TEE) |
--rtmrs | string | "" | No | comma-separated TDX RTMR pins <index>=<sha384-hex> that mesh peers must satisfy (RTMR[1] guest kernel, RTMR[2] cmdline with the dm-verity root hash); SNP peers are unaffected. Empty = no RTMR pinning, so on TDX --measurements pins TDVF firmware only |
--measurements-config | string | "" | No | path to a measurements config listing the VM images this cluster runs; each entry is matched as a whole image (launch digest plus, on TDX, that image's registers) and is accepted both as a mesh peer and as the CDS this proxy dials. Cannot be combined with --measurements, --rtmrs, --cds-measurements, or --cds-rtmrs, and its tee must match the platform this node attests on |
--cert-ttl | duration | 24h | No | RA-TLS certificate lifetime, minimum 1m (rotates at 50%) |
--rotation-timeout | duration | 30s | No | max time for background certificate rotation |
--cert-mode | string | self-signed | No | certificate mode: self-signed, or cds (boots self-signed, upgrades to CDS-issued in background) |
--cds-url | string | "" | No | CDS service URL for attestation and CA bundle retrieval; required with --cert-mode cds |
--ca-cert | string | "" | No | path to CA certificate file for peer verification |
--ca-poll-interval | duration | 5m | No | interval to poll CDS /ca for CA bundle updates |
--cds-measurements | string | "" | No | comma-separated SHA-384 hex launch measurements that the CDS RA-TLS peer cert must match; empty = accept any (UNSAFE outside development) |
--cds-rtmrs | string | "" | No | comma-separated TDX RTMR pins <index>=<sha384-hex> that the CDS RA-TLS peer cert must satisfy on top of --cds-measurements; ignored when CDS presents SNP evidence. Empty = launch-digest pinning only |
--cds-retry-backoff | duration | 2s | No | initial backoff duration for CDS certificate upgrade retries |
--cds-retry-max-backoff | duration | 1m | No | maximum backoff duration for CDS certificate upgrade retries |
--cds-op-timeout | duration | 30s | No | per-operation timeout for CDS certificate upgrade and CA bundle refresh |
--session-cache-size | int | 64 | No | TLS session cache size per node (0 disables session resumption) |
--access-log | bool | true | No | emit per-connection structured access log |
--cert-pipeline-probe-url | string | "" | No | CDS /readyz URL for pipeline health probing (empty = disabled) |
--cert-pipeline-probe-timeout | duration | 5s | No | HTTP client timeout for cert pipeline health probe requests |
--cert-pipeline-probe-interval | duration | 1m | No | interval between cert pipeline health probe requests |
--max-dest-header-size | int | 256 | No | maximum destination header size in bytes |
--pipe-buffer-size | int | 32768 | No | buffer size for TCP pipe forwarding |
--accept-error-threshold | int64 | 10 | No | consecutive accept errors before marking unhealthy |
--health-read-timeout | duration | 5s | No | health server read timeout |
--health-write-timeout | duration | 10s | No | health server write timeout |
--metrics-update-interval | duration | 10s | No | interval for resolver cache and cert expiry metric updates |
--local-cidr-boot-timeout | duration | 1s | No | synchronous retry budget at startup for host pod-network CIDR discovery; past it the mesh falls through to the async refresh loop and local-destination validation uses Kubernetes pod HostIP ownership until discovery recovers |
--iptables-metrics-file | string | /tmp/ratls-iptables-metrics.json | No | shared file where iptables-sync publishes counters (empty disables) |
c8s ratls-mesh iptables-sync
Watch Kubernetes pods and maintain the iptables/ipset rules that redirect mesh traffic.
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--outbound-port | int | 15001 | No | outbound listener port |
--uid | int | 1337 | No | UID to exclude from redirect |
--exclude-uids | string | 0 | No | comma-separated UIDs to skip (e.g. root=0 so kubelet/containerd can reach registries) |
--exclude-source-namespaces | string | kube-system | No | comma-separated local source namespaces excluded from transparent mesh interception |
--node-ip | string slice | nil | No | local node IP(s); repeat or comma-separate for dual-stack (one per family). Defaults to the NODE_IP env var. Each address must be a non-loopback, non-unspecified IP bound to a local interface |
--resync-period | duration | 30s | No | periodic full ipset reconciliation interval |
--watchdog-period | duration | 2s | No | interval at which the base-chain jump rules are re-asserted at the head of their chain (bounds the race window against kube-proxy reinserting KUBE-SERVICES) |
--ipset-maxelem | int | 262144 | No | maximum members per managed ipset |
--cw-inbound-passthrough | string | udp:53,tcp:53 | No | comma-separated proto:source-port replies exempted from the always-on cw inbound guard, which drops FORWARD-path traffic to confidential.ai/cw pods. Each entry matches only a destination port in 32768-60999 and, for TCP, a reply segment shape. Empty = strict drop-all; DNS is the default |
--ready-file | string | "" | No | path to write after initial ipset and iptables sync succeeds |
--iptables-metrics-file | string | /tmp/ratls-iptables-metrics.json | No | shared file where iptables-sync publishes counters (empty disables) |
--log-level | string | info | No | log level: debug, info, warn, error |
c8s ratls-mesh iptables-cleanup
Remove the iptables NAT rules and ipsets the mesh created.
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--keep-guard | bool | false | No | keep the fail-closed filter guard (the RATLS-MESH-CW and RATLS-MESH-CW-EGRESS chains, their FORWARD jumps, and the cw pod ipsets) while removing the interception NAT rules; the daemonset preStop hook sets it so a terminating mesh stays fail-closed. A full teardown removes the guard as well |
c8s nri-image-policy
Run the nri-image-policy plugin. Uses the standard Go flag package, so the help output
prints single-dash forms and both -config and --config parse; most configuration comes
from the YAML config file rather than CLI flags.
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--config | string | /etc/nri/conf.d/image-policy.yaml | No | path to config file |
--health-addr | string | :8080 | No | health check listen address |
--read-timeout | duration | 5s | No | HTTP server read timeout |
--write-timeout | duration | 10s | No | HTTP server write timeout |
c8s probe-file
Exit 0 if <path> exists and is a non-empty file — a file-existence helper for distroless
containers, where /bin/test is not available. One-shot by default (for a kubelet exec probe);
with --wait it blocks until the path passes (or --timeout elapses), so it can be the
entrypoint of an init container that gates a workload on a file another container writes — the
exec-free equivalent of a startup probe when exec probes are
denied by policy. The non-empty check rules out passing on a half-written file.
| Flag | Type | Default | Required | Description |
|---|---|---|---|---|
--wait | bool | false | No | block until <path> passes the check instead of probing once |
--poll-interval | duration | 1s | No | how often to re-check <path> in --wait mode |
--timeout | duration | 0 | No | give up (non-zero exit) after this long in --wait mode; 0 waits forever |