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/pathis repeatable.ENVmust be a normal environment variable name, andsecret/pathmay contain/path segments.--resolvemaps to?resolve=true, so referenced values such as${secret.app/db/password}expand only when the caller asks for it.runusesTRSTCTL_TOKENto 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/developerworkspace 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 retainedtenant.registeredevent; 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 asTRSTCTL_TOKENfortrstctl-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.