Observability & risk — see your crypto, score it, catch what changes
What it is
Discovery tells you what credentials exist; this page — the smoke detectors and risk register to discovery's census — tells you which ones to worry about and what's changing: Certificate Transparency monitoring (certificates issued for your domains you didn't request), drift detection (a deployed credential moved, replaced, or exposed), credential risk scoring (rank everything by "fix this first"), and the CBOM — a bill of materials flagging weak and quantum-vulnerable crypto.
trstctl also exports the control-plane signal you need to operate those workflows: served HTTP traces and event-sourced audit records can stream to your OpenTelemetry Collector over OTLP/HTTP protobuf. That lets Splunk, Datadog, or any SIEM pipeline consume the same immutable audit stream auditors inspect, with event sequence and tenant attributes for dedupe and gap detection. In air-gapped installs, that collector must be operator-owned on a private host or explicitly allowlisted; the no-phone-home guard blocks public collector endpoints.
Why it exists
A list of credentials only helps if you can act on it. Security teams drown in findings, so the question is always "what first?" — that's risk scoring. Mis-issuance and shadow IT show up as certificates in public logs you didn't request — that's CT monitoring. Quietly broken or loosened deployments cause outages — that's drift. And the looming quantum transition makes "where is our weak/old crypto?" urgent — that's the CBOM. Together they turn inventory into action.
How it works
Credential risk scoring (F19)
Risk scoring assigns every credential a 0–100 score from six weighted factors: age, exposure (blast radius from the graph), privilege, rotation staleness (never-rotated scores highest), owner activity (orphaned scores higher), and sensitivity (wildcards/large SAN sets) — weighted toward exposure and privilege, what hurts most in a breach. Scoring pages the whole inventory, tenant-isolated at the database layer; filter by minimum score, privilege class, or owner.
Status: served — GET /api/v1/risk/credentials, GET /api/v1/risk/contextual-priorities, and the four NHI-posture routes below, each with a
matching risk/nhi posture CLI command.
Contextual risk prioritization ranks certificates, NHI, SSH keys, and discovery findings by blast-radius impact, CBOM crypto context, owner state, staleness, and expiry urgency, returning priority reasons, evidence refs, severity, and a recommended action — useful when two credentials score similarly but differ sharply in blast radius.
NHI posture reads the same unified inventory as the dashboard — managed identities, access tokens, and discovery findings — across four conditions:
| Endpoint | What it answers | Key response fields |
|---|---|---|
GET /api/v1/nhi/posture/overprivilege |
Which grants exceed observed usage? | Unused grants, least-privilege recommendation, source row, severity, evidence refs |
GET /api/v1/nhi/posture/stale |
Which credentials are stale, dormant, unused, or orphaned? | Thresholds, activity/creation age, owner status, severity, evidence refs, remediation |
GET /api/v1/nhi/posture/static-credentials |
Which credentials are long-lived, static, or overdue for rotation? | Credential age, TTL, rotation age, lifetime thresholds, owner status, severity, evidence refs, remediation |
GET /api/v1/nhi/posture/exposure |
Which credentials are internet-exposed or insecurely deployed? | Sanitized endpoint/callback URLs, severity, evidence refs, remediation |
Grants with no usage evidence stay unclassified rather than counting as a finding; the
exposure route is read-only and never echoes credential values. For example,
trstctl-cli nhi posture stale reports each stale credential's activity age, owner
status, severity, and remediation.
Certificate Transparency monitoring (F17)
Every certificate a public CA issues is recorded in public, append-only CT logs
(RFC 6962). If one appears for your domain that you didn't request, that's an early
warning of mis-issuance, shadow IT, or attack. trstctl's monitor polls CT logs
incrementally from a saved checkpoint, matches entries against watched domains (resistant
to the example.com.evil.net suffix trick), and alerts on anything not already in your
inventory. Alerts use reliable, journaled, at-least-once
delivery with an idempotency key (ct:<log>:<index>) so a retry never double-alerts.
Polling runs in its own bounded lane, RFC 6962 binary parsing stays inside the single
crypto path, and checkpoints persist so monitoring resumes across restarts, tenant-isolated
at the database layer.
Status: served. Use GET/PUT /api/v1/discovery/ct-monitoring, discovery ct-monitoring get|update, or the Posture page to configure watched domains/logs, inspect
checkpoints, queue a poll, and review ct_unexpected_issuance findings. The worker polls,
records tenant-scoped findings, and queues notifications via the outbox.
Drift detection (F18)
After the agent installs a credential, drift detection notices if reality diverges from
intent, comparing each watched file's content fingerprint and permissions and classifying
the divergence as Deleted, Replaced (different content), Relocated (same content
elsewhere, so a move isn't misreported as deletion), or PermissionChanged (mode/ACL
loosened). Permission checks are platform-aware (POSIX mode bits; Windows DACL for
broad-access ACEs); the agent reports at startup whether the platform can detect
permission loosening. Content hashing goes through the single crypto path;
secret material stays in wipeable memory, zeroed after use.
Status: served. Create a Discovery source of kind drift with watched paths,
fingerprints, and modes, then start a run; the worker records credential_drift
findings and queues notifications. Review findings, see the recommended action, and
record a decision via GET /api/v1/discovery/drift-remediation, POST /api/v1/discovery/drift-remediation/{id}/decision, the discovery drift-remediation
CLI, or the Posture page. Decisions are event-sourced as
discovery.finding.triage_changed audit evidence; the API never stores or returns
credential bytes.
The CBOM — cryptographic bill of materials (F52)
You can't plan a crypto migration without knowing what crypto you run. The CBOM scanner
inventories cryptographic usage across TLS endpoints and host config files, then
classifies each observation: algorithm family and strength, whether it's
quantum-vulnerable, and whether it meets policy (default floor:
RSA-2048, EC-256, TLS 1.2; bans 3DES/DES/RC4/NULL/EXPORT/MD5/anon). Findings become
KindCryptoAsset nodes in the credential graph, feeding
blast-radius and compliance reporting and the
PQC migration. Scanning runs in its own bounded lane, is
non-fatal per source, tenant-isolated at the database layer, and keeps TLS/cert parsing
behind the single crypto path.
Status: served. POST /api/v1/cbom/scans (discovery:write, accepts an
Idempotency-Key) runs the scanner in the serving binary and records each observation
as an immutable cbom.asset.observed event before the read model projects it. GET /api/v1/cbom/assets (risk:read) returns the tenant-scoped inventory plus migration
progress. CBOM work has its own bulkhead, so a wide TLS/config sweep rejects fast
instead of starving the regular API or enrollment lanes.
Each returned asset includes the discovered algorithm, source, policy result, PQC posture, and a migration target:
| Observation | Migration target |
|---|---|
| RSA, ECDSA, Ed25519/EdDSA certificate signatures | ML-DSA-65 (FIPS 204) |
| DSA certificate signatures | SLH-DSA-SHA2-128s (FIPS 205) |
| TLS protocol/cipher findings such as TLS 1.0 or 3DES | ML-KEM-768 (FIPS 203) |
| Already quantum-safe ML-DSA, ML-KEM, or SLH-DSA observations | marked post-quantum-ready |
migration_progress is computed from the stored inventory: total assets, how many are
post-quantum-ready or quantum-vulnerable, and the ready percentage.
Core PQC campaigns turn those observations into owned work without requiring a
licence. From /posture, /api/v1/pqc/campaigns, or trstctl-cli pqc campaigns, an
operator can assign owner/deadline/wave/readiness, record a manual or third-party
remediation for each finding, and close only after every finding has evidence. Closure
produces an offline-verifiable signed artifact. Automated fleet execution remains an
optional Enterprise executor and is stated as unavailable by edition; campaign
tracking itself does not degrade into an upsell-only shell.
In the console
The overview dashboard surfaces a severity-ranked alert center from served risk and
certificate-expiry events (no dedicated alerts endpoint — a projection of events the
backend already serves); /risk renders a risk-posture summary (counts by band,
orphaned credentials, average score) above the scored-credential grid. /notifications
serves routing-policy authoring and channel-test delivery; scheduled digest delivery
stays outside the served workflow. See The web console.
Use it
Find your riskiest credentials:
# rotate-this-first: high-privilege, score >= 50
trstctl-cli risk credentials --min_score 50 --privilege high --sort score
# blast-radius priority list with CBOM context + recommended action
trstctl-cli risk contextual-priorities
# NHI posture: overprivilege, stale, static-credential, and exposure findings
trstctl-cli nhi posture overprivilege
trstctl-cli nhi posture stale
trstctl-cli nhi posture static-credentials
trstctl-cli nhi posture exposure
Those map to GET /api/v1/risk/credentials?sort=score&min_score=50&privilege=high,
GET /api/v1/risk/contextual-priorities, and /api/v1/nhi/posture/*.
CT monitoring has a dedicated watchlist/checkpoint endpoint:
# CT-log monitoring: configure watched domains/logs and queue a poll.
trstctl-cli discovery ct-monitoring update --body ct-monitoring.json
trstctl-cli discovery ct-monitoring get
trstctl-cli discovery findings list --run_id "$RUN_ID"
ct-monitoring.json carries the watchlist:
{
"name": "public-ct-watch",
"logs": ["https://ct.example.test/log"],
"watched_domains": ["example.com"],
"max_batch": 25,
"run_now": true
}
Drift reuses the source/run/finding path, plus a remediation decision view:
{
"name": "edge-cert-drift",
"kind": "drift",
"config": {
"watched": [
{
"path": "/etc/nginx/tls/edge.crt",
"class": "certificate",
"fingerprint": "sha256:...",
"mode": "0644"
}
]
}
}
# list drift remediation rows and record an operator decision
trstctl-cli discovery drift-remediation
trstctl-cli discovery drift-remediation decide "$FINDING_ID" --body drift-decision.json
{
"decision": "investigate",
"reason": "rotate certificate on the affected host before accepting the new fingerprint",
"owner": "platform",
"tags": ["rotation-ticket"]
}
CBOM scan:
curl -sS \
-H "Authorization: Bearer $TRSTCTL_TOKEN" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: cbom-demo-001" \
-X POST https://trstctl.example.com/api/v1/cbom/scans \
-d '{
"tls_endpoints": ["payments.internal.example:443"],
"host_configs": ["/etc/nginx/sites-enabled/payments.conf"]
}'
Then read the migration inventory:
curl -sS \
-H "Authorization: Bearer $TRSTCTL_TOKEN" \
https://trstctl.example.com/api/v1/cbom/assets
The response contains items and migration_progress; a non-empty
quantum_vulnerable count means crypto needs a migration target.
Pitfalls & limits
| Capability | Status today |
|---|---|
| Credential risk scoring (F19) | Served — /api/v1/risk/credentials, /api/v1/risk/contextual-priorities, and the four /api/v1/nhi/posture/* routes above, plus risk/nhi posture CLI |
| CT monitoring (F17) | Served — CT watchlist/checkpoint API, CLI, Posture UI, plus Discovery ct_log execution and outbox-backed alerts |
| Drift detection (F18) | Served — Discovery drift execution, outbox-backed alerts, remediation API/CLI/Posture dashboard, and event-sourced decisions |
| CBOM (F52) | Served — /api/v1/cbom/scans, /api/v1/cbom/assets, core /api/v1/pqc/campaigns, event-backed inventory + signed campaign closure |
Other notes: CT monitoring depends on the logs/domains you list. Drift permission detection is best-effort where the ACL model can't be fully read — the agent says so rather than giving false assurance. The CBOM is only as complete as the sources you point it at (TLS endpoints + config files). See Current limitations for the served-vs-library picture.
Reference
- Served:
GET /api/v1/risk/credentials(paramssort,min_score,privilege,owner);GET /api/v1/risk/contextual-priorities; CLIrisk credentials,risk contextual-priorities. - Risk factors: age, exposure, privilege, rotation staleness, owner activity, sensitivity (weighted; defaults favor exposure + privilege).
- CT: Discovery source kind
ct_log; finding kindct_unexpected_issuance; idempotency keyct:<log>:<index>; RFC 6962. - Drift: Discovery source kind
drift; finding kindcredential_drift; drift typesDeleted,Replaced,Relocated,PermissionChanged; remediation routesGET /api/v1/discovery/drift-remediationandPOST /api/v1/discovery/drift-remediation/{id}/decision. - CBOM API:
POST /api/v1/cbom/scans(discovery:write,Idempotency-Keyrequired);GET /api/v1/cbom/assets(risk:read). - CBOM policy floor: RSA-2048, EC-256, TLS 1.2; bans 3DES/DES/RC4/NULL/EXPORT/MD5.
- CBOM event/read model:
cbom.asset.observedprojects intocrypto_assets; rebuilds/snapshots replay the same inventory.
See also
Discovery & inventory (what feeds these) · Graph, query & AI (exposure / blast radius) · Lifecycle & PQC (migrating off weak crypto the CBOM finds) · Policy & governance (compliance reporting) · glossary: Certificate Transparency, drift, CBOM, PQC
Covers: F17, F18, F19, F52