Issue your first certificate
Goal
When you finish this journey you will have a running trstctl control plane and your first real certificate minted by it, owned, and visible in inventory. It is for anyone evaluating trstctl who wants the shortest path from "nothing installed" to "a signed certificate I can list" — using only the built-in CA, no external issuer, no cloud account. In plain terms: you start a control plane, get a credential to talk to it, name the thing that needs a certificate, flip it to issued, and watch the control plane sign it and record it.
Before you start
- Docker with the Compose plugin, or a Go toolchain if you run from source. The exact prerequisites and the full first-run walkthrough live in Getting started — this journey lifts its concrete steps into one straight line.
- About 1 GB of free disk for the PostgreSQL and NATS volumes.
- A few minutes. Issuance itself is sub-second; most of the wall-clock is the one-time stack startup.
Steps
Bring up the control plane. From the repo root, start the one-command evaluation stack (control plane plus its datastores):
docker compose -f deploy/docker/docker-compose.yml up --buildYou should see Compose wait for PostgreSQL and NATS to report healthy, then the control plane start its event log, projections, orchestrator, and API in order.
Confirm it is serving. The control plane serves over TLS by default with a self-signed evaluation certificate, so check health with
-k:curl -fksS https://localhost:8443/healthz # {"status":"ok"}You should get
{"status":"ok"}. The web UI is the same binary at https://localhost:8443. How the API, CLI, and UI fit together is described in Platform & API.Mint your first API token. A fresh control plane fails closed — every route returns
401until you present a credential. Run the host-local bootstrap verb (pick any UUID as your tenant id; a single-tenant deployment uses one well-known id):trstctl token create --tenant 11111111-1111-1111-1111-111111111111 --subject ci-bot # -> prints a trst_... token on stdout. Store it now; it is shown only once.You should see a
trst_...token printed once. It carries operator scopes but deliberately excludes certificate issuance, so a bootstrap credential can administer the platform but cannot self-issue — the registration-authority split described in Policy & governance.Point the CLI at the control plane. Export the server URL and your token:
export TRSTCTL_SERVER=https://localhost:8443 export TRSTCTL_TOKEN=trst_...You should now be able to run
trstctl-clicommands without a401.Create an owner, then an identity, then transition it to issued. The owner is the service the certificate belongs to; the identity is the certificate itself; the transition to
issuedis what drives the control plane to sign:owner=$(echo '{"kind":"workload","name":"payments"}' | trstctl-cli owners create -f - | jq -r .id) ident=$(echo "{\"kind\":\"x509_certificate\",\"name\":\"payments.svc\",\"owner_id\":\"$owner\"}" \ | trstctl-cli identities create -f - | jq -r .id) echo '{"to":"issued"}' | trstctl-cli identities transition "$ident" -f - sleep 2You should see each command return JSON. The transition to
issuedmakes the orchestrator mint a leaf certificate through the built-in signer-backed CA. The single issuance path and the guarantees around it are covered in Issuance & certificate authorities.See it in inventory. List the certificates the control plane now tracks:
trstctl-cli certificates listYou should see your freshly minted certificate — discovered, owned, and tracked. That is your first certificate.
Where next
Journey: J1 Steps through: F4, F10, F11, F12, F8, F14