A ctlplne studio product

Platform & API — how you drive trstctl, and how it runs

What it is

This page covers the platform plumbing — the surfaces you use to operate trstctl and the properties of how it runs: the REST API, the CLI, the web UI, OIDC/SAML/LDAP sign-on, SCIM 2.0 provisioning, RBAC plus ABAC authorization, single-binary distribution, encrypted transport, multi-tenant topology, and federation. Not glamorous, but this is what makes trstctl usable, secure, and operable in a real organization.

The mental model: if the feature pages are the appliances, this is the wiring, the breaker box, the front door lock, and the meter — the infrastructure that lets everything else run safely on shared premises.

Why it exists

A control plane is only as good as how you interact with it and how safely it runs. You need a programmable API for automation, a CLI for scripts and CI, a UI for humans, SSO so people log in with existing accounts, encrypted channels so nothing is sniffable, hard tenant isolation so customers can't see each other, and a distribution simple enough to actually deploy. These are the table-stakes properties an enterprise checks before it trusts a platform with its credentials.

How it works

The REST API (F10)

The API is data-driven: every route is declared once in a single registry that simultaneously generates the served http.ServeMux, the OpenAPI 3.1 document (served at /api/v1/openapi.json), the CLI command table, and the Terraform provider route constants for its managed resources — so the spec, the server, the CLI, and the infrastructure-as-code surface can't drift apart. Errors are RFC 7807 application/problem+json. Every mutation requires an Idempotency-Key, recorded in PostgreSQL so a retry returns the original result instead of applying the change twice. Tenant comes from the authenticated principal (so one tenant can never act on another's data), pagination uses opaque cursors, and over-budget callers get 429 with Retry-After. Every guarded route checks RBAC first; when auth.abac.enabled is configured, a deny-only ABAC overlay can then block the request using route, actor, environment, and time attributes. Served.

The CAP-API-07 receipt: the served POST /api/v1/identities/{id}/transitions route requires an Idempotency-Key, appends the lifecycle event once, and binds the matching ca.issue outbox row to that same key so a retry returns the first result instead of minting or dispatching twice. Webhook eventing uses the same spine: operators author channels at /api/v1/notification-channels, test a channel through POST /api/v1/notification-channels/{id}/test, and expiry or response alerts enqueue notification outbox work before the dispatcher delivers the signed webhook.

The CLI (F11)

trstctl-cli is the API's twin: every command is a row in a table that maps trstctl-cli <group> <verb> straight to an API route, so the CLI is provably at parity with the API and carries no bespoke logic. It auto-supplies idempotency keys on mutations. The command groups span the full route surface — from owners, identities, certificates, and secrets through discovery, nhi, breakglass, graph, risk, managed-keys, transit, ai, and mcp — see the CLI reference for the complete table. Served (binary).

Terraform provider

terraform-provider-trstctl is built with the standard HashiCorp Terraform plugin framework and ships as a normal trstctl binary. It manages certificate profiles through POST /api/v1/profiles, issues short-lived certificates through POST /api/v1/secrets/pki, and manages application secrets through /api/v1/secrets/store. Each mutation sends an Idempotency-Key, uses the same bearer token and tenant headers as the CLI, and is backed by provider tests plus a real Terraform apply acceptance test. See Terraform provider. Served (binary).

The web UI (F12)

The UI is a React 18 + Vite + shadcn/ui single-page app served by the binary from an embedded filesystem on the same port and TLS certificate as the API. Real hashed asset files are served directly, deep links fall back to the SPA, and /api/* stays owned by the API handler. No separate static server is required. Served. The embedded index.html references the real Vite bundle, and tests fail if a clean build regresses to the placeholder.

The console is organized as a space rail over scoped sidebars — Certificate Lifecycle, Machine & Workload Trust, Secrets & Access, Software Trust, and Trust Operations each own one operator mental model, with Home carrying the cross-space dashboard, journeys, and worklists. These are views over one API, tenant boundary, event stream, owner directory, alert service, policy system, and audit chain; they are not separate backends. Every served capability across these feature pages has a screen behind it: the certificate command center, the secrets workspace, non-human-identity governance, discovery, the PQC posture gauge, the compliance and audit surfaces, the privacy (/privacy) governance console, and the integrate (/integrate) hub that hands you copyable ACME / EST / SCEP enrollment URLs, the language SDKs, and the Terraform / cert-manager / SPIRE integrations. Navigation is RBAC-gated and one row per route, and every label resolves through the typed i18n catalog. The full route-to-screen map is The web console. Served.

OIDC, SAML, and LDAP / Active Directory sign-on (F13)

OIDC stays in the Free core. Tenant SAML and LDAP require Enterprise SSO, which Provider inherits. All enabled methods compose into the same tenant-scoped session and authorization path; enabling one does not replace another.

People log in through OIDC (OpenID Connect), SAML 2.0, or LDAP / Active Directory against a standards-compliant provider. OIDC uses the authorization-code flow with random state (CSRF protection) and a mandatory nonce (replay protection); the returned id*token is verified — signature (via JWKS through the single isolated cryptography path), issuer, audience, expiry, nonce — before session issue. SAML serves a Service Provider at /auth/saml/metadata, starts SP-initiated login at /auth/saml/login, and accepts signed POST-binding assertions at /auth/saml/acs; IdP metadata and XML signature verification stay behind the same isolated cryptography boundary. LDAP / Active Directory mounts POST /auth/ldap/login, binds the user to the directory, searches directory groups, and maps those groups to tenant roles. All three paths mint the same short-lived, HMAC-signed, HttpOnly+Secure session cookie and resolve the verified subject, tenant claim, or groups through the same per-user tenant-mapping table. CI/CD instead uses API tokens (trst*-prefixed, only the SHA-256 hash stored). Served when auth.oidc.enabled, auth.saml.enabled, or auth.ldap.enabled is configured, with Enterprise SSO required for SAML and LDAP. API tokens remain the zero-dependency auth path when SSO is disabled; an enabled-but-incomplete OIDC, SAML, or LDAP block fails closed at startup.

Operators can start from the per-IdP OIDC runbooks for Keycloak, Authentik, Okta, Auth0, Microsoft Entra ID, and Google Workspace. Those pages use the real TRSTCTL_AUTH_OIDC_* settings, including PKCE S256, authorization response iss validation, back-channel logout, and the encrypted tenant-scoped credential-store reference for confidential-client secrets.

SCIM 2.0 provisioning

Directory provisioning requires Enterprise SSO and is served under /scim/v2 when auth.scim.enabled is on. An IdP such as Okta or Microsoft Entra sends a tenant-bound bearer token to /scim/v2/Users and /scim/v2/Groups; trstctl hashes the configured token file at startup and keeps only the hash in memory, reading the file again within two seconds of a change, so rotating a token is rewriting its file. The token chooses the tenant before any payload is read, so a SCIM request cannot smuggle a tenant id in its JSON body.

Each token also selects the login-subject attribute: userName by default, or explicit externalId when the trusted IdP mapping supplies the exact login subject there. Both provisioning identifiers are retained. The selected value is the immutable resource id; it is never inferred from an email. See SCIM identity mapping before onboarding.

SCIM users project into the same tenant-member read model used by RBAC. Creating or updating a user appends a tenant-member upsert event; active:false or DELETE appends an offboarding event. SCIM groups map to existing RBAC role names: a group named viewer gives its members the viewer role, and removing a member removes that role. Any other group needs the token's group_roles entry naming the built-in or tenant custom role it grants (custom roles); an unmapped group, or one mapped to a custom role the tenant has not defined, is refused and grants nothing. Group cleanup preserves offboarding; a group addition cannot reactivate an inactive user. Browser sessions consult the current tenant-member roles on each API request, so SCIM provisioning and deprovisioning change real authorization, beyond an admin list. Supported IdP operations are SCIM Users create/get/list/put/patch/delete and Groups create/get/list/patch/delete. Served with Enterprise SSO and auth.scim.enabled configured.

Home's expanded metrics distinguish loading or unavailable reads from verified zero counts. Inventory, alert summaries, certificate charts, renewal trends, and risk ordering show their own source failures and an explicit retry. Independent permitted reads remain visible. A refused certificate or risk feed cannot become an empty estate or a claim that no alerts exist.

Evidence for denied API permissions

An authenticated API request that lacks its route permission is refused with 403. The server also attempts to append an authz.decision event containing the verified tenant, caller, missing permission and registered route pattern. It does not copy request bodies, query strings or bearer credentials into that event.

This evidence path has its own bounded admission budget: by default 1,200 attempts per minute per API process, 300 per tenant, 120 per client address and 60 per authenticated subject within a tenant. At most 8 appends run at once, with no waiting queue and a one-second context deadline. These limits do not consume the login/enrollment budget. Existing special-route limit overrides also configure this separate budget. Floods cannot turn an access denial into an allowed request.

The 403 response's X-Trstctl-Audit-Status header is recorded when the append was confirmed, rate_limited when its admission budget is exhausted, busy when all append slots are occupied, or unavailable when no confirmed append is available. An append can commit just before a timeout; unavailable does not prove an event is absent. Only missing-route-permission decisions after authentication, tenant, CSRF and target-scope validation enter this path. Other rejections, including invalid credentials, conflicting tenant headers and invalid CSRF tokens, are outside it. Handler-specific and ABAC decisions retain their own evidence paths. Do not infer complete recording of every rejected request from a successful export.

The console's shared query layer stops automatic retries, live polling and visibility/reconnection refresh for a read refused with 401 or 403. It also hides the last allowed result after that refusal. An explicit refresh or a new page navigation can check access again; an authorized successful read resumes normal polling. Home shows unavailable renewal and audit evidence separately from a verified empty result. Ask an administrator to restore the required permissions, then check again, or sign in with an authorized account.

Single-binary distribution (F14)

For evaluation, the one trstctl binary can supervise its own datastores: bundled PostgreSQL (downloaded once, checksum-pinned, run on loopback) and embedded, file-backed NATS JetStream. Bundled PostgreSQL is allowed only for host archives with committed runtime pins in deploy/supply-chain/embedded-postgres.json (summarized in Supply chain) (linux-amd64, linux-arm64v8, darwin-arm64v8 today), and startup fails closed if the archive is unsupported, unpinned, or hash-mismatched. Even bundled, Postgres runs under the non-superuser trstctl_app role so row-level security still applies — per-tenant isolation is enforced at the database layer even for eval, not relaxed. The signing service is always a separate supervised child process, never in-process — private-key operations stay in their own isolated service. For production, flip Postgres/NATS to external. Served (binary).

The CAP-MODEL-01 receipt (Self-hostable, run-anywhere): the served GET /api/v1/platform/distribution route and trstctl-cli platform distribution command return the self-hostable run-anywhere posture directly from the product. The receipt lists the host-archive eval path, Docker Compose eval path, Kubernetes/Helm path, and external-datastore production path; supported host archives (linux-amd64, linux-arm64v8, darwin-arm64v8); the embedded-PostgreSQL runtime pin; release gates such as make lint test, embedded-Postgres scan receipts, OpenAPI/CLI route parity, and the architecture linter; and the editions guard that offline license verification plus audit/export stay in core.

The CAP-MODEL-03 receipt (Air-gapped / on-prem + data residency): the same served GET /api/v1/platform/distribution route and trstctl-cli platform distribution command return an air_gap receipt. It lists TRSTCTL_AIRGAP_ENABLED, TRSTCTL_AIRGAP_ALLOW_PRIVATE, TRSTCTL_AIRGAP_ALLOW_HOSTS, TRSTCTL_AIRGAP_ALLOW_CIDRS, values-airgap.yaml, operator-owned PostgreSQL and NATS endpoints, and the offline transfer bundle with checksums. The receipt also points to docs/airgap.md, scripts/airgap-bundle.sh, the Helm air-gap overlay, and internal/server/airgap_served_test.go, whose served integration path proves certificate issuance plus native-secret create/rotate with zero public egress after a synthetic public-endpoint tripwire proves the runtime guard is armed.

Encrypted control-plane transport (F15)

Every channel is encrypted. By default the signing service is reached over a Unix domain socket with SO_PEERCRED peer-uid authentication (a 0600 socket; a different uid is rejected); across nodes it is reached over mTLS (TLS 1.3, AEAD-only, the control plane and signer each pinning the other's certificate). Either way the signing service has no HTTP server and no SQL driver — it stays a separate, isolated process — and at startup it disables core dumps and ptrace so secret material can't be read out of its memory. The REST API/UI is served over TLS (self-signed by default for instant start, operator cert in production, TLS 1.3, AEAD-only). Agents connect over mTLS with short-lived, auto-rotated client certificates. The KMIP listener, when enabled, is also TLS 1.3 mutual TLS and verifies client certificates against TRSTCTL_PROTOCOLS_KMIP_CLIENT_CA_FILE. All TLS/x509 code lives behind the single isolated cryptography path. Served.

Note: the default signer channel is a peer-authenticated UDS (co-located/sidecar); the cross-node channel is mutually-authenticated, mutually-pinned mTLS.

Multi-tenant topology (F40 / CAP-IAM-02)

Isolation between tenants is enforced by PostgreSQL itself, not by application code — one tenant can never read another's data, and that guarantee lives at the database layer. Every table carries a tenant_id and has row-level security that denies all rows when the tenant context is unset (fail-closed). WithTenant drops to the non-superuser role and sets the tenant for the transaction, so every query is confined automatically — and a custom build check fails the build if any repository query omits the tenant filter. A single-company deployment runs one tenant. Each tenant can also keep its encryption under its own key domain, which it can migrate into, seal, unseal, and rotate without touching other tenants (see secrets).

Managed offering / SaaS provider plane (CAP-MODEL-02)

trstctl also serves the provider-plane path needed for a managed or SaaS offering. A Provider-tier license enables provider_plane; without it, the status endpoint is still readable but tenant provisioning fails with 403. Provider operators can inspect posture with GET /api/v1/managed-offering/status or trstctl-cli managed-offering status (including tenant_band and managed_tenants_registered, the hosted tenants the band already holds), then create a hosted tenant with:

trstctl-cli --idempotency-key hosted-acme-create-001 \
  managed-offering tenants provision -f hosted-tenant.json

hosted-tenant.json carries only non-secret topology facts:

{
  "tenant_id": "33333333-3333-4333-8333-333333333333",
  "name": "Acme Hosted",
  "region": "us-east-1",
  "data_residency": "US",
  "plan": "enterprise",
  "support_tier": "24x7",
  "slo_tier": "99.95"
}

The mutation is idempotent like every other state change. It emits tenant.registered for the hosted tenant and includes managed_offering metadata in the immutable event payload (provider_tenant_id, region, residency, plan, support tier, SLO tier, and actor). The projector then builds the tenant row from that event, so the hosted tenant receives its own PostgreSQL RLS boundary immediately. No managed-service token, customer secret, or billing credential belongs in this request; those use the normal tenant-scoped secret/API-token/session paths.

In the console, open System health → Exceptions → Managed offering. An operator with access:write and an enabled Provider license can review the customer, placement and service details before provisioning. Region, residency and service fields record metadata; this operation creates the isolated tenant, without deploying or relocating customer infrastructure. Configure the customer's access and credentials through the team onboarding journey.

If the result is uncertain, keep the original request and retry key. The console saves pending provisioning requests for the signed-in tenant and operator in this browser. After a reload, choose the saved request and Retry unchanged request. A saved request is recovery information; only the server's returned registration event confirms that the tenant was created. Changing the account, customer details or retry key does not resume the original operation.

For CLI/API retries, preserve the same request body, authenticated operator and Idempotency-Key. In the example above, retry hosted-acme-create-001 unchanged. A new key can conflict with a registration already in progress. Keep the key with the request until its result is confirmed; do not generate a new key for every retry. The console's saved requests contain the provisioning metadata and request key, with no session token or customer credential. Clearing this site's browser data removes those local records.

The console also sends the reviewed provider tenant as X-Tenant-ID and the reviewed operator subject as X-Trstctl-Expected-Subject (percent-encoded, as with JavaScript encodeURIComponent). These are assertions, not credentials. A tenant mismatch is refused with 403 and an operator mismatch with 409 before creation or cached replay; an empty, duplicate or malformed subject assertion is refused with 400. The subject assertion requires X-Tenant-ID. Requests carrying a browser session cookie must include both assertions; an older console receives 409 and must reload. API clients without a browser session cookie may omit them and use their normal authenticated account. If another browser tab changes the account, sign in with the original account before resuming its saved request.

The public packaging boundary has three tiers — Free (self-hosted BUSL-1.1 core), Enterprise (the commercial ee/ set, per control-plane deployment), and Provider/MSP, which inherits Enterprise, adds provider-plane operation, and grants managed-service and resale rights with dedicated-deployment flexibility. The tier matrix and commercial posture live in Editions. Every path uses the same event-sourced, PostgreSQL-RLS-isolated binary lineage; none moves tenancy, audit/export, crypto, or license verification into ee/.

High-volume orchestration (CAP-SCALE-01)

trstctl serves a scale-orchestration posture for 100,000 to 1,000,000+ managed credentials. GET /api/v1/scale/orchestration and trstctl-cli scale orchestration expose the same plan:

  • credential bands for 100k, 250k, and 1M managed credentials;
  • the selected CAP-LARGE tier from the committed capacity model;
  • hot-path SLOs, release gates, and required measurement artifacts;
  • execution lanes for issuance, inventory, graph/risk, revocation, signer, and projection replay;
  • the bounded queues, bulkhead environment knobs, backpressure signals, replay source, and AN-* architecture invariant for each lane;
  • the shard plan for inventory pages, CRL shards, and projection batches;
  • explicit residuals for customer infrastructure costs, external relying-party CRL adoption, and remote CI behavior.

This endpoint is read-only and guarded by access:read. It does not count a vendor SKU or customer CDN as product-owned serving evidence. Instead it turns the already committed performance and capacity denominator into an operator-visible execution plan tied to scripts/perf/artifacts/smoke-baseline.json, scripts/perf/artifacts/live-load-baseline.json, and the soak gate. The Platform page renders the same plan with the served lane/gate/band tables.

Multi-region HA issuance (CAP-SCALE-02)

trstctl serves a regional HA issuance reference architecture at GET /api/v1/scale/ha-issuance and trstctl-cli scale ha-issuance. The response sets evidence_scope: reference_architecture. Its named regions are examples, not discovered deployment members; served: true confirms the route is available, not that this installation has active regional HA. In the model, multiple regions can accept issuance traffic, but every tenant mutation still commits through a fenced writer plane with the same idempotency record, event append, transactional outbox, leader election, and isolated signer boundary.

The endpoint returns:

  • example issuance regions, their writable scope, signer placement, datastore/event-log posture, and health signals;
  • tenant write fences for idempotency, event-log append, outbox side effects, leader-owned workers, and signer isolation;
  • regional issuance lanes for API, agent renewal, and protocol enrollment traffic;
  • failover steps and release gates for regional smoke, failover drills, idempotency replay, and the architecture linter;
  • RPO/RTO targets of 5 seconds and 30 seconds, not measurements, plus residuals for customer DNS, ingress, datastore promotion, signer/HSM latency, and external CA provider limits.

This fits beside F41 federation. Federation gives a passive region replayable read state from peer event import. CAP-SCALE-02 describes active regional issuance ingress that requires a healthy shared or promoted writer endpoint, replicated JetStream event log, idempotency table, outbox, and signer. Qualify a real installation with regional issue/renew/revoke smoke and a multi-host failover drill before claiming HA or the target recovery times. If write fences degrade, issuance must fail closed instead of minting from two independent writers.

Enterprise support, SLAs, and professional services (CAP-MODEL-04)

trstctl serves an Enterprise support posture endpoint so an operator can inspect the standard support packages without relying on static sales copy. The GET /api/v1/support/enterprise API and trstctl-cli support enterprise return:

  • the live ha_support license mode (enabled, read_only, or off);
  • the business-hours and 24x7 production support tiers;
  • P1, P2, and P3 response/update SLA targets;
  • deployment-architecture, migration-readiness, and credential-incident-retainer professional-services packages;
  • the explicit contract boundary: commercial support terms control legal SLA credits, named contacts, and any customer-specific restoration target.

The endpoint is read-only and guarded by access:read. It does not call an external support system, write an outbox row, or mint a customer secret. Its job is to expose the served product posture and standard Enterprise package catalog, while a signed license and commercial agreement decide whether support is active for the deployment. The Platform page renders the same data beside Editions and the managed-offering controls.

Federation (F41)

Cross-cluster / multi-region federation imports peer event logs into the local event log, then projects those imported events through the same read-model projector as local writes. That gives a passive region the same tenant registry, trust issuers, certificate inventory, audit facts, and other replayable read state without adding another datastore or copying PostgreSQL tables directly. Imported events keep their original event id, timestamp, tenant id, payload, actor, and schema version, so retries are duplicate-safe and the target region can rebuild from its own local log after failover.

The worker is off until an operator enables it. It runs under the existing leader election, so one control-plane replica imports a peer while every replica can serve the replicated read state. The peer cursor is durable per source cluster; a restart resumes from the last imported source sequence. A typical passive region points at the primary region's external NATS URL:

export TRSTCTL_FEDERATION_ENABLED=true
export TRSTCTL_FEDERATION_CLUSTER_ID=us-west-passive
export TRSTCTL_FEDERATION_REGION=us-west-2
export TRSTCTL_FEDERATION_PEER_ID=us-east-primary
export TRSTCTL_FEDERATION_PEER_REGION=us-east-1
export TRSTCTL_FEDERATION_PEER_NATS_URL=nats://nats.us-east.example:4222
export TRSTCTL_FEDERATION_INTERVAL=1s
export TRSTCTL_FEDERATION_RPO=5s
export TRSTCTL_FEDERATION_RTO=30s

The RPO target is the maximum import polling gap plus the health of the peer's replicated JetStream stream. The RTO target is the time for the passive region to finish local projection and accept traffic after you move clients or ingress. See Configuration and Run in production.

Use it

# the API spec (no auth needed) — point your tooling at it
curl -s https://trstctl.example.com/api/v1/openapi.json

# drive it from the CLI
trstctl-cli certificates list --limit 50
trstctl-cli audit events --type cert.issued --since 2026-01-01T00:00:00Z
trstctl-cli platform distribution

# one-binary evaluation: bundled datastores, supervised signer
TRSTCTL_POSTGRES_MODE=bundled TRSTCTL_NATS_MODE=embedded ./trstctl

The web console, browser /auth/login flow, SCIM /scim/v2 provisioning surface, REST API, and CLI all drive the same served control plane. API tokens are still the zero-dependency bootstrap path; OIDC, SCIM, and the ABAC deny overlay turn on only when configured; tenant SCIM additionally requires Enterprise SSO. See Current limitations, Install, and Configuration for production setup.

Pitfalls & limits

  • Federation is passive-read-state replication — run one writable region for a tenant at a time, then promote a passive region during failover after its peer cursor and projection lag are inside your RPO/RTO target.
  • TLS defaults to self-signed for instant start; set an operator cert (TRSTCTL_SERVER_TLS_MODE=file) for production. Plaintext mode requires TRSTCTL_DEV_ALLOW_PLAINTEXT=true and a loopback bind, so it is mechanically local-dev bounded.
  • Bundled datastores are for evaluation; run external PostgreSQL and NATS in production.
  • The signer is a separate process by design — don't try to collapse it in; keeping private-key operations in their own isolated process is a security boundary.

Reference

  • API: OpenAPI 3.1 at GET /api/v1/openapi.json; RFC 7807 errors; Idempotency-Key on mutations; cursor pagination; 429 + Retry-After; authenticated REST JSON request bodies are capped at 1 MiB and reject trailing JSON tokens.
  • CLI groups: one group per API route family (owners, identities, certificates, secrets, discovery, nhi, breakglass, graph, risk, managed-keys, transit, ai, mcp, and the rest) — complete table in the CLI reference.
  • Auth: /auth/login, /auth/callback, /auth/me, /auth/logout (OIDC when auth.oidc.enabled is on); /auth/saml/login, /auth/saml/acs, and /auth/saml/metadata (SAML when auth.saml.enabled is on); POST /auth/ldap/login (LDAP / Active Directory when auth.ldap.enabled is on); API tokens prefixed trst_. Config: TRSTCTL_AUTH_OIDC_ISSUER, TRSTCTL_AUTH_OIDC_CLIENT_ID, TRSTCTL_AUTH_OIDC_REDIRECT_URI, TRSTCTL_AUTH_OIDC_CLIENT_SECRET_TENANT, TRSTCTL_AUTH_OIDC_CLIENT_SECRET_REF, TRSTCTL_AUTH_SAML_ENTITY_ID, TRSTCTL_AUTH_SAML_ACS_URL, TRSTCTL_AUTH_SAML_IDP_METADATA_FILE, TRSTCTL_AUTH_LDAP_URL, TRSTCTL_AUTH_LDAP_GROUP_FILTER.
  • SCIM provisioning: GET /scim/v2/ServiceProviderConfig, /scim/v2/Users, and /scim/v2/Groups when auth.scim.enabled is on. Config: TRSTCTL_AUTH_SCIM_ENABLED, TRSTCTL_AUTH_SCIM_TOKEN_TENANT_ID, TRSTCTL_AUTH_SCIM_TOKEN_FILE.
  • Authorization overlays: RBAC on every guarded route; ABAC deny overlay when auth.abac.enabled is on. Config: TRSTCTL_AUTH_ABAC_ENABLED, TRSTCTL_AUTH_ABAC_MODULE, TRSTCTL_AUTH_ABAC_ENVIRONMENT.
  • Run modes: TRSTCTL_POSTGRES_MODE (bundled/external), TRSTCTL_NATS_MODE (embedded/external), TRSTCTL_SERVER_TLS_MODE (internal/file/disabled).
  • Distribution posture: GET /api/v1/platform/distribution and trstctl-cli platform distribution expose CAP-MODEL-01 self-hostable run-anywhere evidence receipts and CAP-MODEL-03 Air-gapped / on-prem + data residency receipts.
  • Federation (F41): event-log import with durable peer checkpoints, duplicate-safe event identity, and local read-model projection.

See also

The web console (every served surface in the browser) · Policy & governance (RBAC + audit) · Install · Configuration · Signing-service design · Current limitations · glossary: idempotency, mTLS, RLS, multi-tenancy

Covers: F10, F11, F12, F13, F14, F15, F40, F41

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