CLI reference

Command arguments, flag types, defaults, requirements, and effects for the public C8s CLI and its operational components.

Tables list the registered flags for the public commands and operational components below. Grouped sections identify which subcommand takes each flag; hidden conformance commands are excluded. Required conditions include runtime validation, not just CLI annotations. Defaults show registered values; descriptions identify effective fallbacks and conditional requirements.

The c8s binary also responds to the symlink aliases get-cert, armtls-mesh, and nri-image-policy (each auto-prepends the matching subcommand). Installed as c8s-runc, it is the measured OCI runtime wrapper of the node image; pass runc commands and flags directly, without a c8s command prefix.

--image-policy-file takes a complete JSON image policy. A CDS pin binds both its image and the exact measured launch file (cds-pin.json). Node and router policies, such as server.json, identify those targets independently. Flat measurement flags exist only where listed.

c8s install

Install the C8s operator, CRDs, attestation-api, and component charts via Helm. Flags are registered with cobra/pflag. node.baked=false is the chart default; node.baked=true selects chart artifacts baked into the measured node image and settings from its signed launch file. router.enabled=true (the default) enables the router and its routing listener.

FlagTypeDefaultRequiredDescription
--namespacestringc8s-systemNonamespace to install into
--releasestringc8sNoHelm release name
-f, --valuesstring slicenilNovalues files (repeatable)
--waitbooltrueNowait for the release to become ready (helm --wait)
--install-crdsbooltrueNoinstall chart CRDs (false passes helm --skip-crds)
--webhook-cert-fs-groupint6465532NofsGroup for injected certificate volume
--webhook-get-cert-renew-intervalduration6hNorenewal interval for injected workload certificates. Applied only when passed: unset, the chart default webhook.getCert.renewInterval (2h) stands
--webhook-get-cert-run-as-userint6465532NorunAsUser for injected get-cert containers
--webhook-get-cert-run-as-groupint6465532NorunAsGroup for injected get-cert containers
--webhook-get-cert-run-as-non-rootbooltrueNoset runAsNonRoot for injected get-cert containers
--volumesboolfalseNodeploy volumed, the node agent that opens a pod's encrypted volume devices, and pin its image into the NRI allowlist. Off by default: it runs privileged, with hostPID and a writable bind of the kubelet directory
--cvm-modestring""YesDeployment 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-platformstring""YesCPU-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-tagstring""Nocomponent 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-digestsbooltrueNoresolve each component image tag to its registry digest (via crane), pin it, and add the resolved images to the NRI allowlist. Also reads each pinned image config, the router nginx image included (docker.io unless router.nginx.image.repository names a mirror). Pass --resolve-digests=false when supplying digests via -f
--attestbooltrueNoserve the router's attestation endpoints under /.well-known/c8s/ (browser and CLI verification via c8s-verify); --attest=false sets router.attest.enabled=false and turns them off, while the cds-attest sidecar keeps routing application requests
--image-pull-secretstring""Noname 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-refstring slicenilNoexisting 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 ordinary application TCP port carried by its injected mesh endpoint, required on the ref --upstream selects
--upstreamstring""Noconfidential.ai/cw id of the adopted --workload-ref workload to route / to: writes a route manifest naming c8s-<id>.<ns>.svc.cluster.local:<port> (that ref's :<port>, carried by the injected mesh endpoint) and the allowlist entry <id>, for every router.san DNS name
--operator-keystring""Nooperator EC private-key PEM file path (env C8S_OPERATOR_KEY) signing the --upstream route manifest; publish to the external CDS using --cds-address and --cds-pin. Requires --upstream; without this key, write the manifest to --routes-out
--routes-outstringroutes.jsonNofile the --upstream route manifest is written to when no --operator-key signs it, or when install cannot store it on CDS
--routes-revisionuint640Norevision of the --upstream route manifest, above the one CDS stores; default the later of the stored revision plus one and the current Unix time. After a CDS reset, pass one above the highest revision any router applied
--routes-max-ageduration24hNomaxAgeSeconds of a new --upstream route manifest: how long the router admits new attested sessions by it without a successful fetch from CDS; application routing goes on regardless. A manifest CDS already stores keeps its own
--operator-keysstring""ConditionalPEM public-key bundle file path embedded in cds.operatorKeys for router route verification; install preflight requires this flag, a -f values file, or --force. CDS write authority comes from its own measured configuration
--forceboolfalseNobypass guarded install prompts for missing --operator-keys/values files and a component policy that would deny platform pods; chart validation still applies
--cds-addressstring""Conditionalexternal CDS <host>:<port> (DNS or IPv4); sets cds.address. With node.baked=false, supply this and --cds-pin, or set cds.address and cds.measurementsConfig in -f values
--cds-pinstring""Conditionalpath to cds-pin.json, binding the external CDS image and exact launch file; embeds its contents in cds.measurementsConfig
--allowlist-seed-outstring""Nowrite the release/options-matched component allowlist seed and stop before cluster mutation; input to c8s cds config new --allowlist-seed

c8s uninstall

Uninstall the C8s Helm release and sweep C8s host artifacts, including image-policy and mesh state. Requires Helm and kubectl on PATH.

FlagTypeDefaultRequiredDescription
--namespacestringc8s-systemNonamespace the release was installed into
--releasestringc8sNoHelm release name
--waitbooltrueNowait for the release deletion to complete (helm --wait); the host sweep waits for its host pods to be gone either way
--host-sweepbooltrueNoafter the release is deleted, sweep C8s host artifacts (NRI image-policy plugin, armtls-mesh netfilter state, RKE2 prep template, idle c8s volume attach disks) off every node through a short-lived privileged DaemonSet. Runs for every release shape
--host-sweep-onlyboolfalseNoskip 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
--forceboolfalseNouninstall while pods hold C8s encrypted volumes; the pre-delete hook cannot close a mapping a live pod holds, and fails naming it
--delete-crdsboolfalseNoalso delete the ConfidentialWorkload CRD — this deletes every ConfidentialWorkload object in the cluster with it
--delete-namespaceboolfalseNoalso 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). The consuming chart defaults to node.baked=false and needs cds.address and cds.measurementsConfig; supply the flags here or layer these values in the consuming Helm configuration. node.baked=true selects measured-image artifacts with signed launch inputs. router.enabled=true (default) enables routing; its keys come from launch inputs, cds.operatorKeys, or the verified CDS. Route manifests are not Helm values: store them with c8s routes.

FlagTypeDefaultRequiredDescription
--distrostring""Nohost Kubernetes distro (k8s | rke2); install autodetects it, render-values does not, so pass it to pin the value (unset leaves the chart default)
--volumesboolfalseNoemit volumed.enabled=true, deploying the node agent that opens encrypted volumes
--cvm-modestring""YesDeployment 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-platformstring""YesCPU-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
--resolve-digestsbooltrueNoresolve each component image tag to its registry digest (via crane), pin it, and enable the NRI allowlist derivation
--image-tagstring""Nocomponent image tag to resolve digests at (default: the CLI build version, or main)
--image-pull-secretstring""Noname of an existing dockerconfigjson Secret the chart wires into every component's imagePullSecrets
--operator-keysstring""NoPEM public-key bundle file path; embeds its contents in cds.operatorKeys for router route verification. Without configured or measured launch keys, the router fetches keys from verified CDS
--install-crdsbooltrueNoemit values for chart CRDs (false sets statusMirror.enabled=false, matching install --install-crds=false)
--cds-addressstring""Conditionalexternal CDS <host>:<port> (DNS or IPv4); emits cds.address. Supply with --cds-pin, or layer both CDS values in the consuming Helm configuration; this command accepts no values-file input
--cds-pinstring""Conditionalpath to cds-pin.json, binding the external CDS image and exact launch file; embeds its contents in cds.measurementsConfig

c8s operator

Run the C8s controller-manager and admission webhook.

FlagTypeDefaultRequiredDescription
--metrics-bind-addressstring:8080Noaddress for Prometheus metrics
--health-probe-bind-addressstring:8081Noaddress for health/readyz probes
--leader-electbooltrueNoenable leader election for HA
--leader-election-namespacestringc8s-systemNonamespace holding the leader-election Lease
--status-mirror-enabledbooltrueNoenable CRD-backed ConfidentialWorkload status mirror controller
--get-cert-imagestring""Noimage reference the webhook injects for get-cert containers (empty = webhook disabled)
--attestation-api-urlstring""Noattestation-api endpoint (empty = no verification)
--exclude-namespacesstring slicenilNoextra namespaces the startup reinject sweep skips (mirrors webhook.extraExcluded)
--webhook-config-namestring""NoMutatingWebhookConfiguration to patch caBundle (empty = skip)
--webhook-service-namestring""Conditionalwebhook Service name; required when --webhook-config-name requests webhook configuration
--webhook-service-namespacestring""Nowebhook Service namespace (defaults to --leader-election-namespace)
--cert-fs-groupint6465532NofsGroup applied to injected pods when unset; enabled mesh injection requires a nonnegative value
--get-cert-renew-intervalduration2hNorenewal interval for injected workload certificates
--workload-claims-host-dirstring""Conditionalhost directory holding the NRI inventory socket; required for injected certificates, whose get-cert container redeems a sandbox token
--mesh-imagestring""Conditionalpod mesh endpoint image; required with --get-cert-image

c8s cds

Run the Certificate Distribution Service (CDS) from a measured c8s-cds/v1 configuration. A verified self-report must bind its exact bytes. The host-readable configuration holds public inputs, including operator keys, configured node pins and policy; it carries no private keys or secrets. Subcommands are ca, config new, ha, and verify (see c8s verify).

A singleton holds its mesh CA and secrets in memory. An HA configuration selects replicated volatile state and requires explicit Genesis. A replica restart need not lose cluster state; losing all replica memory does. Surviving memory is retained when quorum loss stops serving. CA certificates renew under the same key after half their lifetime; certificate fingerprint changes alone do not establish a new CA key.

FlagTypeDefaultRequiredDescription
--hoststring0.0.0.0Nolisten address; auto selects this VM's primary IPv4 address
-p, --portint8443Nolisten port
--log-levelstringinfoNolog level: debug, info, warn, error
--attestation-api-urlstring""Yesthis VM's attestation API; must use a literal loopback IP address
--ca-common-namestringc8s Mesh CANosingleton mesh CA common name; HA uses the built-in common name
--ca-cert-validityduration8760hNosingleton mesh CA certificate lifetime; HA uses the built-in lifetime. Both renew after half-life under the same key
--jwt-clock-skewint6430Nooperator JWT clock-skew tolerance in seconds; singleton startup without --allowlist-persistent also delays operator-token requests for this interval
--cert-ttlduration24hNoTTL of the leaf and EAR /attest issues, capped at the built-in 24h leaf ceiling
--named-cert-ttlduration6hNoupper 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-ttlduration1mNolifetime of an attestation challenge nonce; issuance and /secrets keep separate pools
--request-timeoutduration5sNoper-request timeout on /attest and on the inventory callback (0 disables)
--max-request-sizeint6465536Nomaximum body bytes on /attest, /authenticate and workload secret routes; must be positive
--read-timeoutduration10sNoHTTP server read timeout
--read-header-timeoutduration5sNoHTTP server read-header timeout
--write-timeoutduration10sNoHTTP server write timeout
--idle-timeoutduration20sNoHTTP server idle timeout
--max-header-bytesint1048576Nomaximum HTTP request header bytes
--san-validationbooltrueNorequire CSR IP SANs to equal the request source IP (false rejects CSRs carrying IP SANs)
--allowed-cn-patternstring""Noregex the CSR Subject CN must match in full (empty disables)
--readiness-intervalduration10sNointerval of the attestation-api health check behind /readyz; must be positive
--min-ca-validityduration1hNo/readyz fails when the loaded mesh CA has less than this remaining lifetime
--allowlist-dbstring""Yespath to the allowlist SQLite database
--allowlist-persistentboolfalseNodeclare the singleton allowlist SQLite database durable; does not persist its mesh CA or secret memory. Refused with an HA configuration, whose state is replicated and volatile
--rate-limitfloat6410Nomax requests per second per source IP on attestation endpoints
--rate-burstint20Nomax burst size per source IP
--rate-limiter-max-entriesint10000Nomax entries in the per-IP rate limiter; once full, a new source evicts the least recently seen one
--rate-limiter-evict-intervalduration1mNointerval for per-IP rate limiter eviction sweep
--rate-limiter-idle-timeoutduration5mNoidle duration before a per-IP rate limiter entry is evicted
--secrets-max-pathsint1024Nomax distinct secret paths held in memory across every workload; must be positive
--secrets-max-paths-per-workloadint64Nomax secret paths one allowlist entry may hold; must be positive and below --secrets-max-paths
--secrets-max-value-bytesint4096Nomax bytes in one secret value; must be at least 32, the size of every value the CDS generates
--sandbox-ledger-max-entriesint10000Nomax sandbox-to-inventory bindings held in memory; must be positive
--armtls-cert-ttlduration24hNoTTL of the RA-TLS serving certificate CDS presents
--configstring""Yespath to the exact measured CDS launch document, c8s-cds/v1

c8s cds config

new takes no positional arguments and writes cds-config.yaml and cds-pin.json to a new directory. The pin binds the exact configuration bytes and CDS guest image; all HA replicas boot those same bytes. Generate the release/options-matched component seed first with install --allowlist-seed-out, then generate and verify the external CDS before installation.

FlagTypeDefaultRequiredDescription
--outstring""Yesoutput directory; must not exist
--cluster-idstring""Yescluster name, an RFC 1123 label
--operator-keysstring""YesPEM public-key bundle file path authorizing policy writes and HA decrees
--allowlist-seedstring""YesJSON component allowlist matching the release and deployment options
--workloadsstring""Notenant allowlist added to the seed; names cannot overwrite component entries
--node-pinsstring""Yescomplete node launch identities for singleton admission and the default HA Genesis node set
--node-cidrstring arraynilYesallowed node inventory subnets; repeatable
--pod-cidrstring arraynilYespod ranges, excluded from node inventory ranges; repeatable
--service-cidrstring arraynilYesservice ranges, excluded from node inventory ranges; repeatable
--leaf-dns-namestring arraynilNoallowed literal leaf DNS SAN; repeatable
--leaf-dns-patternstring arraynilNofull-match DNS SAN regex; repeatable. If this flag is omitted, uses ^[a-z0-9-]+[.][a-z0-9-]+[.]svc$ (for example api.tenant.svc), including when --leaf-dns-name is supplied
--image-manifeststring""Yesexact CDS guest image's manifest.json
--platformstring""YesCDS TEE: sev-snp or tdx
--vcpusint slicenilConditionalSEV-SNP vCPU counts, one pin per shape; at least one required for SNP; repeatable
--replicastring arraynilConditionalHA discovery DNS name or IPv4 address, no port or load-balanced address; repeatable; requires --voters
--votersint0ConditionalHA initial voter seats, odd 1–9; requires replicas. Omitting both HA flags selects singleton mode

HA discovery reaches distinct replica identities on their client port and peer port 8444. Up to 16 nonvoters can join. Replicated state has a 256 MiB bound with headroom; this is not available secret capacity. Workloads and voter count initialize live state. Configuration node pins supply the default for HA Genesis; signed Genesis selects the initial admitted node set. Signed changes can update live state. Pinning the configuration does not freeze the live node policy forever.

c8s cds ha

Inspect and administer the replicated CDS. All leaf commands take no positional arguments. Reads verify each reached CDS against --cds-pin. Decrees are signed under an operator key in the measured configuration and posted to POST /ha/decrees.

SubcommandPurpose
statusread every selected replica's GET /ha/status; print serving state and alarms
decreesread GET /ha/decrees from the first answering replica and check every retained operator signature; at most 256 applied decrees are retained
pin-policyread GET /ha/pins, check its signature, cluster and launch-file binding, and optionally write the resulting pins and signed decree; 404 before a pin decree exists
decree genesisbind an unjoined process and its prospective CA to the initial CDS/node pins; explicit Genesis starts an HA cluster
decree pinsreplace the complete accepted CDS image set; overlapping old/new sets support image rolls
decree node-imagesreplace the complete node identity set CDS certifies, independently of CDS image pins
decree votersset the odd target voter-seat count; seats change one at a time while preserving a majority
decree rotate-keyreplace the mesh CA key; recreate pods for new credentials and update client CA anchors
decree recoversign and deliver a survivor-bound Recover intent; delivery can hold it, but production recovery is not wired to apply it
decree dismiss-recoversign a decree naming a Recover doubt to dismiss; does not supply an automatic fencing or recovery mechanism
decree admitlet one unjoined process temporarily admit the serving cluster's applied CDS image set; each restart needs a fresh decree

status exits unsuccessfully for an unreachable, nonserving or wrong-cluster replica, or version/CA disagreement. Not every printed alarm changes its exit status. Only roll_safe and divergence are leader-specific; followers also report voters and checkpoints. Diagnostics remain reachable when ordinary APIs return 503 because a replica lacks a valid leader-confirmed serving lease or applied state.

Decree delivery reports held, applied at version, or refused. A successful CLI exit for a held decree proves acceptance only. Production held-decree consumers handle Genesis and Admit; Recover has no operational consumer or automatic Doubt/fencing proposer. Preserve surviving VMs when permanent quorum loss halts service. Recover acceptance is not a recovery procedure, and total memory loss cannot restore secrets or the CA key.

Before planned removal and between replacements, require the leader's roll_safe result. A VM already known destroyed may be replaced first while a majority serves; its dead vote itself makes the roll gate false. Unreachability does not prove destruction. Image rolls require overlap, per-process Admit and majority preservation. rotate-key changes mesh CA authority only; operator authorization keys stay launch-bound. Clients can adopt an independently signed, strictly newer provisional pin decree over unverified transport; an initial refresh failure keeps the launch pins. New connections fail across changed CA keys; established streams are not guaranteed to terminate immediately.

Flags shared by the read commands and/or decree commands are listed once with their scope:

FlagTypeDefaultRequiredDescription
--configstring""Yesall leaf commands: exact CDS measured configuration
--cds-pinstring""Yesall leaf commands: CDS image/launch-file policy used for every endpoint read or delivery; include both images during a roll
--urlstring arraynilNostatus, decrees, pin-policy: <host>[:8443] replicas overriding config discovery; repeatable
--jsonboolfalseNostatus, decrees: print full JSON reports or records with signature-check results
--outstring""Nopin-policy: write reconstructed pin document; every decree command: write signed decree in addition to posting
--decree-outstring""Nopin-policy: write the signed pin decree for launch-config add-agent --pin-decree
--operator-keystring""Yesevery decree command: EC private-key PEM file path matching measured operator authority
--expires-induration10mNoevery decree command: positive adoption validity interval
--base-versionuint640Yespins, node-images, voters, rotate-key, recover, dismiss-recover: current applied version, explicitly supplied even if 0
--targetstring""Yesgenesis, recover, admit: one process at <host>[:8443]; must resolve to exactly one IPv4 address
--tostring""Yespins, node-images, voters, rotate-key, dismiss-recover: replica to receive the decree and forward to its leader
--platformstring""Yesgenesis, pins: CDS platform, sev-snp or tdx
--image-manifeststring arraynilYesgenesis, pins: accepted CDS guest-image manifests; repeatable
--vcpusint slicenilConditionalgenesis, pins: accepted SEV-SNP CPU counts; required for SNP; repeatable
--nodesstring""Conditionalnode policy document; optional for genesis (defaults to measured config), required for node-images
--resume-versionuint640Yesgenesis, recover: highest known prior version (explicit 0 for first Genesis); Recover requires at least --base-version
--aloneboolfalseNogenesis: allow single-replica start without discovery peers; a host hiding other replicas could cause a separate cluster
--votersint0Yesvoters: target voter seats, odd 1–9
--i-understand-rotation-forks-the-clusterboolfalseYesrotate-key: must be true to acknowledge the new mesh CA key requires fresh workload credentials
--i-understand-recover-is-break-glassboolfalseYesrecover: must be true to acknowledge missing committed writes; does not make Recover operational
--recover-intentstring""Yesdismiss-recover: Recover intent ID reported as doubt
--clusterstring""Yesadmit: serving replica <host>[:8443] supplying the applied pin decree

c8s cds ca

Read the mesh CA bundle CDS serves at GET /ca and write it as PEM to --out, or to stdout. It is the anchor c8s secrets put --mesh-ca, c8s volume create --mesh-ca and c8s verify --mesh-ca take. The read travels the attested connection those commands use and requires endpoint pins. A launch measurement identifies the image, not the instance, so the SHA-256 of each certificate is printed on stderr for comparison on a later read. A singleton restart or loss of all replica memory replaces the mesh CA key. A surviving HA cluster retains it across individual restarts. Same-key certificate renewal also changes certificate fingerprints; compare the key separately when judging cluster continuity. The router front door does not relay /ca, and a URL that serves a router discovery document is refused; point --url at CDS directly.

FlagTypeDefaultRequiredDescription
--urlstring""Yesdirect CDS HTTPS base URL; plaintext and router discovery endpoints are refused
--image-policy-filestring""Yescomplete CDS image and launch-file pin, such as cds-pin.json; required for HTTPS, including reads
--timeoutduration15sNoper-request timeout
--operator-keystring""Noinherited operator credential flag (env C8S_OPERATOR_KEY); the CA read does not require a write token
--insecureboolfalseNoinherited connection flag; cds ca still requires HTTPS
--outstring""Nowrite the bundle here instead of stdout

c8s allowlist

Read and mutate the CDS-served allowlist that nri-image-policy enforces on every node. It is a set of named entries, each pinning an init/main container set with per-container argv, mount, environment and path policy. An image admitted under any command line is an entry whose command and args policy are both any; add writes one. Reads are unauthenticated; writes are signed with the operator EC private key whose public half is in the CDS measured configuration. See The Allowlist for usage.

SubcommandArgumentsPurpose
list—list the current allowlist entries
get<name>print one entry as canonical JSON
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
derive<name> <file|->print an entry built from a Pod, Deployment, StatefulSet or DaemonSet given as JSON; may read image argv from the registry with crane. Injected containers are dropped
add<digest> <image>write the entry <image basename>-<first 12 hex of digest>: one container at <digest> with command and args policy any (operator key required)
apply<file|->replace the named entries whole in a signed full-document update (operator key required)
edit<name>fetch an entry, edit it in $EDITOR, and apply the result (operator key required)
delete<name> [<name>...]delete one or more entries (operator key required)
upload<file>atomically replace the entire allowlist with the contents of a file; CDS assigns the new version (operator key required)

For add, <digest> is sha256: plus 64 hexadecimal digits; <image> is a nonempty informational label (* is refused) (such as a tagged image reference), not a registry lookup. For example, this prints a dry run:

c8s allowlist add sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef example/app:1 --url https://cds.example:8443 --dry-run

The router front door relays /allowlist; commands that contact CDS can use that route.

Entry edits (add, apply, edit, delete) canonicalize and sign a complete policy and use conditional whole-document writes with bounded conflict retries. upload refuses a racing write for review. Exact canonical bytes retain the signature; seed and noncanonical policies may be unsigned. derive prints a bare name-to-entry map and has no egress flag.

Signed egress policy admits at most eight unique TCP exits per workload: masked IPv4 /16 or narrower, or IPv6 /48 or narrower, excluding protected ranges. It requires pinned argv and mounts plus a unique, complete sandbox main-container match. Environment follows the selected policy, which may be any. Exits remain unavailable until observed containers satisfy every main-container policy of the matching workload entry. Exits bypass capture without encrypting payloads; changed or removed exits require pod recreation. See The Allowlist.

HA allowlist history is periodically pruned toward 1000 entries and 64 MiB, preserving the current document; these targets can be exceeded before pruning. Removed objects and signatures become unavailable. HA writes can fail with 503 or 507 state_capacity.

Persistent flags, registered on every subcommand:

FlagTypeDefaultRequiredDescription
--urlstring""Yesrouter or direct CDS base URL; required by every subcommand that contacts the CDS (lint, derive 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
--measurementsstring slicenilNoflat launch-digest pins for the attested endpoint; cannot establish direct CDS launch-file binding. Unpinned HTTPS reads and writes are refused
--measurements-filestring""Nofile of allowed launch measurements, one hex digest per line; merged with --measurements
--image-policy-filestring""Conditionalcomplete endpoint policy; direct CDS requires cds-pin.json with launch-file binding. Router discovery uses its independently intended node policy. Excludes --measurements and --measurements-file
--timeoutduration15sNoper-request timeout
--operator-keystring""Nooperator EC private key PEM file whose public key is pinned in the CDS measured configuration (env C8S_OPERATOR_KEY; the flag wins); required for writes
-o, --outputstringtextNooutput format: text or json
--insecureboolfalseNodev/test only: allow a plaintext http:// CDS URL, skipping RA-TLS attestation of CDS

Per-subcommand flags:

FlagTypeDefaultRequiredDescription
--exit-codeboolfalseNodiff only: exit non-zero when the file and the live allowlist differ
--onlineboolfalseNolint only: also check each digest exists in its registry via crane
--seedstring""Nolint only: the release/options-matched component allowlist seed; lint then names each chart-generated entry the seed now generates under another name, safe to delete once no pod runs it
--strictboolfalseNolint, upload: treat lint warnings as fatal (lint errors already fail on their own)
--cvm-modestring""Noupload: bare-metal, gke, or aks; bare-metal excludes both nri-image-policy and attestation-api from the required components because the measured node supplies them
--dry-runboolfalseNoadd: print the intended entry without calling CDS; apply: show the diff without writing any entry; upload: show the diff without replacing the allowlist
--forceboolfalseNoupload only: upload even if core C8s components are missing from the file's image labels. Bypasses that check alone
--requirestring slicenilNoupload: override required component identifiers; default armtls-mesh, nri-image-policy, attestation-api, nginx
--labelstring""Noderive only: optional label written into the derived entry
--secret-readstring arraynilNoderive only: grant read on this secret path (repeatable); with none the derived entry carries no secrets block. A grant requires every container to pin argv (exact or deny) and mounts (deny, or exact with no host rule)
--envstring""One of twoderive only: environment policy for every container, any or deny; exactly one of --env and --env-file is required
--env-filestring""One of twoderive only: JSON file mapping container names to explicit environment policies, including exact and match
--mountsstring""Noderive: any or deny; omitted with no --mounts-file, uses deny (platform mounts only). Mutually exclusive with --mounts-file
--mounts-filestring""Noderive only: JSON file mapping container names to explicit mount policies, covering every derived init and main container; exact mount rules go here

For a bare-metal node, use upload --cvm-mode bare-metal to check the appropriate component set. --force bypasses the missing-component check and requires a separate review of the policy.

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 apply. Values are held in singleton memory or replicated HA memory. A singleton restart or loss of all replica memory empties the store; preserve operator escrow for restoration. See Secrets.

SubcommandArgumentsPurpose
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 in its measured configuration. The router front door does not relay /secrets or /ca, and both subcommands refuse a URL that serves a router discovery document before they send anything: point --url at the external CDS client address and pin its image and exact launch file with cds-pin.json.

Persistent flags, registered on every subcommand:

FlagTypeDefaultRequiredDescription
--urlstring""Yesdirect external CDS HTTPS base URL; router discovery endpoints are refused. Plaintext HTTP requires --insecure
--image-policy-filestring""Conditionalcomplete CDS image and launch-file pin, such as cds-pin.json; required for HTTPS, including reads
--timeoutduration15sNoper-request timeout
--operator-keystring""Nooperator EC private key PEM file whose public key is pinned in the CDS measured configuration (env C8S_OPERATOR_KEY; the flag wins). Both subcommands sign, so one of the two must be set
--insecureboolfalseNodev/test only: allow a plaintext http:// CDS URL, skipping RA-TLS attestation of CDS

Per-subcommand flags:

FlagTypeDefaultRequiredDescription
--from-filestring""Noput only: read the value from this file instead of stdin
--overwriteboolfalseNoput only: replace a value already at the path. Without it an occupied path is refused, and the error names what is there
--mesh-castring""Conditionalput only: PEM bundle file path for the mesh CA this CDS must serve, the same anchor c8s verify --mesh-ca takes; c8s cds ca reads it. The write is refused unless every certificate CDS serves at /ca is in the bundle. Required unless --force; a plaintext --insecure endpoint is exempt
--forceboolfalseNoput only: write without checking the CDS mesh CA against --mesh-ca. Unrelated to --overwrite
--dry-runboolfalseNoput only: print the intended change without calling CDS
--sandboxstring""Yesexplain only: sandbox ID to report on. It is carried on the pod's certificate; c8s verify prints it
--jsonboolfalseNoexplain 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 operator provisioning process generates the key outside the TEE and writes escrow before publishing it to CDS memory. A key path is create-only: CDS refuses a --path that already holds a value. See Volumes.

SubcommandArgumentsPurpose
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 require a Linux node with LIO support and root; the C8s node image does not support LIO attachment. A QEMU/KVM node receives a disk with the required serial from its hypervisor.

Persistent flags, registered on every subcommand:

FlagTypeDefaultRequiredDescription
--urlstring""Conditionaldirect CDS base URL, verified as for c8s secrets; a router front door is refused before the build. Required by create and not read under --dry-run. attach and detach inherit it and never contact CDS
--image-policy-filestring""Conditionalcomplete CDS image and launch-file pin, such as cds-pin.json; required for HTTPS, including reads
--timeoutduration15sNoper-request timeout
--operator-keystring""Nooperator EC private key PEM file whose public key is pinned in the CDS measured configuration (env C8S_OPERATOR_KEY; the flag wins); required for the store write
--insecureboolfalseNodev/test only: allow a plaintext http:// CDS URL, skipping RA-TLS attestation of CDS

create flags:

FlagTypeDefaultRequiredDescription
--namestring""Yesvolume name; forms the device serial c8s-vol-<name>, so a DNS-1123 label of at most 12 characters
--sourcestring""Conditionaldirectory whose contents become the volume; required for an immutable volume, an optional preload with --mutable
--mutableboolfalseNobuild 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
--sizestring""Conditionalmutable filesystem size, e.g. 50Gi; inferred from --source when one is given, required with --mutable and no --source, and refused without --mutable
--outstring""Yespath the encrypted image is written to; must not exist
--pathstring""Yessecret-store path for the key, e.g. /tenant-a/volumes/weights; absolute, clean, no wildcards
--escrow-outstring""Yescreate: key blob output, mode 0600; must not exist. Keep operator escrow for restoration
--mesh-castring""ConditionalPEM mesh-CA bundle file path checked as for c8s secrets put --mesh-ca; required for publishing the key unless --force, --dry-run, or plaintext HTTP with --insecure applies
--forceboolfalseNowrite the volume key without checking the CDS mesh CA against --mesh-ca
--nodestring""Nonode holding the device; emitted as a nodeSelector on the printed annotations
--work-dirstring""Nodirectory for build intermediates (default: a temp dir); they are removed either way
--dry-runboolfalseNobuild the image and write the escrow file, but do not call CDS
--jobsint0Nocreate: parallel encryption workers; 0 selects min(GOMAXPROCS, 16), a positive value selects that count, and negative values are refused; output format is unchanged

attach and detach flags:

FlagTypeDefaultRequiredDescription
--imagestring""Yesattach only: path on this node to the encrypted image. The device serves the file opened here, not the path
--config-rootstring""Noattach, detach: configfs mount; empty selects /sys/kernel/config
--jsonboolfalseNoattach only: print the name and serial as JSON

c8s routes

Read and write the signed route manifest (c8s.routes/v1) CDS stores at /routes. The router routes application requests by this manifest alone, and c8s install --upstream writes the first one for an adopted workload. A write must carry a revision greater than the stored one, and is signed with the operator key, as for c8s allowlist. add and rm fetch the stored manifest, verify it against --operator-keys, change one route, and write the next revision: the later of the stored revision plus one and the current Unix time, or --revision. They set notBefore to now, or keep a later stored value, and print every route the new revision carries before signing. The router does not relay /routes: point --url at CDS itself, with no path. The route digest show and digest print is the value c8s verify --route-digest takes.

SubcommandArgumentsPurpose
show—print the stored manifest, its revision, notBefore, maxAgeSeconds, route digest and routes
digest<file>validate a manifest file and print its route digest, the hex SHA-256 of its exact bytes
put<file>sign a manifest file's exact bytes and store them (operator key required)
add—add or replace one route and store the next revision (operator key and --operator-keys required)
rm—remove one route and store the next revision; a host left with no routes is removed (operator key and --operator-keys required)

Persistent flags, registered on every subcommand:

FlagTypeDefaultRequiredDescription
--urlstring""Conditionaldirect CDS base URL; required for show, add, rm (including their dry runs), and put without --dry-run. digest and put --dry-run are offline. HTTPS verifies CDS; HTTP requires --insecure
--measurementsstring slicenilNoflat launch-digest pins for the attested endpoint; cannot establish direct CDS launch-file binding. Unpinned HTTPS reads and writes are refused
--measurements-filestring""Nofile of allowed launch measurements, one hex digest per line; merged with --measurements
--image-policy-filestring""Conditionalcomplete endpoint policy; direct CDS requires cds-pin.json with launch-file binding. Router discovery uses its independently intended node policy. Excludes --measurements and --measurements-file
--timeoutduration15sNoper-request timeout
--operator-keystring""Nooperator EC private key PEM file whose public key is pinned in the CDS measured configuration (env C8S_OPERATOR_KEY; the flag wins); required for writes
--insecureboolfalseNodev/test only: allow a plaintext http:// CDS URL, skipping RA-TLS attestation of CDS
--operator-keysstring""NoPEM file of trusted operator public keys; verifies the write token of every fetched route manifest. show verifies when it is given; add and rm require it

Per-subcommand flags:

FlagTypeDefaultRequiredDescription
--hoststring""Yesadd, rm: request host, lower-case without port
--pathstring""Yesadd, rm: route path, beginning with /
--matchstringadd: prefix; rm: ""Noadd, rm: exact or prefix; rm requires a choice when both exist at --path
--addressstring""Yesadd only: backend host:port
--workloadstring""One of two schemesadd: expected backend workload name; its leaf must carry this name and the same allowlist digest as the router's leaf, or routing fails. Select this alone or both --server-name and --ca; mixing schemes is refused
--server-namestring""Conditionaladd: address-backend TLS server name; required with --ca, mutually exclusive with --workload
--castring""Conditionaladd: trust-anchor PEM file path; required with --server-name, mutually exclusive with --workload; must not include the CDS mesh CA
--newboolfalseNoadd only: start a new manifest when CDS stores none (the first route of a cluster)
--max-ageduration24hNoadd only: maxAgeSeconds of a manifest --new starts; otherwise add keeps the stored value
--revisionuint640Noadd, rm: revision to write, above the stored one; default the later of the stored revision plus one and the current Unix time
--dry-runboolfalseNoadd, rm: fetch the stored manifest and print the new one without storing it; put: validate the file and print its revision and digest without calling CDS
-o, --outputstringtextNoshow only: text, or json for the envelope CDS serves
--rawboolfalseNoshow only: print the manifest bytes only, ready to edit and put

After a CDS reset that lost its database, put the last manifest rather than starting a new one.

c8s cds-attest

Run the router routing, attestation and over-encryption sidecar (the c8s-verify/v1 server side). It always runs in the router pod. It polls the operator-signed route manifest from CDS (GET /routes) over RA-TLS, verifies it under the operator keys, and routes by it: plain application requests nginx hands to its loopback routing listener, and requests decrypted from the tunnel. With the attestation endpoints on (chart value 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); both bind the digest of the applied manifest into their evidence. Until it applies a manifest, routed requests get 503 and handshakes are refused with 503 routes_unavailable; once maxAgeSeconds passes without a successful poll, handshakes are refused with routes_stale while routing goes on. A request whose host is not a manifest host, or whose path matches no route, gets 404; a backend TLS failure gets 502. It's a chart-managed component, not normally run by hand — see Consumer Verification for the protocol.

Mesh identity credentials are fixed at /etc/c8s/certs/tls.crt, tls.key and ca.crt. Applications serve ordinary TCP/HTTP; the injected endpoint holds their private mesh credentials. Workload backends must present the expected name and the same allowlist digest as the router leaf; mismatches fail routing. The ordinary nginx-routed HTTP body cap defaults to 1048576 bytes (oversize requests return 413). The attest-pq tunnel instead caps the encoded sealed record at 8 MiB, including overhead, so usable application payload is smaller. Decoded requests go directly to the backend without that ordinary HTTP cap. Backend limits, tunnel response buffering, and aggregate/per-client memory limits also apply.

FlagTypeDefaultRequiredDescription
--session-max-ageduration5hNoabsolute session lifetime: a session's keys retire this long after establishment, however busy it is
--hoststring127.0.0.1Nolisten host (loopback: nginx proxies to it)
-p, --portint8800Nolisten port
--log-levelstringinfoNolog level: debug, info, warn, error
--attestation-api-urlstring""Yeslocal attestation API used for CDS verification and production evidence, required even with a fixture; node-mounted pins require the node verifier. $(NODE_IP) reads /run/c8s/node-ip; $(HOST_IP) reads the environment
--platformstring""ConditionalTEE platform: snp, az-snp, az-tdx, or tdx; required when attestation endpoints are enabled
--generationstringgenoaNoAMD processor generation for the browser's bare-SNP verifier (--platform snp only, ignored otherwise): milan | genoa | turin
--front-door-modestring""Conditionalcds or acme uses a TEE-held serving key; webpki uses a host-visible Secret and refuses attest-lb with external_tls while retaining attest-pq. Required with enabled attestation unless --front-door-mode-file supplies it
--front-door-mode-filestring""Nofile holding the front-door mode, read at start; mutually exclusive with --front-door-mode
--serving-cert-filestring""Nopath 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
--acme-serving-cert-filestring""Noserving-leaf PEM nginx presents in acme front-door mode; used instead of --serving-cert-file when --front-door-mode-file reads acme
--expected-workloadstring""Nogate /readyz on the mesh identity leaf carrying a matched-workload stamp with this exact name; empty keeps /readyz unconditionally 200
--evidence-fixturestring""Nodev only: serve recorded TEE evidence from this file instead of the attestation-api
--session-ttlduration5mNoestablished-session idle TTL
--read-header-timeoutduration5sNoHTTP read-header timeout
--tunnel-io-timeoutduration30sNohow long a tunnel upload, or its sealed response download, may make no progress; must be positive
--attest-endpointsbooltrueNoserve attest-pq, attest-lb and the tunnel; false serves only the routing listener and probes, and requires --routing-port. The chart sets it from router.attest.enabled
--cds-urlstring""ConditionalCDS HTTPS origin for route polling; required unless the node mounts its endpoint; an explicit override of a mounted endpoint is refused
--image-policy-filestring""Conditionalcomplete CDS image and launch-file pin; required when node-mounted pins are absent. Node-mounted pins take precedence and this flag is then ignored
--operator-keys-filestring""NoPEM public-key file path for route signatures when measured node keys are absent; otherwise measured keys take precedence. Unset, fetch keys from the verified CDS
--routes-poll-intervalduration30sNopositive interval between signed route-manifest polls
--routing-hoststring127.0.0.1Norouting listener host (loopback: nginx proxies application requests to it)
--routing-portint0Norouting listener port; 0 disables the listener (the tunnel still routes by the applied manifest)
--backend-timeoutduration1hNohow long a request or upgraded connection on the routing listener may go with no data moving either way; a tunnelled request, whose response is buffered whole, gets this long in total
--reserved-pathsstring slicethe router's own endpointsNopaths the router serves itself; a request under one matches no manifest route. Default: /allowlist, /.well-known/c8s/, /.well-known/cds-cert.pem, /.well-known/mesh-ca.pem, /.well-known/acme-challenge/, /v1/discovery, /readyz, /healthz. Each entry must be a normalized path
--tunnel-budgetquantity""Nobuffer budget, e.g. 32Gi; unset uses 75% of the container memory limit or 32Gi without one, floored at 152 MiB. Explicit budgets must be at least 152 MiB. Per-client allowance is min(budget, max(budget/4, 152 MiB)); excess requests get 503 tunnel_busy
--publish-routesboolfalseNoserve the applied signed route manifest at /.well-known/c8s/routes, for clients that verify it under pinned operator keys; off, the path answers 404. Requires --attest-endpoints=true. The chart sets it from router.routePublication.enabled
--measured-policies-filestring""Nonode TDX policy journal included in attestation bundles; empty omits the list; requires --attest-endpoints=true

c8s acme

Run the router's in-guest ACME sidecar (acme front-door mode). It runs beside nginx in the router pod and keeps the full chain at /etc/c8s-acme-tls/cert.pem, with private and account keys under /etc/c8s-acme-key, issued over ACME HTTP-01: nginx's :80 server proxies /.well-known/acme-challenge/ to the loopback challenge listener. Configured domains whose challenge paths do not yet reach this router are added once they do, without blocking the others. The certificate renews at 2/3 of its lifetime; nginx reads renewed credentials on subsequent handshakes, while open connections retain their negotiated leaf. On a node image the inputs come from the signed launch file through the *-file flags; an empty domains file means no ACME, and nginx serves the mesh leaf from --standby-cert-dir instead. A chart-managed component, not run by hand.

FlagTypeDefaultRequiredDescription
--domainsstring slicenilConditionalcertificate FQDNs; repeatable/comma-separated; mutually exclusive with --domains-file. One domain source is required
--domains-filestring""Conditionalfile of whitespace-separated domains, read at start; mutually exclusive with --domains. An empty file requires --standby-cert-dir
--acme-emailstring""Nocontact email registered with the ACME account
--acme-email-filestring""Nofile holding --acme-email; an empty file keeps the flag value
--acme-directory-urlstringhttps://acme-v02.api.letsencrypt.org/directoryNoACME directory URL; point it at a staging directory when testing
--acme-directory-url-filestring""Nofile holding --acme-directory-url; an empty file keeps the flag value
--standby-cert-dirstring""Conditionalwith an empty --domains-file, do no ACME: report ready once this directory holds the tls.crt and tls.key nginx serves instead
--challenge-portint8402Noloopback port answering ACME HTTP-01 challenges
--http-portint8080Noloopback port of nginx's :80 server, probed round-trip before each order
--ready-portint0Noport serving GET /healthz, and GET /readyz, 200 once cert.pem and key.pem exist (0 disables it)
--log-levelstringinfoNolog level: debug, info, warn, error

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.

FlagTypeDefaultRequiredDescription
--hoststring127.0.0.1Nolisten host; must be a loopback IP (nginx is the public listener)
-p, --portint8801Nolisten port; 1–65535
--cds-urlstring""ConditionalHTTPS CDS origin; required unless the node supplies the endpoint. Node-mounted endpoint/pins must be paired and cannot be overridden by flags
--image-policy-filestring""Conditionalcomplete CDS image and launch-file pin; required unless the node supplies pins, which refuse a flag override
--attestation-api-urlstring""Noattestation-api URL used to verify CDS evidence. A literal $(NODE_IP) is replaced by the address in /run/c8s/node-ip and $(HOST_IP) by the HOST_IP environment variable; startup fails when that source is missing or not an IP address
--request-timeoutduration30sNotimeout for one request to CDS; must be positive
--read-header-timeoutduration5sNoHTTP request-header timeout; must be positive

c8s attest-proxy

Expose the pod-loopback attestation API through a node-local Unix socket. Socket ownership and mode restrict reachability; the socket is not a routable attestation endpoint. With no subcommand, serve until stopped. healthcheck performs one GET /health over its socket with a 3s timeout and exits 0 only on success; it registers only --socket. Both accept no positional arguments.

FlagTypeDefaultRequiredDescription
--socketstring""Yesabsolute socket path to serve (mode 0660) or, for healthcheck, probe
--socket-gidint65532Noserver only: group owning the socket; 0 keeps the process group
--upstreamstringhttp://127.0.0.1:8400Noserver only: HTTP(S) attestation API base URL; deployment uses pod loopback
--health-addrstring""Noserver only: TCP address for GET /healthz; empty disables
--read-header-timeoutduration5sNoserver only: positive socket-listener header timeout

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; 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) or --url; one target is required unless --from-file supplies evidence. If both target forms are given, the positional argument wins. With --from-file, evidence is read from the file even if a target is supplied. c8s cds verify is the same command with CDS presets (--kind cds, default port 8443); --mode stays auto, which resolves to armtls-cert for a CDS target. See the verification guide for the end-to-end workflow.

FlagTypeDefaultRequiredDescription
--urlstring""Conditionaltarget URL or host:port; required unless a positional target or --from-file is supplied. A positional target overrides this flag
--kindstringautoNocomponent being verified: cds, lb, workload, or auto
--modestringautoNoevidence mode: auto, armtls-cert, discovery, attest-pq, or attest-lb; any other value is a usage error. auto resolves to armtls-cert for --kind cds, discovery for --kind lb, and otherwise tries discovery, then the serving cert
--discovery-pathstring/v1/discoveryNopath of the LB discovery document (discovery mode)
--server-namestring""NoTLS SNI server name (for port-forward / routed domains)
--timeoutduration15sNoper-attempt timeout (evidence fetch and AMD KDS collateral fetch)
--from-filestring""Noverify evidence from a saved PEM certificate or attestation-response JSON instead of dialing; with --mode attest-lb, also pass --observed-serving-cert and --attestation-nonce
--observed-serving-certstring""Nowith --mode attest-lb --from-file: PEM serving leaf observed on the connection that fetched the receipt
--attestation-noncestring""Nowith --mode attest-lb --from-file: unpadded base64url nonce sent to fetch the receipt
--measurementsstring slicenilNoallowed 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 --image-policy-file
--measurements-filestring""Nofile of allowed launch measurements, one hex digest per line; feeds the same allowlist as --measurements and carries the same exclusions
--image-manifeststring""Nobuild-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, --image-policy-file, or a by-hand --rtmr 1=/--rtmr 2=. TDX evidence only — a policy error against SEV-SNP evidence
--expected-rtmr3string""NoDEPRECATED — use --rtmr 3=<sha384-hex>, which is the identical pin under identical rules. Retained so existing invocations keep working
--operator-pkeystring""Nooperator public-key PEM file path; seed RTMR[3] replay from its exact bytes and replay measured policy history supplied by evidence. Requires --image-manifest; excludes other RTMR[3] pins; TDX only
--rtmrstring slicenilNoexpected 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
--image-policy-filestring""Conditionalcomplete target identity policy; required for --kind cds, using launch-file-bound cds-pin.json. Node/router targets use their independently approved policy. Excludes --measurements, --measurements-file, and --image-manifest
--served-policy-filestring""Noexplicitly require the CDS /measurements set to equal this independently intended current node policy; use peers.json only while it matches the intended set. HA's initial set comes from Genesis, its signed initialization decree; c8s cds ha decree genesis --nodes can override that set, and later node-images decrees can change it. Endpoint pinning alone does not request this check
--operator-keysstring""NoPEM bundle file path of expected operator public keys. --kind cds: verification fails unless the key set the attested target serves at /operator-keys matches it. --mode attest-pq/attest-lb: the route manifest the router publishes at /.well-known/c8s/routes must verify under these keys, and its digest must be the one the evidence binds; refused with --kind cds in those modes
--route-digeststring slicenilNoexpected route digest(s) (repeatable / comma-separated), the hex SHA-256 of the route manifest bytes as c8s routes show prints it. attest-pq and attest-lb evidence binds one, so evidence binding any other digest fails. These modes require this or --operator-keys, not both; a saved attest-pq bundle or attest-lb receipt (--from-file) requires this
--routes-floorstring""Nowith --operator-keys in attest-pq/attest-lb: <revision>:<route digest hex> last accepted; a published manifest with a lower revision, or the same revision and another digest, fails (rollback)
--sandbox-idstring""Noexpected CRI pod sandbox ID on the target's leaf; requires --mesh-ca. Refused with --kind cds, including default c8s cds verify
--workloadstring""Noexpected matched-workload name on the target's leaf; requires --mesh-ca, since CDS's signature on the leaf is what vouches for the stamp. Refused with --kind cds, including default c8s cds verify
--allowliststring""Nofile 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. Refused with --kind cds, including default c8s cds verify
--mesh-castring""NoPEM bundle file path for 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 and attest-lb mode it also upgrades a responder-chosen chain anchor from a partial verdict to a verified one. c8s cds ca reads it. Refused with --kind cds, including default c8s cds verify
--init-datastring""Noexpected 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-debugboolfalseNoaccept debug-enabled guests
--min-tcb-bootloaderuint0Nominimum bootloader TCB component (0–255); SEV-SNP evidence only, a policy error against TDX evidence
--min-tcb-teeuint0Nominimum TEE TCB component (0–255); SEV-SNP evidence only, a policy error against TDX evidence
--min-tcb-snpuint0Nominimum SNP firmware TCB component (0–255); SEV-SNP evidence only, a policy error against TDX evidence
--min-tcb-microcodeuint0Nominimum microcode TCB component (0–255); SEV-SNP evidence only, a policy error against TDX evidence
--expected-report-datastring""Nohex REPORTDATA / TPM-nonce anchor override for bare evidence files (1–64 bytes, exactly as bound by the producer); refused in --mode attest-pq and attest-lb
-o, --outputstringtextNooutput format: text or json
--show-evidenceboolfalseNoprint the raw report fields
--pin-policystring slicenilNoaccepted sha256:<hex> policy digests; every replayed digest and the leaf's issuing policy must be accepted. Requires --operator-pkey or an image policy with approver_key; excludes --trust-operator; proving the leaf stamp requires --mesh-ca
--trust-operatorboolfalseNoaccept history and issuing policies only after fetching, re-hashing, and checking their signed write tokens against --trust-operator-keys; excludes --pin-policy, requires an approver-key replay anchor; seed/noncanonical policies may be unsigned
--trust-operator-keysstring""ConditionalPEM public-key bundle file path for policy signatures; required with --trust-operator and refused without it. Separate from --operator-keys route/CDS checks
--fetch-allowlistsstring""Nosave digest-checked replayed policy documents as <hex>.json in this directory; failed fetch/write fails verification. Requires --operator-pkey or an image policy with approver_key

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, a responder-chosen chain anchor, or unjudged policy history). Policy measurement is optional and TDX-only; the stock baked image disables it, so its policy-history verification is not guaranteed. --pin-policy and --trust-operator fail when replayed history is absent. Certificate, discovery, or offline history alone is at best partial even after policy checks; fresh nonce-bound attest-pq or attest-lb evidence is needed to establish current history. History objects have bounded retention.

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; one policy document cannot mix the two platforms.

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.

derive takes one or more <image-dir|manifest.json> arguments. lint <measurements.json> checks a config for problems and takes no flags.

derive flags:

FlagTypeDefaultRequiredDescription
--teestring""Noplatform to derive for, sev-snp or tdx; required when an image is built for both
--outstring""Nowrite the config to this path instead of stdout

c8s get-cert

Obtain a CDS-signed certificate over RA-TLS using a fresh ECDSA P-256 private key per issuance. The chain, key and CA form one validated generation on the private credential volume. Resolve current once and read its directory for a coherent generation; stable file paths are replaced individually. All three output paths are required and must share a directory. Workload claims are enabled by default. Select exactly one of --san, --san-file, or --no-san.

Renewal follows CA certificate renewal under the same key. A replacement CA key requires pod recreation because each pod binds its issuer key for its lifetime. Private credentials are for platform consumers; ordinary applications use their injected mesh endpoint.

FlagTypeDefaultRequiredDescription
--ca-watch-intervalduration1mNoin renewal mode, poll CDS for same-key CA certificate or policy changes and renew; otherwise defaults off. 0 disables, positive values must be at least 1s. Replacement CA keys require pod recreation
--cds-urlstring""ConditionalHTTPS CDS base URL; required unless the node mounts its endpoint. An explicit URL is refused when the endpoint is mounted
--image-policy-filestring""Conditionalcomplete CDS image and launch-file pin; required unless the node supplies pins; excludes --image-policy-json and node-mounted pin overrides
--image-policy-jsonstring""Noinline complete JSON image policy, in the same format as --image-policy-file; only one of the two may be set
--attestation-api-urlstring""YesURL of the node-local attestation-api (e.g. http://localhost:8400, or unix:// plus the on-node socket path the chart wires). A literal $(NODE_IP) is replaced by the address in /run/c8s/node-ip and $(HOST_IP) by the HOST_IP environment variable; startup fails when that source is missing or not an IP address
--sanstring""One of threecertificate IP or RFC 1123 DNS SAN; wildcards refused; select this, --san-file, or --no-san
--san-filestring""One of threefile holding the certificate SAN; mutually exclusive with --san and --no-san
-v, --verboseboolfalseNoenable debug logging
--renew-intervalduration0Nore-obtain the certificate at this interval (0 = run once and exit)
--renew-jitter-percentint20Noshorten 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-intervalduration30sNowith workload claims and --renew-interval, renew while the installed leaf carries no matched-workload stamp, at most this far apart (plus jitter), starting at 2s and doubling; settles to --renew-interval once named. Poll timing never changes the match decision. 0 disables the fast poll
--expected-workloadstring""Noallowlist entry this pod should be stamped with; requires workload claims and --renew-interval. A leaf stamped with any other name stays on the --unnamed-renew-interval fast poll instead of settling. Issuance never fails on a mismatch (empty = any stamp settles)
--initial-retry-timeoutduration2mNoretry 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-intervalduration2sNoinitial request retry delay; CDS/inventory 403 and CDS 429 back off with jitter, doubling up to 5m
--continue-on-initial-errorboolfalseNoin renewal mode, keep running when the first certificate request fails, retrying on a capped backoff until a certificate is issued; requires --renew-interval
--discovery-outstring""Nopath to write JSON discovery metadata for the issued certificate and attestation evidence
--discovery-cds-cert-urlstring""Nopublic URL path where the CDS certificate PEM is served
--discovery-mesh-ca-urlstring""Nopublic URL path where the mesh CA PEM is served
--discovery-public-tls-modestringcdsNopublic TLS mode to report in discovery metadata: cds, webpki, or acme
--discovery-public-tls-mode-filestring""Nofile holding the public TLS mode to report, read at start; replaces --discovery-public-tls-mode
--discovery-public-tls-hostnames-filestring""Nofile holding launch-selected public hostnames; discovery reports the first one without changing the certificate SAN
--workload-claims-timeoutduration5sNotimeout for the admission inventory request
--cert-pathstring""Yespublished certificate chain PEM; same directory as the other credential paths
--key-pathstring""Yespublished private key PEM, mode 0600 (0640 in a shared setgid directory); memory-backed filesystem required; same directory as the other credential paths
--ca-pathstring""Yespublished mesh CA PEM; same directory as the other credential paths
--no-sanboolfalseOne of threerequest no SAN for an unnamed pod; CDS derives the subject from verified workload identity
--no-workload-claimsboolfalseNodisable the default sandbox-token assertion for a node without an inventory; the leaf then has no workload instance binding. Injected workloads retain claims
--measured-policies-filestring/run/c8s/workload-claims/measured-policiesNomounted node TDX policy journal listed in CSR and attestation requests; empty lists none

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 is lost with singleton restart or total replica memory loss. Publication replaces each file atomically, not the whole set. A 404 can mean a denied read or missing value; secrets explain diagnoses release, and secrets put or escrow restore supplies operator values. After writing, the process idles until the pod is torn down. See Secrets.

FlagTypeDefaultRequiredDescription
--cds-urlstring""ConditionalHTTPS CDS base URL; required unless the node mounts its endpoint. An explicit URL is refused when the endpoint is mounted
--attestation-api-urlstring""Yesresolved local HTTP(S) attestation API URL or unix:// plus an absolute socket path, used to verify CDS; the CLI does not expand $(NODE_IP) or $(HOST_IP)
--image-policy-filestring""Conditionalcomplete CDS image and launch-file pin; required unless the node supplies pins; excludes --image-policy-json and node-mounted pin overrides
--image-policy-jsonstring""Noinline complete JSON image policy, in the same format as --image-policy-file; only one of the two may be set
--certstring/run/c8s/certs/tls.crtNothe pod's CDS-issued certificate, presented to CDS
--keystring/run/c8s/certs/tls.keyNoprivate key for --cert
--secretstring slicenilYesNAME=/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-dirstring/run/c8s/secretsNodirectory the secret files are written to; must be memory-backed
--file-modestring0640Nooctal mode for the written files
--attemptsint0Nomaximum attempts; 0 retries without limit, negative values refused; release waits for all main containers to run
--retry-intervalduration5sNoinitial retry delay, doubles to 30s; an explicitly larger interval stays constant; must be positive
--request-timeoutduration10sNoper-request timeout against CDS; must be positive
--inventory-timeoutduration5sNotimeout 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. The node agent's socket directory is compiled in (/run/c8s/workload-claims), so a pod cannot point the key handoff elsewhere. Linux only — the subcommand is registered only in Linux builds of the CLI. See Volumes.

FlagTypeDefaultRequiredDescription
--cds-urlstring""ConditionalHTTPS CDS base URL; required unless the node mounts its endpoint. An explicit URL is refused when the endpoint is mounted
--attestation-api-urlstring""Yesresolved local HTTP(S) attestation API URL or unix:// plus an absolute socket path, used to verify CDS; the CLI does not expand $(NODE_IP) or $(HOST_IP)
--image-policy-filestring""Conditionalcomplete CDS image and launch-file pin; required unless the node supplies pins; excludes --image-policy-json and node-mounted pin overrides
--image-policy-jsonstring""Noinline complete JSON image policy, in the same format as --image-policy-file; only one of the two may be set
--certstring/run/c8s/certs/tls.crtNothe pod's CDS-issued certificate, presented to CDS
--keystring/run/c8s/certs/tls.keyNoprivate key for --cert
--volumestring slicenilYesNAME=/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
--attemptsint0Nomaximum attempts; 0 retries without limit, negative values refused; release waits for all main containers to run
--retry-intervalduration5sNoinitial retry delay, doubles to 30s; an explicitly larger interval stays constant; must be positive
--request-timeoutduration10sNoper-request timeout against CDS and the node agent; must be positive
--inventory-timeoutduration5sNotimeout 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. CDS checks release grants; volumed checks the key blob and target. Writer exclusion is node-local. Verity authenticates immutable content, not freshness; mutable dm-crypt provides neither integrity nor rollback protection.

FlagTypeDefaultRequiredDescription
--socket-dirstring""Yeshost 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
--kubelet-rootstring/var/lib/kubeletNokubelet's root directory, holding per-pod volume directories
--cgroup-rootstring/sys/fs/cgroupNocgroup mount, where a pod's slice going away is what triggers teardown
--reap-intervalduration15sNohow often to tear down volumes whose pod has gone; must be positive
--max-mountsint64Nomaximum volumes open on this node 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. The same key may instead request a log-reader certificate (pods and their logs, nothing else) to hand on to someone who should not hold the operator role. Authorization is the cluster's RBAC on the issued group: the C8s node image bakes ClusterRoleBindings for the default --cert-org and --log-cert-org; elsewhere, create them or pass groups the cluster already binds. 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 seeds RTMR[3] as SHA-384(0x00*48 ‖ SHA-384(pubkey)), followed by the measured-policy journal replay, checked against 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.

FlagTypeDefaultRequiredDescription
--listenstring:8443NoHTTPS (RA-TLS) bind address
--attestation-api-urlstringhttp://127.0.0.1:8400Nolocal attestation-api base URL: the source of the RA-TLS serving cert's quote and, on SEV-SNP, of the verified HOSTDATA self-report
--platformstring""YesTEE platform: tdx or snp; selects the operator-key binding checked at startup
--client-ca-certstring/var/lib/rancher/rke2/server/tls/client-ca.crtNocluster client-CA cert that signs kube client certs
--client-ca-keystring/var/lib/rancher/rke2/server/tls/client-ca.keyNocluster client-CA key
--server-ca-certstring/var/lib/rancher/rke2/server/tls/server-ca.crtNoCA that signs the apiserver serving cert; embedded in the released kubeconfig
--cert-ttlduration168hNolifetime of issued operator certs
--cert-orgstringc8s:node-operatorsNoKubernetes group (cert Subject O) for the issued operator cert; the node image binds the default to the baked, bounded c8s-node-operator ClusterRole
--cert-cnstringoperatorNoKubernetes user (cert Subject CN) for the issued cert
--log-cert-ttlduration168hNolifetime of issued log-reader certs
--log-cert-orgstringc8s:log-readersNoKubernetes group (cert Subject O) for log-reader certs; the node image binds the default to the baked c8s-log-reader ClusterRole
--log-cert-cnstringlog-readerNoKubernetes user (cert Subject CN) for log-reader certs
--measured-policies-filestring/run/nri-image-policy/measured-policiesNoTDX allowlist policy journal replayed after the operator-key seed during the binding check; empty replays none

c8s get-kubeconfig

Obtain an operator or log-reader 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] replay from the operator-key seed, measured-policy history and any explicitly expected --workload-image digest extensions. Fresh response runtime extensions feed replay; 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. New --out files are created with mode 0600; existing files are overwritten with their permissions preserved. Verification runs in-process with attestation-go, including the RA-TLS check on the cred-release dial; fresh attestation is operator-authenticated over the cred-release endpoint, so the guest's raw attester can stay on loopback. Requires --operator-key, --image-manifest, and --out, plus either --node, --vmi, or both --release-url and --apiserver-url.

FlagTypeDefaultRequiredDescription
--nodestring""Noguest host/IP that fills --release-url and --apiserver-url with the standard ports (8443/6443); each explicit URL flag overrides it. Mutually exclusive with --vmi
--vmistring""Noguest 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-urlstring""Nooptional legacy attestation-api /attest URL; by default attestation runs operator-authenticated over --release-url
--release-urlstring""Nocred-release base URL
--apiserver-urlstring""Noapiserver URL written into the kubeconfig
--operator-keystring""Yesoperator ECDSA private-key PEM file path; 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-manifeststring""Yesprovenanced 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-imagestring arraynilNodigest-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
--contextstringc8sNokubeconfig cluster/context/user name
--tls-server-namestringc8s-cvmNokubeconfig 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
--outstring""Yeskubeconfig output path; new files are created 0600, existing files are overwritten with their permissions preserved
--rolestringoperatorNoidentity the released cert carries: operator (tenant workloads cluster-wide, bounded so it cannot reach the node's guards) or log-reader (pods and their logs only)
--timeoutduration30sNoper-step network timeout
--release-waitduration2mNohow long to retry refused connections to cred-release during attestation and credential release; 0 fails on the first refused dial

c8s keys

Manage the operator EC keypair (P-256). The private key signs allowlist, secret, volume and route writes, and authenticates c8s get-kubeconfig; CDS pins its operator public keys in its measured launch configuration. Helm operator keys configure router verification. Changing CDS authority requires a new measured configuration and pin; HA rotate-key changes the mesh CA key only.

SubcommandArgumentsPurpose
new—generate an operator keypair; neither file is ever overwritten, and the private key is written 0600
sign-launch<launch.yaml>sign a launch configuration, writing the detached signature to <launch.yaml>.sig beside it
FlagTypeDefaultRequiredDescription
--outstring""Yesnew only: private key output path
--pub-outstring""Yesnew only: public key output path
--keystring""Yessign-launch only: operator private-key PEM file path (c8s keys new --out)
--forceboolfalseNosign-launch only: replace an existing signature, after editing the document

c8s launch-config

Create, extend and stage a measured node's signed c8s-launch/v2 configuration. c8s node launch-config is the same command. Node documents reject workloads; the generator uses --tenant-workloads for CDS policy. Signed node fields include registry mirrors, optional nodePassword, and router body limits. See the node CVM launch contract.

SubcommandPurpose
newcreate a cluster's launch bundle: launch keys, fresh RKE2 join tokens, a signed launch.yaml per node, and the client policy that pins the server
add-agentderive an agent launch.yaml from the bundle's server document, sign it with the bundle's agent key, and write <bundle>/<name>; nothing the server booted with changes
stageon the guest: verify the signed launch configuration and stage the selected node role

new writes:

PathContent
<out>/server.keygenerated server/operator key; omitted when --operator-key supplies an existing key
<out>/cds-config.yamlmeasured configuration the external CDS boots
<out>/cds-pin.jsonCDS image and exact configuration pin, independent of server/peer node policies
<out>/agent.keyagent launch key; add-agent reuses it
<out>/server.jsonimage policy pinning the server node; distinct from the CDS identity pin
<out>/peers.jsonsingleton node policy and default HA Genesis node set; use the independently intended current policy for c8s cds verify --served-policy-file
<out>/server/pubkey, launch.yaml, launch.yaml.sig: the server's opkeydata
<out>/<agent>/the same three files for each --agent

Attach each node directory as its opkeydata disk: an ISO with volume label opkeydata, or a KubeVirt Secret volume with volumeLabel: opkeydata. On SEV-SNP, also set HOST_DATA to the SHA-256 of that node's pubkey file.

FlagTypeDefaultRequiredDescription
--outstring""Yesnew only: bundle directory to create; must not exist
--cluster-idstring""Yesnew only: cluster name, an RFC 1123 label
--image-manifeststring""Yesnew only: manifest.json published with the exact node image to boot
--vcpusint0Conditionalnew: SNP node vCPU count; required if the manifest contains multiple SNP variants, otherwise selects its sole variant; refused for TDX
--server-namestring""Nonew only: server node name; empty selects <cluster-id>-server
--server-addressstring""Conditionalnew: server IPv4 address every node can reach; required with agents, otherwise the server autodetects it. add-agent: defaults to the server document's, which must then be explicit
--agentstring arraynilNonew only: agent node name; repeatable
--tls-sanstring""Nonew only: DNS name for the front-door certificate; empty selects c8s.local
--router-hostnamestring arraynilNonew only: public DNS name the router serves with an ACME certificate; repeatable
--acme-emailstring""Nonew only: contact email for the router's ACME account; requires --router-hostname
--acme-directory-urlstring""Nonew only: ACME directory URL, e.g. a staging directory for tests; requires --router-hostname (default Let's Encrypt)
--bundlestring""Yesadd-agent only: bundle directory created by launch-config new
--namestring""Yesadd-agent only: agent node name, an RFC 1123 label
--configstring""Yesstage only: signed launch.yaml
--signaturestring""Yesstage only: detached launch.yaml.sig
--platformstring""Yesstage only: image TEE platform, tdx or snp
--attestation-api-urlstringhttp://127.0.0.1:8400Nostage only: trusted node-local attestation API
--tenant-workloadsstring""Nonew: tenant allowlist JSON merged into the CDS component seed; component-name collisions refused
--cds-addressstring""Yesnew: external CDS <host>:<port> (DNS or IPv4)
--cds-image-manifeststring""Yesnew: exact CDS guest image manifest
--cds-platformstring""Yesnew: CDS platform sev-snp or tdx, independent of node platform
--cds-vcpusint slicenilConditionalnew: SEV-SNP CDS CPU counts, at least one for SNP; repeatable
--cds-node-cidrstring arraynilYesnew: node inventory subnets the CDS may dial; repeatable
--cds-allowlist-seedstring""Yesnew: release-matched allowlist-seed-<platform>.json component policy
--cds-replicastring arraynilConditionalnew: HA DNS names or IPv4 addresses, no port or load-balanced address; repeatable; requires --cds-voters
--cds-votersint0Conditionalnew: odd initial HA voter seats, 1–9; requires replicas; omit both HA inputs for singleton
--registry-mirrorstring arraynilNonew: signed registry=http://ipv4[:port] mirror mappings; one per registry, repeatable
--router-max-request-body-bytesint640Nonew: signed ordinary nginx-routed HTTP body limit; 0 selects 1048576 bytes, positive values override; oversize requests return 413. Decoded tunnel requests bypass this limit; encoded sealed records have an 8 MiB cap including overhead, and backends may impose limits
--operator-keystring""Nonew: existing P-256 private-key PEM file path used as server/operator key; not copied into the bundle
--operator-pubkeystring""Nonew: public-key PEM file path; its bytes must equal the public key derived from --operator-key, which is required
--pin-decreestring""Noadd-agent: checked signed CDS pin decree; embeds its images and the floor max(base_version, resume_version), not its resulting applied version
--measured-policies-filestring/run/nri-image-policy/measured-policiesNostage: TDX policy journal for operator-key binding replay; empty replays none

c8s node-image

Build measured node-image integration artifacts at image build time. node-services (prepare, node-ip) is its in-guest counterpart: baked units that prepare the image's authenticated bootstrap inputs, with no flags.

SubcommandPurpose
renderrender the bundled chart as complete Kubernetes manifests for the node image; needs Helm at build time, and none in the guest. Authenticated launch settings are mounted read-only from /run/c8s-node at boot
check-imagesread the config of every image render listed from its preloaded OCI layout, and check that the bootstrap seed admits each baked container's complete launch environment; run it before the image is sealed
FlagTypeDefaultRequiredDescription
--output-dirstring""Yesrender: directory for c8s-integration.yaml, allowlist-seed.json, images.txt and router-nginx/; check-images: the directory render wrote
--hardware-platformstring""Yesrender only: CPU TEE, tdx or sev-snp
--kube-versionstring""Yesrender only: Kubernetes semantic version of the baked RKE2 release
--chart-dirstring""Norender only: chart source directory; empty uses the chart bundled in this binary
--image-digeststring""Yesrender only: digest of the operator/get-cert image (sha256:...)
--image-repositorystring""Norender only: operator/get-cert repository; empty uses the chart default
--armtls-mesh-image-digeststring""Yesrender only: digest of the mesh image
--armtls-mesh-image-repositorystring""Norender only: mesh repository; empty uses the chart default
--router-image-digeststring""Norender only: digest of the nginx image; empty uses the pinned chart default
--router-image-repositorystring""Norender only: nginx repository; empty uses the chart default
--layoutsstring""Yescheck-images only: directory holding each image's OCI layout as oci-<sha256 hex>

c8s armtls-mesh

Run one pod's injected TCP mesh endpoint. Applications serve ordinary TCP/HTTP inside the pod; the endpoint handles TLS 1.3 using a CDS-issued chain, purpose, ALPN and sandbox identity. It performs certificate validation, not hardware attestation on each connection, and supplies no generic destination-workload ACL. Covered pods are injected whether or not they have a cw name; the name expresses workload/service intent.

Credentials stay on the platform's private volume at /etc/c8s/certs in injected pods. Nonempty credential path/volume overrides and application credential mounts are refused by injection.

FlagTypeDefaultRequiredDescription
--cert-pathstring""YesCDS-issued pod certificate chain PEM
--key-pathstring""Yesmatching private key PEM
--ca-pathstring""Yesissuing mesh CA PEM; all credential paths share one directory

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.

FlagTypeDefaultRequiredDescription
--configstring/etc/nri/conf.d/image-policy.yamlNopath to config file
--health-addrstring:8080Nohealth check listen address
--read-timeoutduration5sNoHTTP server read timeout
--write-timeoutduration10sNoHTTP 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 check rejects directories and zero-length files; a nonempty file can still be incomplete.

FlagTypeDefaultRequiredDescription
--waitboolfalseNoblock until <path> passes the check instead of probing once
--poll-intervalduration1sNohow often to re-check <path> in --wait mode
--timeoutduration0Nogive up (non-zero exit) after this long in --wait mode; 0 waits forever