A ctlplne studio product

CLI

trstctl-cli is a command-line interface at parity with the REST API, built for scripts and CI: machine-readable JSON output and a CI-friendly API token. The CLI itself is table-driven — one row in internal/cli/command.go per API operation, proven complete by a parity test against the route table. This reference page, however, is maintained by hand, not generated; treat internal/cli/command.go as the ground truth if the two ever disagree.

The running control plane also publishes its full OpenAPI 3.1 specification at /api/v1/openapi.json — fetch it to generate clients or import the API into your tooling.

Prefer a typed library? trstctl ships supported client SDKs for Go and TypeScript (with auth, Idempotency-Key, cursor iterators, problem+json errors, and retries) pinned to that same served contract. See Client SDKs.

Prefer infrastructure-as-code? trstctl also ships terraform-provider-trstctl for certificate profiles, short-lived PKI credentials, and application secrets, backed by the same served OpenAPI routes.

Every command documented below is trstctl-cli. The trstctl server binary is a separate program with four admin command families of its own — token create (see "Bootstrapping the first API token" below), connector target ..., ssh ..., and the offline support-bundle — for direct calls against a running control plane, using their own --flag arguments and TRSTCTL_URL rather than the -f <file> bodies and TRSTCTL_SERVER used everywhere else on this page. Those direct operational commands also honor TRSTCTL_CA_FILE; set it to the inspected public CA or self-signed public certificate for a private/self-hosted control plane. They do not provide an option that disables TLS verification. A private control-plane hostname may additionally need a narrow comma-separated TRSTCTL_EGRESS_ALLOW_PRIVATE_CIDRS value (for example, the one internal subnet that owns it); localhost needs no exception, and metadata/link-local ranges stay blocked.

The exception is trstctl support-bundle: it deliberately does not require a running HTTP server. Use trstctl support-bundle --output support.tar.gz --log-file <local-log> during cold-start failures. The archive is bounded, contains posture and aggregate counts instead of raw configuration, and refuses residual secret/PII data after redaction. It stays offline by default. --include-enrollment-diagnostics is the explicit exception: it requires TRSTCTL_URL and TRSTCTL_TOKEN, fetches the authorized aggregate-only addendum, and still excludes tenant, operation, identity, endpoint, diagnostic, and timestamp references.

Global flags

Every command accepts these, each with a TRSTCTL_* environment fallback:

Flag Env Meaning
--server TRSTCTL_SERVER Base URL of the control plane.
--token TRSTCTL_TOKEN API token, sent as Authorization: Bearer.
--tenant TRSTCTL_TENANT Tenant id (X-Tenant-ID) for header/dev auth.
--ca-file TRSTCTL_CA_FILE PEM CA bundle used to verify the control plane.
--idempotency-key TRSTCTL_IDEMPOTENCY_KEY Stable key for safe retries; generated per call if unset.

A trstctl API token carries its own tenant and scopes, so with --token you usually need nothing else. Mutations always send an Idempotency-Key so a retried command can never execute twice.

Ordinary API calls have a 30-second client deadline. Direct subject erasure and retention enforcement automatically use a 10-minute deadline because they may perform a synchronous, crash-recoverable event-history rewrite on a large tenant. If either command is interrupted, retry it with the same explicit --idempotency-key; do not assume a client timeout means the server rolled back.

For an evaluation server using its self-signed internal certificate, point --ca-file at the public certificate you inspected and chose to trust. Internal mode persists its private identity in data/tls/internal-server.pem, so a normal restart with the same data volume keeps that pin valid. Never copy that combined private state file to a client; capture only the public certificate from the TLS endpoint. A missing data volume is a new identity and must be inspected again. Production deployments should use the operator-managed CA bundle for server.tls.mode=file. The CLI deliberately has no switch that disables certificate verification.

Output and exit codes

Responses are pretty-printed JSON on stdout. Exit code is 0 on success, 1 on a request/response error (the status is written to stderr), and 2 on a usage error — scriptable end to end.

Verify audit exports offline

Search and export accept the same optional filters: --tool, --feature_id, --action, --type, --since, --until, --as_of, --q, --window, and --limit. The server intersects filters, then selects the earliest (default) or latest matching events before applying the limit. --tool accepts discover, certificates, workloads_machines, secrets, software_trust, operations, or the supporting platform_integrations area. Omit it for the whole tenant stream; an unknown tool is an error, not an unfiltered result. Shared lifecycle records can appear in more than one tool without creating another audit stream.

GET /api/v1/audit/events also returns archived_prefix when this tenant has a sealed retention boundary. Its record_count and chain_head come from the same pinned history view as the returned events. An empty events array can therefore coexist with older signed archive records. The API intentionally does not return archive files or their host paths: request the JWS files from the archive custodian and verify each with pinned audit JWKS and trstctl-cli audit verify --format retention-jws. A missing archived_prefix means no sealed boundary was observed in this read, not that the tenant never had activity.

trstctl-cli audit events --tool workloads_machines --limit 100
trstctl-cli audit events --window latest --limit 50
trstctl-cli audit export --tool workloads_machines --as_of 120 --limit 100 --format ndjson > workload-audit.ndjson

Here --as_of 120 means “up to tenant-local event sequence 120,” not the newest 120 events. A retained export carries its archived-prefix hash so the verifier can check the surviving chain. A tool filter never overrides tenant permissions, privacy redaction or the configured retention window. Signed exports selected with --window latest carry that selector inside the signed query. Verify them with the CLI from this release or newer; older strict offline verifiers reject the added selector even when the signature is valid.

trstctl-cli audit verify is a local command: it opens no HTTP connection and does not need TRSTCTL_SERVER, a token, or a running control plane. It verifies the canonical JWS envelope and the exact CSV, NDJSON, Splunk HEC (splunk-hec), and Microsoft Sentinel (sentinel) record-stream shapes served by audit export. It also verifies signed retention archive files with explicit --format retention-jws; these files are a different signer domain from interactive exports, so automatic format detection never treats one as the other.

A JWS export accepts at most 512 KiB of serialized audit payload. Larger queries return HTTP 413 with code audit_export_too_large. Choose --format ndjson to export the same range with its chain and timestamp trailer, or reduce the time range or record limit. The product never silently truncates the requested JWS range or changes its format. Pin TSA trust for an independently verifiable record stream, as described below.

Bootstrap trust before disconnecting from the deployment. A plain signed JWS export needs the separately authenticated audit public key. An export with an external timestamp also needs the TSA root from a trusted channel:

# This authenticated read returns only the current audit signer's public RSA JWK.
trstctl-cli audit verification-keys > audit.jwks.json

# For timestamp verification, obtain this out of band from the PKI operator.
# Use the root CA that
# issued the configured TSA certificate, not the TSA leaf carried by an export.
cp /trusted/pki/trstctl-tsa-root.pem tsa-root.pem

Pin the applicable files in the auditor's trust inventory. The verification command never trusts a JWK, TSA root, or replacement authority supplied only by the saved artifact: an attacker who can replace evidence could replace embedded trust too. The TSA root may be PEM or DER. The JWK set is required for jws; record-stream formats rely on the hash chain plus the separately trusted RFC 3161 authority.

Verify a plain signed export without configuring an unrelated timestamp service:

trstctl-cli audit export --format jws > audit.jws.json
trstctl-cli audit verify --artifact audit.jws.json --audit-jwks audit.jwks.json

For an unanchored JWS, success reports audit_signature_verified: true and anchor_verified: false. It checks the signature, tenant scope, record count, record chain and signed head. It does not establish an independent time or prove that the selected export contains every tenant event. The verifier supplies its own anchor_detail; explanatory text carried by the file is not a trust input. The unsigned CSV/JSON record streams cannot use this signature-only path.

Verify an archived retention segment recovered from the configured archive directory with the separately pinned audit JWK set:

trstctl-cli audit verify --artifact audit-00000000000000000120.jws \
  --format retention-jws --audit-jwks audit.jwks.json \
  --expected-tenant <tenant-id>

# For the next segment, copy chain_head from the preceding verified receipt.
trstctl-cli audit verify --artifact audit-00000000000000000240.jws \
  --format retention-jws --audit-jwks audit.jwks.json \
  --expected-tenant <tenant-id> --previous-head <verified-prior-head>

The receipt identifies the tenant, first and last tenant-local sequences, record count, previous hash and signed chain head. It verifies the archive signature, record links, sequence continuity within the segment and tenant scope. To prove two segments connect, supply the preceding verified chain_head as --previous-head; independently keep the expected tenant and the ordered archive inventory. A single segment cannot prove that no earlier or later segment is missing. Retention archives carry no independent timestamp: the receipt reports anchor_verified: false, and timestamp-policy flags are rejected rather than silently reported as verified. Obtain a separately timestamped export when an external time assertion is required.

Use --require-anchor when your workflow requires timestamp evidence. Supplying --tsa-root or a positive --max-anchor-delay also requires an anchor. An explicitly provided empty or whitespace-only TSA root path is a configuration error. A present timestamp must verify under separately pinned TSA trust: a missing root, damaged token or wrong authority fails rather than falling back to signature-only success.

Download any served shape while the control plane is online, then verify it after the server is gone:

trstctl-cli audit export --format jws > audit.jws.json
trstctl-cli audit export --format csv > audit.csv
trstctl-cli audit export --format ndjson > audit.ndjson
trstctl-cli audit export --format splunk-hec > audit.splunk.ndjson
trstctl-cli audit export --format sentinel > audit.sentinel.ndjson

trstctl-cli audit verify \
  --artifact audit.jws.json \
  --format auto \
  --audit-jwks audit.jwks.json \
  --tsa-root tsa-root.pem \
  --require-anchor \
  --max-anchor-delay 24h

# A record stream does not use the audit JWK, but gets the same chain/TSA checks.
trstctl-cli audit verify --artifact audit.csv --format auto \
  --tsa-root tsa-root.pem --max-anchor-delay 24h

# Pipe a saved artifact instead of naming a file.
trstctl-cli audit verify --artifact - --format ndjson \
  --tsa-root tsa-root.pem < audit.ndjson

# Hold the continuous anchor series inside an unbroken run of records to an
# hourly cadence (Enterprise audit compliance with the TSA served).
trstctl-cli audit export --format ndjson --since 2026-10-01T00:00:00Z > audit.ndjson
trstctl-cli audit verify --artifact audit.ndjson --format ndjson \
  --tsa-root tsa-root.pem --anchor-cadence 1h

With --audit-jwks, the export's anchor log is checked too: its signed head and an inclusion proof for every anchor record, so an anchor cut from between two the export holds is refused. Keep the receipt's anchor_log.signed_head and pass it back on a later export:

jq -r .anchor_log.signed_head receipt.json > anchor-log-head.jws
trstctl-cli audit export --format ndjson --anchor_log_from 2 > later.ndjson
trstctl-cli audit verify --artifact later.ndjson --audit-jwks audit.jwks.json \
  --tsa-root tsa-root.pem --previous-anchor-log anchor-log-head.jws

anchor_log_from is the earlier head's tree_size; the export then proves the anchor log extends it.

Exports also carry the issuing CA's OCSP answer for every TSA certificate their timestamps rely on; the receipt's tsa_revocation lists each certificate's status. Fetch the CA's current CRL while connected and pass it with --tsa-crl to see revocations recorded after the export; --require-tsa-revocation refuses a TSA certificate whose status no evidence issued after its newest timestamp establishes:

curl -fsS "$TRSTCTL_SERVER/crl/<tenant>.crl" -o tsa-root.crl
trstctl-cli audit verify --artifact audit.ndjson --tsa-root tsa-root.pem \
  --tsa-crl tsa-root.crl --require-tsa-revocation

With --tsa-root, every audit.anchored record inside an unbroken run of records is re-checked and the receipt's anchor_series says how many anchors verified, how many cover only records before the window, and how many a later subject erasure superseded. --anchor-cadence also requires every record to be covered by an anchor within that cadence (plus --anchor-skew, five minutes by default); the newest records are covered by the export's own anchor. A run with a content filter (--type, --q, a tool or feature) is a chain of its own and cannot carry the series; a run selected only by time or sequence keeps the hashes its records have in the tenant's full chain, and its prev_hash is that chain's head just before its first record.

auto identifies only the five pinned served grammars; use an explicit format for an empty or otherwise ambiguous JSON stream. Verification starts from the trailer or signed bundle's prev_hash, so a live suffix after an archived prefix is checked as a continuation rather than incorrectly treated as a new genesis. It recomputes every record link and chain head, verifies the audit JWS domain where applicable, and, for anchored evidence, verifies the domain-separated RFC 3161 timestamp imprint and TSA chain. The outer anchor time must match the signed timestamp; different timezone offsets are accepted when they represent the same instant. Contradictory or missing outer times are rejected. It applies the optional maximum anchor delay from the newest record to authority time.

When a CMS timestamp artifact is present, verification checks its actual signature, the exact TSA signer, signed content type and certificate identifiers, and the TSTInfo imprint, policy, serial and time. Malformed, substituted or contradictory CMS fails; it never falls back to manifest-only verification. Historical tokens may omit CMS and retain their independently signed timestamp manifest. The historical encoder stores whole seconds in CMS while its signed manifest can retain nanoseconds; verification accepts only that exact precision mapping or an exact matching fractional CMS time, not a general time tolerance.

Success prints a non-secret JSON receipt with format, tenant when present, record count, archived-prefix hash, chain head, anchor kind/time, and newest-record time. audit_signature_verified identifies a verified JWS signature; anchor_verified identifies a verified timestamp. Record streams have no JWS signature and therefore report the former as false even when their timestamp verification succeeds. timestamp_artifact_verified separately identifies a verified CMS artifact. A legacy manifest-only token reports it as false and explains the missing artifact in anchor_detail; an unanchored result reports both timestamp flags as false. These receipts do not establish TSA revocation status or complete long-term validation evidence. Malformed input, duplicate authority fields, tamper, truncation, wrong trust, head mismatch, cross-tenant records, excessive input, or a delay-policy violation returns exit code 1 and writes a stable audit verification failed diagnostic to stderr. Invalid flags return exit code 2.

Commands

One row per command group — covering every core API operation — plus the local run wrapper for developer secret injection (kept in sync by hand, per the note above). Each row gives a one-line purpose plus representative verbs, not an exhaustive subcommand list:

Group Purpose (representative verbs)
access Tenant membership, custom roles, API tokens, JIT privileged-access sessions, and NHI access-change requests/reviews (roles · roles define · roles delete · oidc-mapping · members · tokens · sessions · requests · reviews)
acme ACME ARI publication/scheduler posture plus DNS-01 provider coverage, secret-referenced provider configs, and propagation/CAA/wildcard preflight (ari posture · dns-01 providers · dns-01 provider-configs · dns-01 preflight)
agents In-network agent inventory, enrollment tokens, cert revocation, offboarding (list · enroll-token · revoke-cert · offboard)
agent-delegation Core chain-bound agent credentials: register/list root anchors, issue, follow the issuance receipt to its credential ID, read credential/chain, revoke with --force, and inspect exact directive jobs/evidence. See agent delegation.
ai AI assistant status, question answering, root-cause analysis (status · query · rca)
approval-requests Review immutable certificate, secret, and managed-key operation requests within the caller's real permission domains (list · approve · deny)
archives Archive objects' S3 legal holds, set in the bucket and read back (legal-holds place · legal-holds release · legal-holds list)
audit Query/export the signed audit log, pin public verification keys, verify every saved format offline, and configure native collector feeds (events · export · verification-keys · anchors · verify · feeds set · feeds list)
breakglass Effect-free emergency-request preview, ceremony-gated online issuance, rotation, cross-signing, and offline-bundle reconciliation (issue-preview · issue-ceremony · issue · rotation-ceremony · rotate · cross-sign-ceremony · cross-sign · reconcile)
broker agent-identities Issue a policy-gated AI/MCP agent identity (issue)
ca ceremonies Effect-free review, start, inspect, approve, and reasoned cancellation of m-of-n CA key ceremonies (preview · start · get · approve · cancel)
ca authorities Private CA authority lifecycle — create/import roots and intermediates, preview/activate rotation, rekey, cross-sign, issue leaf certs (list · create-root · import-offline-root · import-existing · create-intermediate · rotate-preview · rotate · rekey · cross-sign · issue)
ca keys Read retirement dependencies, record a successor and host route for a certificate (reprotect plan), queue re-protection jobs (reprotect), and request irreversible signer-gated retirement (retirement · retire). A plan or enqueue receipt is not evidence that a credential was reissued or deployed.
ca discovery List public and private CA discovery inventory (list)
cbom Cryptographic bill of materials: effect-free plan review, bounded scan, inventory (preview · scan · assets)
pqc pilots Staged post-quantum handshake pilots with a canary halt and a signer-signed readiness report (create · list · get)
pqc campaigns Core PQC migration ownership and evidence workflow (create · list · get · update · readiness · disposition · close · evidence)
certificates Certificate inventory: ingest, list, get, health, bulk-revoke, recovery of a historical PKI-secret or managed CA leaf, recovery of a row's certificate bytes, device-bound key evidence and its offline check (ingest · list · get · health · bulk-revoke · inventory-pki-secret · inventory-managed-ca · recover-der · key-attestation · verify-key-attestation)
code-signing Review and sign artifact digests with a managed key or a keyless Sigstore/Fulcio identity (identities · preview · sign · keyless-preview · keyless)
compliance Compliance/inventory reporting, signed schedule runs, exact artifact download, recovery, and signed evidence-pack export (inventory-report · nhi-report · report-schedules preview/create/list/pause/resume/runs · report-runs get/download/requeue/verify/legal-hold/release-hold · report-signing-key · evidence-pack)
connector target Deployment connector targets: create, bind, test, deploy, roll back, exact host containment and its recovery check, material removal, verification address suggestions, and combined CA/host key-compromise response (create · list · get · update · delete · bind · test · deploy · rollback · contain-preview · contain · recovery-check · recovery-status · purge-preview · purge · verification-suggestions · confirm-verification-address)
connectors Connector catalog, outbox circuit-breaker state, delivery receipts (catalog · outbox-circuits · deliveries)
discovery Discovery segments, sources, schedules, runs, findings, coverage and the addresses seen outside every declared segment, CT monitoring, drift remediation, continuous monitoring (segments create · sources · schedules · runs · findings · coverage · coverage candidates · ct-monitoring · drift-remediation · monitoring)
editions Show edition, license, and FIPS posture (status)
ephemeral Approval-gated JIT credentials and reviewed short-TTL API keys (issue · api-keys preview · api-keys issue · approve)
endpoints Read live endpoint identity and key-custody evidence, including one exact signed verification (verifications · verifications get · key-custody)
enrollment diagnostics Read exact tenant refusal evidence, export aggregate-only support counts, and queue signed proof after a successful retry (list · support-addendum · prove-fixed)
external-cas List and issue through configured upstream CA integrations (list · issue)
graph Query the credential graph and operate its canonical crypto-readiness workflow (nodes · reachable · blast-radius · crypto-readiness · crypto-readiness actions create · crypto-readiness export · query)
identities Identity lifecycle: create, list, review an exact transition plan, execute it, approve dual-control actions, or bulk-revoke (create · list · get · issuance-result · issuance-retry · deployment-evidence · transition-preview · transition · compromise-preview · compromise · compromise-status · compromise-retry · approve · approve issue · approve rotate · approve revoke · bulk-revoke)
issuance-requests Preview and open a certificate request with an explicit CA, list requester-visible issuers, then track independent approval and signer-backed completion (issuers · preview · open · list · approve · deny · cancel · prepare · complete)
incidents executions Execute credential-compromise remediation and inspect evidence packs (execute · list · get)
incidents response-integrations Dispatch an incident packet to SIEM/SOAR/chat/ITSM integrations (dispatch)
incidents fleet-reissuance Exact-H1, signed-gate H2 compromised-issuer cohorts: effect-free prerequisite preview, start, list, get, pause, resume, current-cohort rollback, evidence (preview · start · list · get · pause · resume · rollback · evidence)
issuers Create, list, get certificate issuers (create · list · get)
itsm servicenow tickets Queue a ServiceNow ITSM ticket through the outbox (create)
kubernetes Native Kubernetes CertificateSigningRequest and trust-bundle distribution support (csr · trust-bundles)
lifecycle CA-explicit endpoint lifecycle review/execution and rotation-run history (endpoint-bindings preview · endpoint-bindings create · rotation-runs list · rotation-runs get)
managed-keys BYOK/HSM-resident key lifecycle and recovery: custody readiness, preview, generate, tenant-scoped paginated inventory, exact provider/handle and pending-operation reads, dual-control approve, rotate, revoke, zeroize (custody · preview · generate · list · get · operation · approve · rotate · revoke · zeroize)
managed-offering Managed-offering/provider-plane posture and hosted-tenant provisioning (status · tenants provision)
mcp List and invoke the MCP tools the server exposes (tools · call), or serve them to a standard MCP client over stdio (serve)
mdm MDM SCEP policy/challenge status and enrollment-policy management (scep status · scep policies)
migration Core PQC migration plans, issuance status, and selected-asset rollback (plan · start · status · rollback)
nhi Unified NHI inventory, posture findings, policy compliance, decommissioning (inventory · posture shadow/stale/overprivilege/static-credentials/exposure · policy compliance · decommission)
notifications Notification channels, exact effect-free routing-policy review, saved routing rules, inbox/dead-letter recovery (channels · routing-policies preview/create/list/get/update/delete · routing-preview · list · get · read · requeue)
operations Operational telemetry for the bounded worker pools that carry backpressure (bulkheads)
owners Owner CRUD, event-backed contextual/bulk assignment, application-model readiness, explicit attestation, expiring identity exceptions, and NHI attribution (create · list · get · update · delete · assign · attest · exceptions list/grant/revoke · attribution)
platform Show self-hostable run-anywhere distribution posture (distribution)
platform Running build, uptime, signer topology, and spine reachability (system)
platform Tenant cryptographic custody: status, migration into a tenant key domain, seal, unseal, and key rotation (tenant-key-domain status/migrate/seal/unseal/rotate)
platform Deployment KEK custody and rotation by the operator tenant (deployment-kek status/rotate)
policy Author, list, activate, and roll back lifecycle policy versions; dry-run a candidate module (versions create/list/activate/rollback · dry-run)
privacy Subject erasure, retention runs, archive-erasure attestations, export, personal-data catalog (erasures · retention · archives · export · catalog)
profiles Certificate profile versions and append-only recovery (create · list · get-version · restore-preview · restore)
remediation Automated remediation playbooks/runs and owner-driven self-remediation actions (playbooks · playbooks run · playbook-runs list/get · owner-actions list/accept)
reports Plain-language and prioritized reports: the customer assurance report in the tenant's brand and the cryptographic risk report (assurance · crypto-risk · crypto-risk export)
revocation Published CRLs, signed relay endpoint health, rogue-certificate findings, CT-log submission (crls · health · rogue-certificates · ct-submit)
risk Rank credentials by risk score, with blast-radius-aware prioritization (credentials · contextual-priorities)
run Local wrapper: run a child process with fetched secrets injected into its environment
scale High-volume orchestration and multi-region HA issuance posture (orchestration · ha-issuance)
secrets store Stored secrets: effect-free create review, then put, atomic import, list, get, history, recover, update, delete (preview · put · import · list · get · history · recover · update · delete). import -f FILE accepts private JSON with optional prefix and a values object of 1–100 new names; -f - reads standard input. The receipt contains names, versions and batch ID, not values.
secrets leases Dynamic secret leases: list safe provider setup/readiness, effect-free exact preview, then issue, get, renew, revoke (providers · preview · issue · get · renew · revoke)
secrets honeytokens Inert API bait credentials: plant with -f JSON (name, placement), list/get metadata, inspect first trigger, and revoke (plant · list · get · revoke). Mutations use Idempotency-Key; the bearer is revealed only in the plant response.
secrets honeytokens aws Operator-attached AWS IAM bait keys: list configured accounts, effect-free preview with -f JSON (account_id, name, placement, ttl_seconds), plant the same request with its optional preview_fingerprint, list/get monitoring evidence, rearm after triage, and retire (accounts · preview · plant · list · get · rearm · retire). The secret access key is revealed only in the plant response.
secrets rotations Effect-free exact review, then worker-owned connector rotation; static and dynamic provider modes fail closed before effects (preview · run)
secrets rotation-schedules Scheduled connector rotations with bounded durable due-run receipts (create · list · get · pause · resume · retire · run-due)
secrets syncs Push a stored secret to an external sync target, read its durable delivery, and reconcile a lost receiver result (preview · run · status · reconcile · targets)
secrets scans Gitleaks scanning: CI runs, repository/third-party webhooks, local pre-commit and staged-diff (run · repositories · repositories webhook · third-party · third-party ingest · staged-diff · pre-commit install)
secrets shares Review without sending the value, create with safe same-key recovery, and redeem a one-time share (preview · create · redeem)
secrets approvals Approve a pending secret-store change (approve)
secrets Machine-auth login methods, machine-login sessions, credential exchange, preview-bound dynamic PKI secrets, cloud/Kubernetes/workload integration status (auth-methods · sessions · login · pki preview · pki · cloud-secret-managers · kubernetes-operator · workload-injection · unvaulted)
setup Tenant-bound eval protocol profile status and activation (protocols status · protocols activate)
ssh SSH CA/KRL/attestation workflow status, trust rollout, exact effect-free previews, direct and attested issuance, safe unchanged-request recovery, revoke, adoption of a predecessor control plane's KRL, per-host KRL receipts, host retirement (fleet · status · trust-rollout · preview · issue · preview-attested-user · issue-attested-user · revoke · krl adopt · krl receipts · retire-host)
support Show enterprise support, SLA, and services posture (enterprise)
transit keys List safe metadata, inspect full version history, create, and rotate a tenant-scoped Transit key (list · versions · create · rotate)
transit Read effect-free restore/KMIP status or encrypt, decrypt, rewrap, HMAC, sign, and verify with a transit key (status · encrypt · decrypt · rewrap · hmac · sign · verify)
workloads Workload attester trust sources and attested X.509-SVID issuance (attester-trust-sources create/list/get/update/rotate/revoke/delete · attested-issuance)

Plus version. trstctl (the server binary) additionally serves token, connector, and ssh under its own conventions — see the callout above.

Review a notification route before saving it:

trstctl-cli notifications routing-policies preview -f routing-policy.json
trstctl-cli --idempotency-key notifications-payments-v1 \
  notifications routing-policies create -f routing-policy.json

The first command sends the exact unsaved rule to the server and returns a ready/blocked answer, normalized scope and channels, missing-channel blockers, recovery steps, verification steps, and a stable request fingerprint. It writes no event, saves no policy, queues no message, contacts no provider, and therefore does not accept an Idempotency-Key. If the JSON changes, review it again. Use notifications routing-preview after saving to explain which rule currently wins for one workspace, owner, asset, and severity. Create and update recheck current channel readiness, so disabling a channel after review makes the later save fail closed instead of installing a dead route.

Before creating a native-store value, ask the same server oracle used by the console to validate the exact name, owner, and transient value without writing it:

chmod 600 secret-create.json
# {"name":"app/payments/api","owner_id":"11111111-1111-4111-8111-111111111111","value":"..."}
trstctl-cli secrets store preview -f secret-create.json
trstctl-cli --idempotency-key secret-create-2026-09-01 secrets store put -f secret-create.json

preview returns a ready/blocked plan, zero-effect boundary, execution writes, recovery guidance, and a server-keyed request fingerprint. It never returns the secret value and does not take an Idempotency-Key, because it does not mutate state. Changing any input requires a new preview; put always rechecks current server authority and state.

Run with secrets

Review the exact access plan before wiring a secret into an application:

cat > secret-access.json <<'JSON'
{"name":"app/db/dsn","env_var":"DATABASE_URL","resolve":true}
JSON
trstctl-cli secrets access preview -f secret-access.json

secrets access preview calls the read-only POST /api/v1/secrets/access/preview operation. It returns the current version, least-privilege permission, exact run argument vector, HTTP path, TypeScript example, recovery and verification instructions, and a server-keyed request fingerprint. It returns no secret value, writes no state, makes no external call, and requires no Idempotency-Key. A missing secret or reference, reference cycle, or invalid environment variable returns a blocked plan or validation error instead of a runnable command.

trstctl-cli run fetches one or more stored secrets through the same served GET /api/v1/secrets/store/{name} path as secrets store get, then starts a child process with those values added to its environment. It is a wrapper, not a JSON API command: stdout, stderr, stdin, and the child's exit code are passed through.

Preview and issue a PKI certificate

Keep the private key beside the workload and put only its public CSR in the request:

chmod 600 pki-request.json
# {"csr_pem":"-----BEGIN CERTIFICATE REQUEST-----\n...","ttl_seconds":900}
trstctl-cli secrets pki preview -f pki-request.json
trstctl-cli --idempotency-key payments-pki-1 secrets pki -f pki-request.json

secrets pki preview uses the same subject, SAN, public-key strength, certificate rule, and TTL validator as issuance. It reports the issuing CA, custody boundary, revocation/audit prerequisites, exact effects, recovery, verification, Vault/OpenBao path, and a server-keyed fingerprint. It does not sign, write, enqueue, audit, or contact another service, so it intentionally sends no Idempotency-Key. Add that returned fingerprint as preview_fingerprint to bind automated execution to the reviewed tenant, principal, CA, CSR/name, profile, and TTL. The server returns 409 if that reviewed plan is stale.

trstctl-cli run --secret DB_PASSWORD=db/password -- env
trstctl-cli run --resolve --secret DATABASE_URL=app/db/dsn -- ./payments-api
  • --secret ENV=secret/path is repeatable. ENV must be a normal environment variable name, and secret/path may contain / path segments.
  • --resolve maps to ?resolve=true, so referenced values such as ${secret.app/db/password} expand only when the caller asks for it.
  • run uses TRSTCTL_TOKEN to fetch the requested secrets but does not pass that API bearer to the child. If the application needs its own credential, map a separately scoped stored secret to an environment variable explicitly.
  • trstctl never logs injected values and wipes its byte-backed fetched copies after the child exits. The operating-system environment is still a string boundary, so use this with trusted commands and avoid debug commands that print all env vars outside a test.
  • The web console’s /secrets/developer workspace requests this same server plan, invalidates it when an input or secret version changes, and shows only a name/version/fingerprint receipt after its real access test.

Secret-store approvals use the same m-of-n dual-control store as privileged issuance. A distinct approver records a pending secret change like this:

cat > approval.json <<'JSON'
{"action":"rotate"}
JSON
trstctl-cli --idempotency-key approve-db-password secrets approvals approve db/password -f approval.json

Identity approvals can be sent with either an explicit JSON body or the fixed-action aliases. The aliases post the same served approval route with the action body filled in:

trstctl-cli --idempotency-key approve-web-issue identities approve issue 11111111-1111-1111-1111-111111111111
trstctl-cli --idempotency-key approve-web-rotate identities approve rotate 11111111-1111-1111-1111-111111111111
trstctl-cli --idempotency-key approve-web-revoke identities approve revoke 11111111-1111-1111-1111-111111111111

The cross-resource review queue is permission-filtered: certs:issue can review certificate operations, secrets:write can review secret operations, and keys:approve can review managed-key operations. It does not grant a new standalone approval permission. The list command uses an opaque newest-first cursor, so callers can continue beyond the first page without skipping requests that share a timestamp:

trstctl-cli approval-requests list --status pending --limit 100
trstctl-cli approval-requests list --status pending --limit 100 --cursor '<next_cursor>'
trstctl-cli --idempotency-key approve-request-42 approval-requests approve <request-id> <sha256>
trstctl-cli --idempotency-key deny-request-42 approval-requests deny <request-id> <sha256> 'change window closed'

Approve and deny bind to the request's exact kind, action, resource, and intent digest. A denial is an immutable terminal decision on the request; it never revokes, retires, deletes, or otherwise mutates the target resource.

Access-change approvals

trstctl-cli access requests opens and decides NHI entitlement changes against PR, ticket, or CAB evidence. The create and decide commands are mutating API calls and send an Idempotency-Key; retrying the same key returns the original request or decision instead of recording a duplicate.

cat > access-request.json <<'JSON'
{
  "requested_action": "grant",
  "nhi_id": "github-app:prod-deployer",
  "nhi_kind": "oauth_app",
  "display_name": "Prod deployer GitHub App",
  "resource": "github:org/prod-infra",
  "entitlement": "repo:contents:write",
  "change_ref": "github:org/prod-infra#4821",
  "change_url": "https://github.com/org/prod-infra/pull/4821",
  "risk": "high",
  "required_approvals": 2,
  "reason": "Scoped deployment automation access",
  "evidence_refs": ["pull:4821/checks", "ticket:CAB-4821"]
}
JSON

trstctl-cli --idempotency-key access-4821-open access requests create -f access-request.json
trstctl-cli access requests list --status pending
trstctl-cli access requests get 77777777-7777-4777-8777-777777777777

cat > access-decision.json <<'JSON'
{
  "decision": "approved",
  "reason": "PR checks and CAB ticket match the requested entitlement.",
  "decision_evidence_refs": ["github-review:security-reviewer"]
}
JSON

trstctl-cli --idempotency-key access-4821-approval-1 access requests decide 77777777-7777-4777-8777-777777777777 -f access-decision.json

The requester cannot approve their own request, and the same approver cannot be counted twice. Any denial makes the request terminal; approvals move it to approved only after the required count is met. The server derives both identities from the caller's authenticated session. If a request includes requester_subject or a decision includes approver_subject, it must match that authenticated subject. Sign in as each distinct approver before recording their decision.

Ephemeral API keys

trstctl-cli ephemeral api-keys preview first asks the server to normalize and check one exact subject, permission set, and lifetime. This is a read-only POST: it mints no bearer, creates no idempotency row, appends no event, and calls no external system. It also refuses permission escalation—a caller can grant only scopes it already has.

The preview returns a server-keyed request_fingerprint. Put that value in the issue body. trstctl-cli ephemeral api-keys issue then fails closed if the tenant, caller, subject, scopes, or lifetime no longer match the review. The successful response prints the raw trst_... bearer once; the server stores only its one-way hash. The leaseworker records api_token.revoked after ttl_seconds.

cat > ephemeral-api-key.json <<'JSON'
{"subject":"ci-preview-deploy","scopes":["access:read"],"ttl_seconds":900}
JSON
trstctl-cli ephemeral api-keys preview -f ephemeral-api-key.json > ephemeral-api-key.preview.json

# Copy request_fingerprint from the preview into the exact reviewed body.
jq --slurpfile review ephemeral-api-key.preview.json \
  '. + {preview_fingerprint: $review[0].request_fingerprint}' \
  ephemeral-api-key.json > ephemeral-api-key.reviewed.json

# Keep this recovery key stable until the response is certain. Retrying this exact
# command recovers the original response instead of minting another bearer.
trstctl-cli --idempotency-key ci-preview-key ephemeral api-keys issue -f ephemeral-api-key.reviewed.json

Observe or revoke the key by id with access api-tokens list and access api-tokens revoke. For an access:read key, prove the bearer works by using it against a metadata-only access endpoint, then revoke it and prove the same bearer receives 401. Never place the raw bearer in a URL, log, screenshot, or committed file.

Bootstrapping or recovering a local API token

trstctl-cli authenticates with an API token, but a freshly deployed control plane has none and fails closed (every route 401s). Mint the first one with the server binary's local bootstrap verb, run inside the control-plane custody boundary. It writes straight to the datastore (no existing HTTP credential or network trust required) and prints a tenant-scoped token once:

trstctl token create --tenant <uuid> [--subject <name>] [--scopes a,b,c] [--tenant-name <label>]

For the shipped evaluation Compose stack, run that server binary inside the control-plane container so it reaches the Compose-only PostgreSQL service:

docker compose -f deploy/docker/docker-compose.yml exec -T trstctl \
  /usr/local/bin/trstctl token create --tenant <uuid> --subject <name>

Running an unconfigured host binary can bootstrap a different local datastore; it does not recover the Compose deployment.

  • --tenant (required) is the UUID the token is scoped to. If it is new, the tenant is registered through the event log. If it already exists, the command first proves that the read model points to the exact retained tenant.registered event; it does not rename or register the tenant again.
  • The default scope set provides capability discovery and routine first-run administration. It deliberately excludes certificate issuance (certs:issue) and separately delegated high-risk permissions — bootstrapping a credential never grants self-issue.
  • The raw trst_… token is printed once to stdout (only its hash is stored); save it immediately. Then export it as TRSTCTL_TOKEN for trstctl-cli.
  • Because this command can recover access without an existing HTTP token, run it only with direct PostgreSQL plus signer/audit custody on the control-plane host. Possession of the public server binary alone is not enough.

Examples

export TRSTCTL_SERVER=https://localhost:8443
export TRSTCTL_TOKEN=trst_...

# Read this tenant's ARI publication windows and scheduler-consumption evidence.
# The API token needs lifecycle:read; the command is read-only JSON output.
trstctl-cli acme ari posture

# Create an owner from a JSON body on stdin.
echo '{"kind":"workload","name":"payments"}' | trstctl-cli owners create -f -

# Show managed and discovered NHI attribution by human owner, team, vendor, or orphan state.
trstctl-cli owners attribution

# Decommission NHIs selected from departure, vendor-term, or inactivity signals.
trstctl-cli nhi decommission -f nhi-decommission.json --force

# List shadow, unmanaged, and unregistered NHI posture findings.
trstctl-cli nhi posture shadow

# List governed NHI policy violations for rotation, scope, geography, expiry, and purpose.
trstctl-cli nhi policy compliance

# Author, activate, list, and roll back lifecycle policy versions served by the mutation gate.
trstctl-cli policy versions create -f lifecycle-policy-version.json
trstctl-cli policy versions list
trstctl-cli policy versions activate <version-id> -f policy-activation.json
trstctl-cli policy versions rollback <version-id> -f policy-rollback.json

# List usage-backed NHI over-privilege findings and least-privilege recommendations.
trstctl-cli nhi posture overprivilege

# List stale, unused, orphaned, and dormant NHI posture findings.
trstctl-cli nhi posture stale

# List long-lived and static NHI credential posture findings.
trstctl-cli nhi posture static-credentials

# List internet-exposed and insecure-deployment NHI posture findings.
trstctl-cli nhi posture exposure

# Probe the exposed NHIs' public endpoints from a network relay; the exposure
# posture then shows what answered. An empty inventory_ids list probes every
# exposed record, most severe first, up to 50 endpoints.
trstctl-cli nhi posture exposure probe -f nhi-exposure-probe.json --force

# Show the automatic actions the tenant's nhi_posture rules ask for and the last automatic run of each.
trstctl-cli nhi posture automation

# Hand stale NHIs to a new accountable owner and notify them.
trstctl-cli nhi posture stale handoff -f nhi-handoff.json --force

# List and run automated remediation playbooks.
trstctl-cli remediation playbooks
trstctl-cli remediation playbooks run nhi-right-size -f right-size.json --force
trstctl-cli remediation playbook-runs list --playbook_id nhi-right-size
trstctl-cli remediation owner-actions list --owner_id 11111111-1111-1111-1111-111111111111
trstctl-cli remediation owner-actions accept right-size-aWRlbnRpdHkvMTEx -f accept-owner-action.json --force

# Dispatch one incident response packet to SIEM, SOAR, chat, and ITSM sinks.
trstctl-cli incidents response-integrations dispatch -f response-dispatch.json

# List the certificate inventory.
trstctl-cli certificates list --limit 50

# Show full, sharded, and delta CRL distribution artifacts for the tenant.
trstctl-cli revocation crls

# Show signed network-relay CRL and OCSP endpoint health evidence.
trstctl-cli revocation health

# Show signed per-segment relay-local CRL and OCSP cache freshness metadata.
# Cached protocol bytes and upstream locations remain inside the segment.
trstctl-cli revocation caches

# List rogue and non-compliant certificate posture findings.
trstctl-cli revocation rogue-certificates

# Queue a precertificate and final certificate for RFC 6962 CT log submission.
trstctl-cli revocation ct-submit -f ct-submission.json

# Show the regional HA reference model and write fences; qualify deployment separately.
trstctl-cli scale ha-issuance

# Start a root CA ceremony, collect two approvals, then create the root.
cat > root-ceremony.json <<'JSON'
{"operation":"create_root","threshold":2,"spec":{"common_name":"Example Root CA","ttl_seconds":315360000,"signature_algorithm":"ECDSA-P256","max_path_len":1,"permitted_dns_domains":["example.internal"]}}
JSON
# Preview is effect-free: it validates and fingerprints this exact body without
# creating a ceremony, key, certificate, event, or external request.
trstctl-cli ca ceremonies preview -f root-ceremony.json
trstctl-cli ca ceremonies start -f root-ceremony.json
# Run each approval with a distinct custodian token.
trstctl-cli ca ceremonies approve <ceremony-id>
trstctl-cli ca ceremonies approve <ceremony-id>

# If the reviewed work is withdrawn before the CA action consumes the ceremony:
# printf '{"reason":"change window closed"}\n' > cancel-ceremony.json
# trstctl-cli ca ceremonies cancel <ceremony-id> -f cancel-ceremony.json

cat > root-create.json <<'JSON'
{"ceremony_id":"<ceremony-id>","spec":{"common_name":"Example Root CA","ttl_seconds":315360000,"signature_algorithm":"ECDSA-P256","max_path_len":1,"permitted_dns_domains":["example.internal"]}}
JSON
trstctl-cli ca authorities create-root -f root-create.json

# A post-quantum pilot root beside it: the same ceremony with an ML-DSA key family.
cat > pq-root-ceremony.json <<'JSON'
{"operation":"create_root","threshold":2,"spec":{"common_name":"Example PQ Pilot Root","ttl_seconds":315360000,"signature_algorithm":"ml-dsa-65","max_path_len":1,"permitted_dns_domains":["example.internal"]}}
JSON
trstctl-cli ca ceremonies start -f pq-root-ceremony.json
# ... two approvals, then create-root with the same spec and ceremony_id.

# Import an offline root, generate a signer-held intermediate CSR, sign it offline,
# then import the signed intermediate.
cat > offline-root-ceremony.json <<'JSON'
{"operation":"import_offline_root","threshold":2,"certificate_pem":"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n","spec":{"common_name":"Example Offline Root CA","ttl_seconds":315360000,"signature_algorithm":"ECDSA-P256","max_path_len":1,"permitted_dns_domains":["example.internal"]}}
JSON
trstctl-cli ca ceremonies start -f offline-root-ceremony.json
trstctl-cli ca ceremonies approve <offline-root-ceremony-id>
trstctl-cli ca ceremonies approve <offline-root-ceremony-id>

cat > offline-root-import.json <<'JSON'
{"ceremony_id":"<offline-root-ceremony-id>","certificate_pem":"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n","spec":{"common_name":"Example Offline Root CA","ttl_seconds":315360000,"signature_algorithm":"ECDSA-P256","max_path_len":1,"permitted_dns_domains":["example.internal"]}}
JSON
trstctl-cli ca authorities import-offline-root -f offline-root-import.json

# Import an existing root/intermediate chain bound to a signer-held key handle.
# When the direct issuer is already registered in this tenant, pass its ID in
# BOTH the ceremony and import bodies. The server compares its certificate to
# the next certificate in the chain before recording the parent relationship.
cat > existing-ca-ceremony.json <<'JSON'
{"operation":"import_existing_ca","threshold":2,"parent_id":"<registered-direct-issuer-id>","certificate_pem":"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n","signer_handle":"customer-existing-ca","spec":{"common_name":"Example Imported Issuing CA","ttl_seconds":71280000,"signature_algorithm":"ECDSA-P256","max_path_len":0,"permitted_dns_domains":["example.internal"]}}
JSON
trstctl-cli ca ceremonies start -f existing-ca-ceremony.json
trstctl-cli ca ceremonies approve <existing-ca-ceremony-id>
trstctl-cli ca ceremonies approve <existing-ca-ceremony-id>

cat > existing-ca-import.json <<'JSON'
{"ceremony_id":"<existing-ca-ceremony-id>","parent_id":"<registered-direct-issuer-id>","certificate_pem":"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n","signer_handle":"customer-existing-ca","spec":{"common_name":"Example Imported Issuing CA","ttl_seconds":71280000,"signature_algorithm":"ECDSA-P256","max_path_len":0,"permitted_dns_domains":["example.internal"]}}
JSON
trstctl-cli ca authorities import-existing -f existing-ca-import.json

# Preferred path when the child CA key does not already exist in signer custody:
# pin the external issuer's public chain and child profile in one ceremony.
# Each custodian approves with their own authenticated CLI token.
cat > prepared-ca-ceremony.json <<'JSON'
{"operation":"prepare_existing_ca","threshold":2,"certificate_pem":"<issuer-first public chain PEM>","spec":{"common_name":"Example Imported Issuing CA","ttl_seconds":2592000,"signature_algorithm":"ECDSA-P256","max_path_len":0,"permitted_dns_domains":["example.internal"]}}
JSON
trstctl-cli ca ceremonies preview -f prepared-ca-ceremony.json
trstctl-cli ca ceremonies start -f prepared-ca-ceremony.json
trstctl-cli ca ceremonies approve <preparation-ceremony-id>
trstctl-cli ca ceremonies approve <preparation-ceremony-id>
cat > prepared-ca-csr.json <<'JSON'
{"ceremony_id":"<preparation-ceremony-id>","certificate_pem":"<same issuer-first public chain PEM>","spec":{"common_name":"Example Imported Issuing CA","ttl_seconds":2592000,"signature_algorithm":"ECDSA-P256","max_path_len":0,"permitted_dns_domains":["example.internal"]}}
JSON
trstctl-cli ca authorities prepare-import-csr -f prepared-ca-csr.json
trstctl-cli ca authorities get-import-csr <preparation-ceremony-id>
# Sign the returned public CSR on the external CA. Import the signed child
# certificate followed by the exact reviewed issuer chain; never submit a key.
cat > prepared-ca-import.json <<'JSON'
{"ceremony_id":"<preparation-ceremony-id>","certificate_pem":"<signed child PEM followed by reviewed issuer chain>","signer_handle":"<returned signer handle>","spec":{"common_name":"Example Imported Issuing CA","ttl_seconds":2592000,"signature_algorithm":"ECDSA-P256","max_path_len":0,"permitted_dns_domains":["example.internal"]}}
JSON
trstctl-cli ca authorities import-existing -f prepared-ca-import.json

# Import a CA together with its existing private key: two custodians approve
# the chain and profile, then the key is sealed on this machine and only the
# sealed key is sent. import.json holds ceremony_id, certificate_pem and spec.
cat > key-import-ceremony.json <<'JSON'
{"operation":"import_ca_key","threshold":2,"certificate_pem":"<imported CA first, then its issuer chain>","spec":{"common_name":"Example Imported Issuing CA","ttl_seconds":71280000,"signature_algorithm":"ECDSA-P256","max_path_len":0}}
JSON
trstctl-cli ca ceremonies start -f key-import-ceremony.json
trstctl-cli ca ceremonies approve <key-import-ceremony-id>
trstctl-cli ca ceremonies approve <key-import-ceremony-id>
trstctl-cli ca authorities key-offer -f import.json > offer.json
trstctl-cli ca authorities wrap-key --offer offer.json --key ca-key.p8.pem --request import.json --out import-sealed.json
trstctl-cli ca authorities import-key -f import-sealed.json

# Revoke a signer-backed authority's key: two custodians approve the exact
# authority and reason, then the revoke command executes it. Permanent.
cat > revoke-ceremony.json <<'JSON'
{"operation":"revoke_ca","authority_id":"<ca-authority-id>","reason":"key_compromise","threshold":2}
JSON
trstctl-cli ca ceremonies preview -f revoke-ceremony.json
trstctl-cli ca ceremonies start -f revoke-ceremony.json
trstctl-cli ca ceremonies approve <revoke-ceremony-id>
trstctl-cli ca ceremonies approve <revoke-ceremony-id>
cat > revoke.json <<'JSON'
{"ceremony_id":"<revoke-ceremony-id>","reason":"key_compromise"}
JSON
trstctl-cli ca authorities revoke <ca-authority-id> -f revoke.json

# Re-check a certificate's device-bound custody claim offline: fetch the
# evidence once, then verify it anywhere against TPM roots you choose.
trstctl-cli certificates key-attestation <certificate-id> > evidence.json
trstctl-cli certificates verify-key-attestation --evidence evidence.json --roots tpm-roots.pem

# Rotate this tenant's domain key to a new generation under its current
# wrapper, or move it onto another configured wrapper. Every stored data key
# and the tenant's event history are re-wrapped; payloads are not decrypted.
trstctl-cli platform tenant-key-domain rotate
cat > rotate.json <<'JSON'
{"wrapper_kind":"pkcs11","wrapper_id":"hsm-b"}
JSON
trstctl-cli platform tenant-key-domain rotate -f rotate.json
trstctl-cli platform tenant-key-domain status

# Rotate the deployment KEK (the operator tenant only) onto an HSM key the
# signer holds; the rotation re-wraps every stored data key in the background.
cat > deployment-kek.json <<'JSON'
{"wrapper_kind":"pkcs11","wrapper_id":"hsm-a"}
JSON
trstctl-cli platform deployment-kek rotate -f deployment-kek.json
trstctl-cli platform deployment-kek status

cat > offline-intermediate-ceremony.json <<'JSON'
{"operation":"create_offline_intermediate","parent_id":"<offline-root-authority-id>","threshold":2,"spec":{"common_name":"Example Issuing Intermediate","ttl_seconds":71280000,"signature_algorithm":"ECDSA-P256","max_path_len":0,"permitted_dns_domains":["example.internal"]}}
JSON
trstctl-cli ca ceremonies start -f offline-intermediate-ceremony.json
trstctl-cli ca ceremonies approve <offline-intermediate-ceremony-id>
trstctl-cli ca ceremonies approve <offline-intermediate-ceremony-id>

cat > offline-intermediate-csr.json <<'JSON'
{"ceremony_id":"<offline-intermediate-ceremony-id>","spec":{"common_name":"Example Issuing Intermediate","ttl_seconds":71280000,"signature_algorithm":"ECDSA-P256","max_path_len":0,"permitted_dns_domains":["example.internal"]}}
JSON
trstctl-cli ca authorities offline-intermediate-csr <offline-root-authority-id> -f offline-intermediate-csr.json

cat > offline-intermediate-import.json <<'JSON'
{"ceremony_id":"<offline-intermediate-ceremony-id>","certificate_pem":"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n","spec":{"common_name":"Example Issuing Intermediate","ttl_seconds":71280000,"signature_algorithm":"ECDSA-P256","max_path_len":0,"permitted_dns_domains":["example.internal"]}}
JSON
trstctl-cli ca authorities import-offline-intermediate <offline-root-authority-id> -f offline-intermediate-import.json

# Sign an external intermediate CA CSR, for example SPIRE's local server CA.
# Keep the private key on the external host. Reuse the exact public CSR and spec
# in both files; a changed field will not match the approved ceremony.
cat > spire-intermediate-ceremony.json <<'JSON'
{"operation":"issue_intermediate_csr","parent_id":"<ca-authority-id>","threshold":2,"csr_pem":"-----BEGIN CERTIFICATE REQUEST-----\n...\n-----END CERTIFICATE REQUEST-----\n","spec":{"common_name":"SPIRE Server CA","ttl_seconds":3600,"max_path_len":0,"permitted_dns_domains":["example.org"]}}
JSON
trstctl-cli ca ceremonies preview -f spire-intermediate-ceremony.json
trstctl-cli ca ceremonies start -f spire-intermediate-ceremony.json
# Run each approval with a different custodian's own token.
trstctl-cli ca ceremonies approve <approved-intermediate-csr-ceremony-id>
trstctl-cli ca ceremonies approve <approved-intermediate-csr-ceremony-id>
cat > spire-intermediate.json <<'JSON'
{"ceremony_id":"<approved-intermediate-csr-ceremony-id>","csr_pem":"-----BEGIN CERTIFICATE REQUEST-----\n...\n-----END CERTIFICATE REQUEST-----\n","spec":{"common_name":"SPIRE Server CA","ttl_seconds":3600,"max_path_len":0,"permitted_dns_domains":["example.org"]}}
JSON
# The console can review/open/refresh this ceremony from the authority Details
# → Sign intermediate CSR dialog; the ID in this request must be that ceremony.
trstctl-cli --idempotency-key spire-upstream-root-1 ca authorities issue-intermediate-csr <ca-authority-id> -f spire-intermediate.json

# Review a zero-downtime rotation first. The preview applies the same eligibility
# rules but changes neither CA; use the exact same body for activation.
cat > ca-rotation.json <<'JSON'
{"successor_id":"<successor-ca-authority-id>","reason":"planned overlap"}
JSON
trstctl-cli ca authorities rotate-preview <predecessor-ca-authority-id> -f ca-rotation.json
trstctl-cli ca authorities rotate <predecessor-ca-authority-id> -f ca-rotation.json

# Re-key a signer-backed CA authority. Copy the current authority's common name,
# DNS constraints, EKUs, and path length from `ca authorities list`; review the
# exact lifetime and reason before custodians approve it.
cat > ca-rekey-ceremony.json <<'JSON'
{"operation":"rekey_ca","authority_id":"<ca-authority-id>","threshold":2,"reason":"planned CA renewal","spec":{"common_name":"Issuing CA","permitted_dns_domains":["example.test"],"extended_key_usages":["serverAuth"],"max_path_len":0,"ttl_seconds":7776000,"signature_algorithm":"ecdsa-p256"}}
JSON
trstctl-cli ca ceremonies preview -f ca-rekey-ceremony.json
trstctl-cli ca ceremonies start -f ca-rekey-ceremony.json

cat > ca-rekey.json <<'JSON'
{"ceremony_id":"<rekey-ceremony-id>","ttl_seconds":7776000,"reason":"planned CA renewal"}
JSON
trstctl-cli ca authorities rekey <ca-authority-id> -f ca-rekey.json

# Cross-sign one exact public target CA after a cross_sign_ca ceremony reaches quorum.
printf '{"ceremony_id":"<cross-sign-ceremony-id>","certificate_pem":"-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----\n"}' > ca-cross-sign.json
trstctl-cli ca authorities cross-sign <issuer-authority-id> -f ca-cross-sign.json
trstctl-cli ca cross-signs get <cross-sign-ceremony-id>

# Import an offline-root successor and both public cross-certificates. The private
# root keys never enter these files or trstctl.
trstctl-cli ca authorities rekey-offline-root <offline-root-authority-id> -f offline-root-rekey.json
trstctl-cli ca offline-rekeys get <succession-ceremony-id> # recover both public trust paths after a lost response
trstctl-cli ca authorities import-offline-cross-sign <successor-authority-id> -f offline-target-cross.json

# Inspect the predecessor CA key's registered dependents before retirement.
# The re-protection response lists queued job IDs; it does not assert that a
# replacement was issued or deployed. Credential jobs require an immutable
# successor/host plan before this command will queue them. The assigned host
# agent retains the existing subject key, and the signed served-leaf report
# drives inventory cutover and durable VDEC completion; inspect the retirement
# checklist again before requesting CA destruction.
trstctl-cli ca keys retirement <predecessor-ca-authority-id>
trstctl-cli ca keys reprotect preview <predecessor-ca-authority-id> -f reprotect-plan.json
trstctl-cli ca keys reprotect plan <predecessor-ca-authority-id> -f reprotect-plan.json
# {"certificate_id":"<outstanding inventory certificate ID>",
#  "successor_authority_id":"<active successor CA ID>",
#  "target_id":"<enabled host target ID>",
#  "expected_target_revision":"<reviewed target revision>",
#  "expected_fingerprint":"<reviewed predecessor certificate SHA-256>",
#  "ttl_seconds":600}
# The server derives the job, one managed identity, old SPKI, assigned host
# agent, connector and listener probe from tenant-scoped records. The plan
# preview is effect-free and shows those exact bindings, including the identity's
# selected active certificate policy or the configured fallback. A policy/name
# drift rejects preview, start or signing; an already recorded plan is read
# back as recorded, never silently replaced with a new policy selection.
# Registration rechecks
# current state and writes a first-writer plan; a lost response is recovered by
# job ID (the CLI URL-escapes the job ID, which contains slashes).
trstctl-cli ca keys reprotect plan get <predecessor-ca-authority-id> <job-id>
# Ambiguous certificate-to-identity links refuse. A changed target,
# certificate or successor requires a new review.
trstctl-cli ca keys reprotect <predecessor-ca-authority-id>

# The same flow is on CA hierarchy > Lifecycle > CA key retirement. Select the
# outstanding host-held certificate, direct successor CA and enabled target;
# review the server-derived plan, record it, read it back, then start. If the
# registration response is lost, enter the preview's job ID in Recover recorded
# job ID and load the immutable plan. Queueing is not served-leaf proof: check
# the signed host result, stock TLS readback and refreshed retirement checklist.
# The host keeps the original subject key and identifiers. Its CSR passes the
# identity-selected active profile's certificate constraints (configured
# default only when there is no identity selection); allowed_protocols governs new
# enrollment, while this reviewed continuation is audited as ca-reprotect.

# For one expired requester-held or revoked, unserved host-held managed CA leaf,
# review a release_managed_ca_leaf ceremony through ca ceremonies preview/create.
# Two other authenticated custodians approve its exact mint ID and public digest.
# The release body binds that ceremony, certificate ID, digest and bounded reason.
trstctl-cli ca keys dependent release <ca-authority-id> -f dependent-release.json
# {"certificate_id":"<inventory id>","expected_certificate_sha256":"<public DER digest>",
#  "ceremony_id":"<approved ceremony id>",
#  "reason":"expired-requester-custody-external-use-risk-accepted","risk_accepted":true}
# For the revoked host-held case, set reason to
# "revoked-unserved-host-custody-external-use-risk-accepted" and confirm the
# review includes its exact completed local-issuer revocation event.

# Once the checklist has no outstanding dependents, request exact-key
# destruction. The irreversible command can wait for signer recovery and
# retained dependency verification; the CLI allows up to ten minutes for the
# response. If the connection still fails, read the checklist before any retry
# and reuse the original Idempotency-Key. A client timeout is not a refusal.
trstctl-cli ca keys retire <predecessor-ca-authority-id> --force -f ca-retire.json
# {"final_epoch":1,"confirm_irreversible":true}

# If the exact retirement outbox command has failed after its delivery budget,
# read its command_event_id and delivery_attempts from the checklist. Review the
# failure, then grant ONE attempt to that same frozen command and signer journal.
# The body must name the exact observed command and attempt count; use a fresh
# Idempotency-Key for each reviewed grant and retain it for lost-response retry.
trstctl-cli ca keys retirement retry <predecessor-ca-authority-id> -f retirement-retry.json
# {"command_event_id":"<from checklist>","expected_attempts":10,
#  "reason":"Local signer response was lost","confirm_irreversible":true}

# Review the exact request and deployment-owned quorum/custody readiness first.
trstctl-cli breakglass issue-preview -f breakglass-issue-intent.json

# Online break-glass uses an exact intent ceremony and authenticated CA approvals;
# the execution body carries ceremony_id but never approver names.
trstctl-cli breakglass issue-ceremony -f breakglass-issue-intent.json
trstctl-cli ca ceremonies approve <breakglass-ceremony-id> # distinct operator token A
trstctl-cli ca ceremonies approve <breakglass-ceremony-id> # distinct operator token B
trstctl-cli breakglass issue -f breakglass-issue.json
trstctl-cli breakglass issues list --limit 20
trstctl-cli breakglass issues get <breakglass-ceremony-id> # exact signed readback after lost response

# Rotation and target cross-signing use the same ceremony -> approvals -> execute pattern.
trstctl-cli breakglass rotation-ceremony -f breakglass-rotation-intent.json
trstctl-cli breakglass rotate -f breakglass-rotation.json
trstctl-cli breakglass cross-sign-ceremony -f breakglass-cross-sign-intent.json
trstctl-cli breakglass cross-sign -f breakglass-cross-sign.json

# When the API/database are down, the separate trstctl-signer binary prepares,
# approves and issues a v2 offline bundle from its sealed vault. After recovery:
trstctl-cli breakglass reconcile -f breakglass-reconcile-body.json
# See runbooks/disconnected-breakglass.md for the exact two-custodian steps.

# List configured upstream CAs and issue through one of them.
trstctl-cli external-cas list
cat > upstream-issue.json <<'JSON'
{"csr_pem":"-----BEGIN CERTIFICATE REQUEST-----\n...\n-----END CERTIFICATE REQUEST-----\n","dns_names":["payments.example.com"],"ttl_seconds":86400}
JSON
trstctl-cli external-cas issue digicert -f upstream-issue.json

# Rank credentials by risk — what to rotate first.
trstctl-cli risk credentials --sort score
# The contextual response includes the canonical urgent_summary: both named
# tenant projections, per-source counts, and a credential_id-deduplicated total.
# If either projection read fails, the command returns the API error, not zero.
trstctl-cli risk contextual-priorities

# Export a signed SOC 2 evidence pack from audit, access, and change evidence.
trstctl-cli compliance evidence-pack soc2

# Export FIPS 140 and Common Criteria evidence posture.
trstctl-cli compliance evidence-pack fips-140
trstctl-cli compliance evidence-pack common-criteria

# Export regulatory framework evidence mappings.
trstctl-cli compliance evidence-pack nist-800-53
trstctl-cli compliance evidence-pack fedramp
trstctl-cli compliance evidence-pack cmmc-2.0
trstctl-cli compliance evidence-pack eidas
trstctl-cli compliance evidence-pack nis2

# Export CA/Browser Forum Baseline Requirements evidence posture.
trstctl-cli compliance evidence-pack cabf-br

# Show CAP-OBS-02 compliance/inventory reporting coverage and served report routes.
trstctl-cli compliance inventory-report

# Show CAP-CMP-06 NHI compliance mappings for NIST 800-53/CSF, PCI DSS 4.0,
# DORA, ISO 27001, FedRAMP, CMMC, eIDAS, and NIS2 evidence refs.
trstctl-cli compliance nhi-report

# Configure one tenant-scoped Splunk HEC schedule. token_ref is an
# operator-allowlisted pointer; the credential value never enters the request.
cat > audit-feed.json <<'JSON'
{"name":"production-soc","provider":"splunk-hec","endpoint_url":"https://splunk.example.com/services/collector/event","token_ref":"env:SPLUNK_HEC_TOKEN","interval_seconds":300,"batch_size":100,"enabled":true}
JSON
# Validate the exact destination and see writes, later effects, proof, and recovery.
# This POST-shaped read sends no Idempotency-Key and performs no write or network call.
trstctl-cli audit feeds preview 52525252-5252-4525-8525-525252525252 -f audit-feed.json

# Save only after the preview matches the intended collector configuration.
trstctl-cli --idempotency-key audit-feed-production audit feeds set 52525252-5252-4525-8525-525252525252 -f audit-feed.json

# Read schedule, cursor, exact record lag, retry/failure, and collector receipt
# state. This is read-only and sends no Idempotency-Key.
trstctl-cli audit feeds list

# Record an archive-backed signed report schedule. The licensed governance signer
# and a private mounted audit.archive_dir are required; no email/webhook is sent.
cat > compliance-schedule.json <<'JSON'
{"framework":"soc2","name":"weekly-soc2-pack","report_type":"framework_evidence_pack","interval_seconds":604800,"delivery":"audit_export","recipient_ref":"weekly-soc2"}
JSON
trstctl-cli compliance report-schedules preview -f compliance-schedule.json
trstctl-cli --idempotency-key weekly-soc2 compliance report-schedules create -f compliance-schedule.json
trstctl-cli compliance report-schedules list
trstctl-cli compliance report-schedules runs SCHEDULE_ID
trstctl-cli compliance report-runs get RUN_ID
trstctl-cli compliance report-runs download RUN_ID > signed-report.json
# Verify a saved run offline against the signing key you pinned (compare its sha256 out of band).
trstctl-cli compliance report-signing-key | jq -r .public_key_pem > report-signing-key.pem
trstctl-cli compliance report-runs verify --report signed-report.json --public-key report-signing-key.pem
trstctl-cli --idempotency-key retry-report-1 compliance report-runs requeue FAILED_RUN_ID

# Recovery retains the definition and evidence, stops future due work, and resumes
# with a fresh full interval after the problem is corrected.
trstctl-cli --idempotency-key pause-weekly-soc2 compliance report-schedules pause SCHEDULE_ID
trstctl-cli --idempotency-key resume-weekly-soc2 compliance report-schedules resume SCHEDULE_ID

# Review the exact normalized targets and read/write ceilings without touching them.
cat > cbom-scan.json <<'JSON'
{"tls_endpoints":["https://payments.internal.example"],"host_configs":["/etc/nginx/sites-enabled/payments.conf"]}
JSON
trstctl-cli cbom preview -f cbom-scan.json

# Run only after reviewing the plan. Preview sends no Idempotency-Key; scan does.
trstctl-cli cbom scan -f cbom-scan.json
trstctl-cli cbom assets

# Track migration work and evidence in Core, independent of execution.
# Operators may remediate manually or with any external tool, then record evidence.
cat > pqc-campaign.json <<'JSON'
{"name":"Payments PQC migration","owner":"team:payments","deadline":"2026-12-01T00:00:00Z","wave":"wave-1","readiness_criteria":["owner approved","rollback documented"],"finding_ids":["<cbom-finding-id>"]}
JSON
trstctl-cli --idempotency-key pqc-payments-create pqc campaigns create -f pqc-campaign.json
printf '{"status":"passed","evidence_refs":["change:CAB-2048"]}\n' | trstctl-cli --idempotency-key pqc-payments-ready pqc campaigns readiness <campaign-id> -f -
printf '{"disposition":"remediated","method":"manual","reason":"replaced through the existing CA workflow","evidence_refs":["audit:certificate.issued:replacement"],"evidence_digests":["sha256:<64-lowercase-hex>"]}\n' | trstctl-cli --idempotency-key pqc-payments-finding pqc campaigns disposition <campaign-id> <finding-id> -f -
trstctl-cli --idempotency-key pqc-payments-close pqc campaigns close <campaign-id> --force
trstctl-cli pqc campaigns evidence <campaign-id>

# Prove a post-quantum leaf in waves: the canary first; one refusal halts the pilot.
cat > pq-pilot.json <<'JSON'
{"name":"Payments PQ pilot","authority_id":"<ml-dsa-issuing-authority-id>","waves":[{"name":"canary","targets":[{"target_id":"<host-target-id>","address":"api.internal:443","server_name":"api.internal","fingerprint":"<served-leaf-sha256>"}]},{"name":"broad","targets":[{"target_id":"<second-target-id>","address":"web.internal:443","server_name":"web.internal","fingerprint":"<served-leaf-sha256>"}]}]}
JSON
trstctl-cli --idempotency-key pq-pilot-1 pqc pilots create -f pq-pilot.json
trstctl-cli pqc pilots get <pilot-id>   # waves, outcomes, verdicts and the signed readiness report

# Core PQC migration: review the exact CBOM asset IDs before starting.
# Preview and start refuse an observed certificate name denied by the active
# served profile. An issued certificate is not proof of key custody or deployment.
cat > migration-start.json <<'JSON'
{"asset_ids":["<cbom-asset-id>"],"target_algorithm":"ML-DSA-65","protocol":"acme","rollback_on_failure":true}
JSON
trstctl-cli migration plan -f migration-start.json
trstctl-cli --idempotency-key migrate-payments-1 migration start -f migration-start.json
trstctl-cli migration status <run-id>
# Rollback requires the exact assets; certificate-key rollback is not a served
# endpoint recovery receipt. Verify the target independently afterward.
cat > migration-rollback.json <<'JSON'
{"asset_ids":["<cbom-asset-id>"],"reason":"operator recovery after reviewed run"}
JSON
trstctl-cli --idempotency-key migrate-payments-1-rollback migration rollback <run-id> -f migration-rollback.json

# Mint a one-time agent bootstrap token. Pass allowed_identity when the token
# should redeem only for one node or host identity.
trstctl-cli agents enroll-token
printf '{"allowed_identity":"node-a"}\n' | trstctl-cli agents enroll-token -f -
trstctl-cli agents list
printf '{"reason":"host decommissioned"}\n' | trstctl-cli --idempotency-key agent-node-a-offboard-1 agents offboard <agent-id> -f - --force
# Change an enrolled agent's roles (needs agents:relay.grant). The agent's next
# renewal signs them; a current agent renews at its next heartbeat.
printf '{"roles":["host","network"],"reason":"front the plant 7 appliances"}\n' | trstctl-cli --idempotency-key agent-node-a-roles-1 agents roles grant <agent-id> -f -

# Issue a policy-gated short-lived credential for an AI/MCP agent.
cat > broker-agent.json <<'JSON'
{"agent_id":"agent-7","method":"k8s_sat","payload_base64":"<proof-base64>","public_key_pem":"-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----\n","scopes":["mcp:graph.read","tool:inventory.read"],"ttl_seconds":600}
JSON
trstctl-cli --idempotency-key agent-7-issue-1 broker agent-identities issue -f broker-agent.json

# Open an attestation-gated JIT credential request, approve it, then mint it.
cat > ephemeral-jit.json <<'JSON'
{"request_id":"jit-agent-7","method":"k8s_sat","payload_base64":"<proof-base64>","public_key_pem":"-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----\n","ttl_seconds":120}
JSON
trstctl-cli ephemeral preview -f ephemeral-jit.json
trstctl-cli --idempotency-key jit-agent-7-request-1 ephemeral issue -f ephemeral-jit.json
cat > ephemeral-approval.json <<'JSON'
{"action":"issue","request_id":"<approval_request_id>","intent_digest":"<intent_digest>"}
JSON
trstctl-cli --idempotency-key jit-agent-7-approve-1 ephemeral approve <approval_request_id> -f ephemeral-approval.json
trstctl-cli --idempotency-key jit-agent-7-issue-1 ephemeral issue -f ephemeral-jit.json

# Discover, review, issue, renew, read, and revoke a dynamic secret lease.
trstctl-cli secrets leases providers
cat > dynamic-lease.json <<'JSON'
{"provider":"payments-db","role":"readonly","ttl_seconds":900}
JSON
trstctl-cli secrets leases preview -f dynamic-lease.json
trstctl-cli --idempotency-key lease-issue-1 secrets leases issue -f dynamic-lease.json
trstctl-cli secrets leases get <lease-id>
printf '{"extend_seconds":900}' | trstctl-cli --idempotency-key lease-renew-1 secrets leases renew <lease-id> -f -
trstctl-cli --idempotency-key lease-revoke-1 secrets leases revoke <lease-id> --force
# If GET later reports revocation_status=failed, repair the provider, then retry
# the exact lease with a fresh key. Keep the old key for replay of its first receipt.
trstctl-cli --idempotency-key lease-revoke-retry-1 secrets leases revoke <lease-id> --force
trstctl-cli secrets leases get <lease-id>  # wait for revocation_status=completed

# Generate and retire an HSM/KMS-backed managed key after managed_keys is enabled.
cat > managed-key.json <<'JSON'
{"provider":"aws","algorithm":"RSA-2048"}
JSON
trstctl-cli --idempotency-key kms-key-1 managed-keys generate -f managed-key.json
# If generation returns 202, use its operation_id until status is completed or
# failed. The same idempotency key replays the original receipt without a new key.
trstctl-cli managed-keys operation <operation-id>
trstctl-cli managed-keys list --limit 20
trstctl-cli managed-keys get aws-kms <key-id> # provider comes from the list result
# A saved active record is historical. Prove the provider still holds this exact
# key before using it; inspect custody_status and custody_checked_at afterward.
printf '{"key_id":"<key-id>"}' | trstctl-cli --idempotency-key kms-key-1-proof managed-keys verify-custody -f - --force
trstctl-cli managed-keys get aws-kms <key-id>
printf '{"key_id":"<key-id>","action":"rotate"}' | trstctl-cli --idempotency-key kms-key-1-approve-a managed-keys approve -f -
printf '{"key_id":"<key-id>","action":"rotate"}' | trstctl-cli --idempotency-key kms-key-1-approve-b managed-keys approve -f -
printf '{"key_id":"<key-id>"}' | trstctl-cli --idempotency-key kms-key-1-rotate managed-keys rotate -f - --force
printf '{"key_id":"<rotated-key-id>","action":"zeroize"}' | trstctl-cli --idempotency-key kms-key-1-zeroize-approve-a managed-keys approve -f -
printf '{"key_id":"<rotated-key-id>","action":"zeroize"}' | trstctl-cli --idempotency-key kms-key-1-zeroize-approve-b managed-keys approve -f -
printf '{"key_id":"<rotated-key-id>"}' | trstctl-cli --idempotency-key kms-key-1-zeroize managed-keys zeroize -f - --force

# Review the exact plan first. Preview has no Idempotency-Key because it makes no
# writes, generates no secret material, and contacts no connector.
printf '{"provider":"connector:ci","key":"db/password","old_ref":"version:2","remote_key":"DB_PASSWORD"}' \
  | trstctl-cli secrets rotations preview -f -

# Run the reviewed worker-queued connector rotation with an Idempotency-Key.
printf '{"provider":"connector:ci","key":"db/password","old_ref":"version:2","remote_key":"DB_PASSWORD"}' \
  | trstctl-cli --idempotency-key connector-rotation-1 secrets rotations run -f -

# Rotate the lease an application secret publishes: a new lease of ttl_seconds is
# issued, published as the next version, verified, and the old lease revoked. The
# secret's name is the provider role; old_ref is the lease id it publishes now.
printf '{"provider":"dynamic-lease:pg-leases","key":"reporting","old_ref":"<lease-id>","ttl_seconds":1800}' \
  | trstctl-cli secrets rotations preview -f -
printf '{"provider":"dynamic-lease:pg-leases","key":"reporting","old_ref":"<lease-id>","ttl_seconds":1800}' \
  | trstctl-cli --idempotency-key lease-rotation-1 secrets rotations run -f -
trstctl-cli secrets rotations get <command-id>

# Schedule connector rotation and run due schedules from the served path.
cat > connector-rotation-schedule.json <<'JSON'
{"name":"reporting-hourly","provider":"connector:ci","key":"db/password","old_ref":"version:2","interval_seconds":3600}
JSON
trstctl-cli --idempotency-key connector-rotation-schedule-1 secrets rotation-schedules create -f connector-rotation-schedule.json
trstctl-cli secrets rotation-schedules list
trstctl-cli secrets rotation-schedules get <schedule-id>
trstctl-cli --idempotency-key schedule-pause-1 secrets rotation-schedules pause <schedule-id>
trstctl-cli --idempotency-key schedule-resume-1 secrets rotation-schedules resume <schedule-id>
# Retirement preserves history and reserves the schedule name; --force acknowledges the permanent stop.
trstctl-cli --force --idempotency-key schedule-retire-1 secrets rotation-schedules retire <schedule-id>
trstctl-cli --idempotency-key connector-rotation-due-1 secrets rotation-schedules run-due

# Review a stored-secret delivery before allowing any write or network effect.
# Preview reads tenant-scoped metadata only: it does not open the secret value,
# append an event, enqueue an outbox row, or contact the target.
cat > secret-sync.json <<'JSON'
{"name":"sync/source","target":"github-actions","remote_key":"DB_PASSWORD"}
JSON
trstctl-cli secrets syncs preview -f secret-sync.json

# Copy request_fingerprint from the preview into preview_fingerprint. Execution
# rejects a stale plan if the caller, secret version, target, or remote key changed.
cat > reviewed-secret-sync.json <<'JSON'
{"name":"sync/source","target":"github-actions","remote_key":"DB_PASSWORD","preview_fingerprint":"sha256:<copy-from-preview>"}
JSON
trstctl-cli --idempotency-key secret-sync-1 secrets syncs run -f reviewed-secret-sync.json

# The execution response is metadata only; the secret value is never echoed back.

# Discover supported and configured target IDs before choosing the target field.
trstctl-cli secrets syncs targets

# Inspect CAP-SEC-04 cloud secret-manager discovery and sync posture.
trstctl-cli secrets cloud-secret-managers

# Inspect the Kubernetes SecretSync CRD, Secret projection, and reload posture.
trstctl-cli secrets kubernetes-operator

# Inspect the no-code workload secret-injection CRD, sidecar, and env/file posture.
trstctl-cli secrets workload-injection

# Inspect unvaulted-secret detection, visible vaults, and augmentation targets.
trstctl-cli secrets unvaulted

# Inspect native Kubernetes CertificateSigningRequest support, signer names, and RBAC.
trstctl-cli kubernetes csr

# Inspect Kubernetes TrustBundle CRD, ConfigMap distribution, status fields, and RBAC.
trstctl-cli kubernetes trust-bundles

# Roll one public CA bundle out to the clusters whose controllers report here,
# canary first; each cluster is verified by its own controller's report.
jq -n --rawfile pem roots.pem '{name:"platform-roots", ca_bundle_pem:$pem,
  namespaces:["apps","payments"], clusters:["sha256:<canary cluster id>","sha256:<next cluster id>"]}' \
  | trstctl-cli kubernetes trust-rollouts start -f -
trstctl-cli kubernetes trust-rollouts list
trstctl-cli kubernetes trust-rollouts get <rollout-id>
trstctl-cli kubernetes trust-rollouts pause <rollout-id>
trstctl-cli kubernetes trust-rollouts resume <rollout-id>

# Run a Gitleaks code scan from CI and record redacted findings in discovery/graph.
cat > secret-scan.json <<'JSON'
{"path":"."}
JSON
trstctl-cli secrets scans preview -f secret-scan.json
# Add the returned request_fingerprint as preview_fingerprint in the same body.
# Reuse this idempotency key if the run is interrupted; a completed run replays.
trstctl-cli --idempotency-key secret-scan-1 secrets scans run -f reviewed-secret-scan.json

# Scan full Git history with the default 213-rule floor plus additive custom rules.
cat > deep-secret-scan.json <<'JSON'
{"path":".","mode":"git_history","custom_rules_path":"./gitleaks-custom-rules.toml"}
JSON
trstctl-cli --idempotency-key secret-scan-deep-1 secrets scans run -f deep-secret-scan.json

# Block local commits on staged Git blobs without requiring a running control plane.
trstctl-cli secrets scans staged-diff --repo .
trstctl-cli secrets scans pre-commit install --repo .

# Run the same local scanner over the head side of a base/head CI diff.
trstctl-cli secrets scans staged-diff --repo . --base origin/main --head HEAD

# Inspect repository secret-scanning posture, then queue a normalized provider event.
trstctl-cli secrets scans repositories
cat > repo-webhook.json <<'JSON'
{"repository":"acme/payments","checkout_path":".","ref":"refs/heads/main","event":"push"}
JSON
trstctl-cli --idempotency-key repo-scan-1 secrets scans repositories webhook github -f repo-webhook.json

# Inspect CI-log, container-registry, Slack, and Jira artifact scanning posture,
# then queue a redacted third-party artifact scan through the discovery outbox.
trstctl-cli secrets scans third-party
cat > third-party-scan.json <<'JSON'
{"source":"acme/slack","artifact_path":"/var/lib/trstctl/exports/slack.jsonl","event":"message_export"}
JSON
trstctl-cli --idempotency-key third-party-scan-1 secrets scans third-party ingest slack -f third-party-scan.json

# Create a transit AEAD key, encrypt data, rotate, and rewrap to the newest version.
cat > transit-key.json <<'JSON'
{"name":"payments","kind":"aead"}
JSON
trstctl-cli --idempotency-key transit-payments-create transit keys create -f transit-key.json
trstctl-cli transit keys versions payments
trstctl-cli transit status

cat > transit-encrypt.json <<'JSON'
{"key":"payments","plaintext":"Y2FyZC10b2tlbi0xMjM=","aad":"dGVuYW50PXBheW1lbnRz"}
JSON
trstctl-cli --idempotency-key transit-payments-encrypt transit encrypt -f transit-encrypt.json
trstctl-cli --idempotency-key transit-payments-rotate transit keys rotate -f transit-key.json

cat > transit-rewrap.json <<'JSON'
{"key":"payments","ciphertext":"trv:1:<ciphertext-from-encrypt>","aad":"dGVuYW50PXBheW1lbnRz"}
JSON
trstctl-cli --idempotency-key transit-payments-rewrap transit rewrap -f transit-rewrap.json

cat > code-sign.json <<'JSON'
{"key_id":"release-key","artifact_type":"oci-image","digest":"4EW4IfBBkDngEwN3v+ChO06PV2er4tF7nEVmFev3x1g="}
JSON
# Review an artifact digest with a configured code-signing key. This is effect-free:
# it does not open the signer, write state, or contact Rekor.
trstctl-cli code-signing preview -f code-sign.json > code-sign-plan.json

# Copy request_fingerprint from the plan into code-sign.json as
# preview_fingerprint, then execute with one retained recovery key. The response
# contains the signature, public key, algorithm, and transparency outbox destination.
trstctl-cli --idempotency-key release-sign-1 code-signing sign -f code-sign.json

# Sign keylessly with a verified Fulcio/Sigstore identity proof. identity_payload is
# base64 JSON bytes; the served attestor verifies it before the signature is issued.
cat > code-sign-keyless.json <<'JSON'
{"artifact_type":"oci-image","digest":"4EW4IfBBkDngEwN3v+ChO06PV2er4tF7nEVmFev3x1g=","identity_method":"github_oidc","identity_payload":"eyJqd3QiOiJleGFtcGxlIn0=","fulcio_san":"repo:acme/payments:ref:refs/heads/main","fulcio_issuer":"https://token.actions.githubusercontent.com"}
JSON
trstctl-cli code-signing keyless-preview -f code-sign-keyless.json > code-sign-keyless-plan.json
trstctl-cli --idempotency-key release-keyless-1 code-signing keyless -f code-sign-keyless.json

# On an enrolled host, report local public certificate files over the agent channel.
trstctl-agent --enroll-url https://localhost:8443 \
  --bootstrap-token-file ./trstctl-bootstrap-token \
  --server localhost:19443 \
  --server-name localhost \
  --name edge-agent-1 \
  --ca-bundle ./trstctl-ca.pem \
  --inventory-cert-roots /etc/ssl,/etc/pki/tls/certs \
  --inventory-os-trust-roots /etc/ssl/certs \
  --inventory-java-trust-stores "$JAVA_HOME/lib/security/cacerts" \
  --inventory-private-key-roots /etc/ssl/private,/etc/ssh
trstctl-cli discovery findings list

# --enroll-url is the control-plane base URL, not /enroll/bootstrap. Plain HTTP
# remains blocked except with --allow-insecure-loopback-enrollment on loopback.

# Correlate one managed issuer to observed trust stores. Authoritative counts use
# exact certificate/SPKI identity; name-only candidates are returned separately.
trstctl-cli graph trust-stores iss:<issuer-id>

# Read the canonical tenant-bound readiness dataset, create an action against
# its current row/owner digest, then download the independently verifiable
# JSON envelope carrying the exact CSV and NDJSON bytes.
trstctl-cli graph crypto-readiness
cat > crypto-readiness-action.json <<'JSON'
{"name":"Payments crypto blocker","owner":"team:payments","deadline":"2026-12-01T00:00:00Z","wave":"wave-1","readiness_criteria":["owner approved","rollback documented"],"finding_ids":["<cbom-finding-id>"]}
JSON
trstctl-cli --idempotency-key payments-crypto-1 graph crypto-readiness actions create -f crypto-readiness-action.json
trstctl-cli graph crypto-readiness export > crypto-readiness-evidence.json

# In a cluster, add --inventory-k8s-secrets to inventory the kubernetes.io/tls
# Secrets in the agent's own namespace (reads tls.crt, never tls.key; needs list
# access to Secrets in that namespace). Add --inventory-k8s-namespaces all (or a
# comma-separated list) to cover other namespaces from the same agent; "all"
# needs the opt-in read-only grant in deploy/kubernetes/rbac-inventory-namespaces.yaml,
# and a namespace the agent cannot list is reported as an error, not as empty.

# Run a graph query.
trstctl-cli graph query "MATCH (c:Certificate)-[:SIGNED_BY]->(i:Issuer) RETURN c,i"

Run the two managed-key approve commands with tokens for two different authenticated principals holding keys:approve. The requester cannot approve their own action, even if that principal also holds keys:approve. Approval bodies keep key_id in JSON so opaque cloud-KMS URLs and HSM handles containing / are preserved exactly; action is one of rotate, revoke, or zeroize.

--inventory-private-key-roots locates and classifies private-key files on the host but reports only metadata: path, key format, algorithm, file-mode status, and a public-key-derived fingerprint when one can be computed. The agent wipes file buffers after inspection and never sends PEM/DER key bytes to the control plane.

Path parameters are positional; list filters (--limit, --cursor, --sort, …) are flags; request bodies come from -f <file> or -f - (stdin).

MCP stdio transport (mcp serve)

A standard Model Context Protocol client (an IDE, an agent framework) spawns the CLI and talks JSON-RPC 2.0 over stdin/stdout, one message per line:

{"command": "trstctl-cli", "args": ["mcp", "serve"],
 "env": {"TRSTCTL_SERVER": "https://cp.example:8443", "TRSTCTL_CA_FILE": "/etc/trstctl/control-plane.crt", "TRSTCTL_TOKEN": "trst_…"}}

initialize, ping, tools/list and tools/call are served; the token travels in the environment, never on the command line. Every tools/call becomes POST /api/v1/mcp/tools/{tool} with your token and a fresh Idempotency-Key, so the server's tenant scope, RBAC, rate limit and audit apply exactly as for REST; a refused call comes back as a readable tool error (isError: true), not as a transport failure. Write tools appear only when the control plane exposes them (TRSTCTL_AI_MCP_WRITE_TOOLS=true) and still require certs:issue. A write that dual control holds comes back with "outcome":"proposed", its approval request and the idempotency_key it is bound to; once a distinct approver approved it, repeat the same call with that idempotency_key argument, which the bridge sends as the Idempotency-Key header, and the approved write runs. The control plane publishes the result schema with its tool list; the bridge gives it to the client as every tool's outputSchema, passes each tool's description, and returns each result as structuredContent alongside its JSON text.

Rendered live from github.com/ctlplne/trstctl — found a mistake? edit this page.