Respond to a key or certificate compromise
Goal
When you finish this journey you will have contained a compromised credential:
the leaked certificate revoked and visible as revoked on the served surface, a
replacement issued and deployed, and the whole response captured as a sealed,
tamper-evident evidence pack. It is for the on-call operator who has just learned a
private key leaked, a certificate was mis-issued, or a CA may be compromised, and
needs to act safely under pressure. In plain terms: you preserve evidence, find
everything the bad credential can reach, replace-then-revoke in the right order so
you do not cause an outage, and — when a second person must sign off — gate the
action behind an approval.
In the console: the
/incidentsscreen runs this whole response — a served blast-radius preview for the compromised identity, replacement-before-revoke execution with the resulting evidence, and a break-glass reconciliation panel. See The web console.
Before you start
- A running control plane and an API token, set up in Getting started. Containment is a privileged action, so your principal needs issuance authority (the bootstrap token deliberately withholds it).
- Know which credential is affected. The blast-radius and revocation surfaces are described in Incident response & just-in-time access and Issuance & certificate authorities.
- Have the incident-response runbook open — this journey is the happy-path version of it.
Steps
Declare the incident and preserve evidence first. Before changing anything, take a full backup — the event log inside it is the immutable forensic record:
trstctl --full-backup-dir=/backups/incident-$(date +%F)You should see a confirmation that the full backup was written. Keep it; you can restore from it later (see the disaster-recovery runbook).
Scope the blast radius. Find the affected credential and everything that depends on it — read-only, so it changes nothing:
trstctl-cli graph blast-radius cert:payments-tlsYou should see the affected resources grouped by kind. This is the same credential graph the served incident workflow reads before it acts.
Run the served containment workflow. For a single leaked identity, the served workflow replaces-then-revokes idempotently — it issues and deploys a replacement first, then revokes the compromised credential, so nothing goes dark mid-incident. Put the details in a JSON file:
{ "identity_id": "11111111-1111-1111-1111-111111111111", "reason": "private key export detected", "replacement_name": "payments-api-incident-replacement", "connector": "nginx", "target": "edge/prod/payments", "delivery_rollback_ref": "restore previous fullchain" }trstctl incidents executions execute -f incident.jsonYou should get back an execution with a replacement id, a revocation-queue status, a connector delivery receipt, and a sealed audit bundle. The order is deliberate — do not shortcut it.
Confirm the revocation is live. Transitioning to revoked marks the certificate
revokedin inventory and updates the published revocation status. Read it back:trstctl-cli certificates get 11111111-1111-1111-1111-111111111111You should see
statusread"revoked"with arevoked_attimestamp. Relying parties checking the served OCSP responder at/ocsp/{tenant}now getrevoked, and the serial appears on the tenant CRL at/crl/{tenant}within the freshness window. The full revocation surface is in Issuance & certificate authorities.Retrieve the sealed evidence pack. Pull the recorded execution for your post-incident review:
trstctl incidents executions get 22222222-2222-2222-2222-222222222222You should see the immutable evidence pack — replacement id, revocation status, delivery receipt, failed-target list, rollback references, and the sealed audit bundle.
If the action needs a second pair of eyes (break-glass / JIT). When dual control is enabled, a privileged issue or revoke is denied until a distinct approver signs off — a self-approval is rejected. The requester opens the request; a second operator approves it:
curl -fksS -X POST \ -H "Authorization: Bearer $TRSTCTL_TOKEN" \ -H "Content-Type: application/json" \ -d '{}' \ https://localhost:8443/api/v1/identities/11111111-1111-1111-1111-111111111111/approvalsYou should see the approval recorded; the action proceeds only once a distinct approver has signed off. The four-eyes and just-in-time model is described in Incident response & just-in-time access.
Use brokered access instead of standing credentials. If the responder needs to inspect a database or host, open a short-lived privileged-access session instead of sharing a long-lived password or SSH key:
curl -fksS -X POST \ -H "Authorization: Bearer $TRSTCTL_TOKEN" \ -H "Idempotency-Key: incident-2026-06-25-db-readonly" \ -H "Content-Type: application/json" \ -d '{"target_type":"postgres","target_id":"pg-main","role":"readonly","reason":"production incident 42","method":"k8s_sat","payload_base64":"...","ttl_seconds":900}' \ https://localhost:8443/api/v1/access/sessionsYou should receive a session id, an expiry, and a one-time credential. Audit readers can later filter
pam.session.startedandpam.session.expired; after expiry the database role is revoked or the SSH certificate is past its validity window.
Where next
Journey: J9 Steps through: F31, F32, F33, F34, F47, F18, F19