trstctl /docs GitHub ↗
   __            __       __  __
  / /___________/ /______/ /_/ /
 / __/ ___/ ___/ __/ ___/ __/ /
/ /_/ /  (__  ) /_/ /__/ /_/ /
\__/_/  /____/\__/\___/\__/_/

the keys to your infrastructure,
  kept in your infrastructure

Self-hosted control plane for every credential that isn't a human —
discover, issue, deploy, rotate, revoke, and retire X.509 certificates, SSH certs, secrets,
API keys, and SPIFFE workload identities. Private keys stay in an isolated process; you host it all.

CI tag Go Report Card Go status license

60-second version · Why · What it answers · Capabilities · How it's built · Try it · Docs · License

New here? Start with the feature index (all 78 capabilities, each with a deep-dive page) and the glossary (every term defined for a zero-knowledge reader). The docs are written so a complete beginner and a domain expert both get value.

Status — active development. A core slice is served end to end by the running binary today (certificate inventory, real X.509 issuance, the credential graph, risk scoring, OIDC login, the hash-chained audit log, observability, resilience, backup/DR, migrations). Much of the broader surface is library-complete and tested but not yet wired into the served binary. Each feature page states its own status, and Current limitations is the single authority on what runs end to end versus what is library code. The license is intentionally TBDsource-available, not open-source (yet) (details).


The 60-second version

Imagine a large building. Every door has a lock, and every person, robot, and delivery cart needs the right key — keys that should expire, be re-cut on schedule, and be revoked the moment one is lost. Now imagine nobody keeps a master register of the locks and keys. That's machine-credential management at most companies today.

trstctl is the master key register and the locksmith and the courier. It walks the building to find every lock and key (discovery), cuts and stamps new keys (issuance), drives them to the right doors (deployment), re-cuts them before they wear out (rotation), cancels lost ones (revocation), and keeps a tamper-proof log of everything (audit) — for the machine world, where the "keys" are certificates, SSH certs, secrets, tokens, and workload identities.

For experts: it's an event-sourced, multi-tenant control plane for the full non-human-identity (NHI) lifecycle — X.509, SSH, secrets, and SPIFFE — with private-key operations isolated in their own process and all cryptography behind a single, swappable boundary. Skip to How it's built.

Why trstctl

Machine and workload identities now outnumber human ones by orders of magnitude, and most teams manage them with a different tool for each kind: one product for TLS certificates, another for secrets, something else for SSH, and a closed, SaaS-only suite for the enterprise features on top. The result is no single inventory, no shared ownership model, no consistent rotation — and, worst of all, no one view of blast radius (what else is exposed) when a credential leaks. You find out at 2 a.m., a certificate has expired on a server nobody remembered, and the outage is already happening.

Three choices set trstctl apart:

  • It stays yours. Self-hosted on infrastructure you control; usage telemetry is opt-in, off by default, and never includes credential content. No credential data ships to a vendor cloud.
  • It's one model for everything. Every non-human credential is a node in a single graph of owners, issuers, identities, and the targets they're deployed to — so discovery, lifecycle, policy, risk, and audit work the same way for a TLS cert, an SSH key, and a database password.
  • It's multi-tenant to the core. Every row carries a tenant and is isolated by the database itself (not by application code), so one deployment safely serves many hard-isolated teams or customers. A single-org install is just the one-tenant case — no separate code path to drift out of sync.

What it answers

trstctl is organized around the questions operators actually ask:

  • "What certificates, keys, and secrets do we even have — and which expire this week?"discovery & inventory + lifecycle.
  • "If this key leaks, what else is exposed?" → the credential graph's blast radius (graph, query & AI).
  • "What should we rotate first?" → composite risk scoring (observability & risk).
  • "Who is allowed to issue — and can the requester quietly self-issue?" → RBAC + the registration-authority split (policy & governance).
  • "Where are we still using weak or quantum-vulnerable crypto?" → the CBOM (Cryptographic Bill of Materials) (observability & risk).
  • "Did someone get a certificate in our name that we didn't request?"Certificate Transparency monitoring (discovery & inventory).

Or ask the built-in assistant in plain English — it answers with cited evidence, grounded in real data and scoped to exactly what the caller may see.

Who it's for

  • Platform & security teams drowning in certificates, keys, and secrets spread across a half-dozen disconnected tools who want one inventory they actually own.
  • Regulated & sovereignty-conscious orgs (finance, healthcare, public sector, critical infrastructure) that need credential automation but cannot send anything to a third-party cloud.
  • MSPs & multi-team orgs — self-host once, serve many hard-isolated tenants from one control plane.

What it does

The same lifecycle, for every credential type:

discover → issue → deploy → rotate → revoke → retire

  • Discover what you already have — scans of the network and filesystem, SSH keys and trust, agentless cloud-certificate enumeration straight from AWS/Azure/GCP APIs, a CBOM with post-quantum posture, and Certificate Transparency monitoring for unexpected issuance.
  • Issue certificates automatically — a built-in ACME server (the protocol that auto-renews certs with no human in the loop), your own private CA (Certificate Authority) hierarchy gated by an m-of-n key ceremony, and the older enrollment protocols existing fleets already speak (EST, SCEP, CMP).
  • Deploy renewed credentials to where they live, through capability-scoped connectors — web servers, load balancers, network appliances, and cloud certificate stores. (The shipped connectors are trusted, in-process code scoped to the capabilities they declare; the WASM sandbox isolates third-party plugins — see the plugin trust model.)
  • Give workloads an identity without planting secrets in them — the SPIFFE Workload API plus attestation (cryptographic proof of what and where a workload is), including a purpose-built broker for AI agents.
  • Manage secrets end to end — a versioned, envelope-encrypted store, dynamic secrets (created on demand and auto-revoked), encryption-as-a-service, and rotation.
  • Understand & respond — a credential graph (reachability and blast radius), composite risk scoring, drift detection, and incident workflows (compromise remediation, just-in-time access, break-glass).

The full catalog — all 78 capabilities, each mapped to its primary docs page — is the feature index.

Capabilities

"Built and tested" means real library code with unit, property, integration, and conformance tests. A core slice is served end to end today; much of the broader surface is library-complete but not yet wired into the served binaryCurrent limitations is the authority on which is which. Every number below is grounded in the repository.

Area What's there
Issuance ACME (+ ARI), private CA hierarchy (m-of-n ceremony, OCSP/CRL), certificate profiles + RA separation, 9 CA integrations
Enrollment EST, SCEP, CMP servers; an embedded/IoT C client; Intune/MDM challenge gating
Workload identity SPIFFE Workload API (X.509 + JWT SVIDs), 6 cloud/hardware attesters, ephemeral issuance, an AI-agent broker
SSH SSH certificate authority + KRL, additive trust agent (validate → reload → health-check → rollback), attestation-gated user certs
Secrets envelope-encrypted store, 7 dynamic-secret backends, transit + KMIP, PKI-as-a-secrets-engine, rotation, secret sync (7 targets)
Deployment 13 production connectors (web servers, load balancers, appliances, cloud cert stores), an example connector harness, plus Kubernetes
Discovery & posture network/filesystem, SSH, agentless cloud certs (AWS/Azure/GCP), CBOM + PQC posture, CT monitoring, drift, risk scoring, the credential graph
Key protection 6 HSM/KMS backends (PKCS#11, TPM 2.0, YubiHSM 2, AWS/Azure/GCP KMS), the isolated signer
Crypto-agility classical + post-quantum (ML-DSA, ML-KEM, SLH-DSA, hybrid) behind one boundary, plus a PQC-migration orchestrator
Platform REST API (OpenAPI 3.1), CLI at full parity, web UI with a first-run wizard, OIDC SSO, RBAC, append-only audit, multi-tenancy
Supply chain reproducible builds, cosign-signed images, and an SBOM

How it's built

trstctl is opinionated about architecture from the very first commit, because the properties below are impossible to bolt on later. Eight non-negotiables are enforced by a custom go/analysis linter that fails the build on violation — they aren't guidelines, they're load-bearing walls. Each is in plain terms; the deep mechanism lives in the linked docs.

Principle (in plain terms)
AN-1 Tenants can't see each other — enforced by the database. Every row carries a tenant ID, and PostgreSQL row-level security blocks cross-tenant reads even if the application code has a bug.
AN-2 The truth is an append-only log. State changes are events in NATS JetStream; the regular tables and the audit trail are projections rebuilt from that log — nothing is silently overwritten, and the system can be rebuilt after a disaster.
AN-3 All cryptography lives behind one door. A single package; nothing else may import crypto/*. Adding an algorithm or an HSM is a one-package change — which is how post-quantum support slots in.
AN-4 The signing service is a separate, sacred process. Private keys live in their own address space, reached over gRPC on a peer-authenticated Unix socket — no HTTP server, no SQL driver. If it's compromised, the company is over, so it's treated that way.
AN-5 Idempotency on every change. A retried request can't accidentally mint two certificates.
AN-6 An outbox for every external call. The intent to call out (a CA, a webhook) is written in the same database transaction as the state change, and a worker delivers it at least once — so calls are never lost on a crash.
AN-7 Bulkheads and backpressure. Each subsystem has its own bounded worker pool; one slow connector or a discovery storm can never starve the API.
AN-8 Memory safety for keys. Secret material lives in locked, zeroed []byte, never a Go string (which the garbage collector can copy freely). A key lives in RAM for milliseconds, not indefinitely.
%%{init: {'theme':'base','themeVariables':{'background':'transparent','primaryColor':'#161b22','primaryTextColor':'#e6edf3','primaryBorderColor':'#3b82f6','lineColor':'#768390','clusterBkg':'#161b22','clusterBorder':'#30363d','fontFamily':'ui-monospace, SFMono-Regular, Menlo, monospace'},'flowchart':{'curve':'basis','nodeSpacing':55,'rankSpacing':55,'padding':12}}}%%
flowchart TB
  ui["Web UI"] --> api
  cli["trstctl-cli"] --> api
  agent["In-network agents"] -- mTLS --> api

  subgraph cp["Control plane — Go, event-sourced, multi-tenant"]
    api["REST (OpenAPI 3.1) + gRPC API<br/>OIDC · RBAC · audit · tenant-first"] --> orch["Orchestrator<br/>idempotency · outbox"]
    orch --> log[("Event log — NATS JetStream<br/>source of truth")]
    log --> proj["Projections"]
    proj --> pg[("PostgreSQL<br/>row-level security")]
  end

  orch -- "gRPC over peer-authenticated UDS" --> signer["Signing service<br/>isolated process · holds the keys"]

  classDef store fill:#173404,stroke:#639922,color:#C0DD97
  classDef signer fill:#412402,stroke:#EF9F27,color:#FAC775
  class log,pg store
  class signer signer

Five binaries make this real: trstctl (the control plane, which supervises the signer as a child process), trstctl-signer (the isolated key-holder), trstctl-agent (the in-network worker), trstctl-operator, and trstctl-cli. Under the hood: ~870 Go files across the internal subsystem packages, with property, differential, fuzz, and real-PostgreSQL/NATS integration tests, plus the architecture linter in CI.

Try it

Requires Go 1.25+, Node 22+ (for the web UI), and Docker (for the evaluation stack).

git clone https://github.com/imfeelingtheagi/trstctl
cd trstctl

make build    # control plane, signer, agent, operator, and CLI -> ./bin
make web      # build the React UI into the binary's embed
make test     # unit + property + embedded-PostgreSQL/NATS integration tests
make lint     # gofmt, vet, the architecture linter, and actionlint

Bring up the whole evaluation stack — PostgreSQL, NATS JetStream, and the control plane — with one command. In bundled mode there are no external dependencies: the binary even supervises its own datastores for evaluation.

docker compose -f deploy/docker/docker-compose.yml up --build

The control plane is serving about two minutes later, and issuance itself is a sub-second operation — the end-to-end integration test mints a certificate into inventory in tens of milliseconds (TestAssembledServerIssuesCertIntoInventory, measured ~20 ms). The full first-certificate walkthrough — connect a CA, install an agent, issue a cert — is in Getting started. Script it through the REST API, which publishes its OpenAPI 3.1 spec at /api/v1/openapi.json, or the CLI at full API parity.

What trstctl is not

trstctl is honest about its edges by design:

  • It manages machines, not people. It is not a human IAM/SSO product for your employees' accounts — it uses OIDC to log operators in, and complements your human identity provider rather than replacing it.
  • It is self-hosted, not a SaaS. Nothing phones home; you run it on your own infrastructure.
  • Its AI is grounded and read-only. The assistant answers from cited evidence and never acts on its own; issuance, deployment, and remediation are gated by policy and, where configured, human approval.
  • It is precise about its own maturity. A core slice is served end to end; the rest is library-complete and tested, with the gaps named in Current limitations — never glossed over.

Repository layout

cmd/        # binaries: trstctl (control plane), trstctl-signer (isolated key-holder),
            #           trstctl-agent (in-network worker), trstctl-operator, trstctl-cli
internal/   # subsystem packages: crypto (the one crypto boundary), signing, events,
            #   projections, store, orchestrator, api, ca, protocols/*, secrets..., graph, query, ...
plugins/    # WASM plugin category roots — ca/ and connectors/
tools/      # trstctllint — the architecture linter that enforces AN-1..AN-8
web/        # React 18 + Vite + shadcn/ui UI, embedded into the control-plane binary
deploy/     # docker (compose), helm chart, kubernetes, operator, observability,
            #   supply-chain, windows
clients/    # the embedded / IoT enrollment client (POSIX C)
docs/       # the documentation site (MkDocs) + the reality tests that keep docs honest
test/       # integration harness
scripts/    # developer & release scripts

Documentation

Topic Doc
All 78 features (each with a deep-dive page) docs/features.md
Glossary (every term, zero-knowledge friendly) docs/glossary.md
Getting started (first certificate, fast) docs/getting-started.md
Install / Uninstall (Linux, macOS, Windows, Docker, K8s) docs/install.md · docs/uninstall.md
Configuration (datastores, server, lifecycle, telemetry) docs/configuration.md
CLI (scripting & CI) docs/cli.md
What runs end to end vs. library code docs/limitations.md
Troubleshooting docs/troubleshooting.md
Authoring guides connectors · plugins · profiles · EST
Design & security signing service · threat model
Release history / changelog CHANGELOG.md
Vulnerability disclosure SECURITY.md

Roadmap

The honest axis isn't "phase 1 vs. phase 2" — most of the platform is already built and tested. What remains:

  • Wire the library-complete capabilities into the served binary — the enrollment protocols, connectors, workload identity, and the secrets domain (tracked in Current limitations).
  • Cross-cluster / multi-region federation — event-log replication and credential residency. This one is genuinely not built yet; it's planned, and documented as such in Platform & API.
  • Plugin marketplace maturity for third-party CAs and connectors, on the existing WASM capability host.

Security

If you find a security issue, please report it privately rather than opening a public issue — see SECURITY.md for the disclosure process, supported versions, and contact. Our triage, patch SLA, and advisory process are documented in docs/security/vulnerability-management.md. The product threat model is in docs/security/threat-model.md, and the security-critical signing service has its own design & threat model.

Contributing

trstctl is built sprint by sprint with a tests-first discipline and the architecture linter as a hard gate — make lint test must be green, and the non-negotiables above are not optional. Start with the authoring guides for connectors and plugins. Fuller contribution guidelines are on the way.

License

Source-available — not open-source (yet). The full source is published to read, audit, and self-host, but no open-source (OSI-approved) license has been granted. The license is undecided — no license file is published yet; the specific instrument is still being chosen and will be added here before any public release, and until a license is published, all rights reserved. Nothing is feature-gated today; revenue is intended to come from commercial/enterprise and MSP licensing, support, and a managed offering, not from withholding the platform's capabilities.

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