Issue and trust SSH access at scale
Goal
You will replace the pile of standing SSH keys in everyone's authorized_keys with
short-lived SSH certificates from a single authority. The outcome is hosts that trust
one SSH certificate authority, users who get certificates that expire on their own
(say, valid until 5 p.m.), and a clean inventory of any leftover keys still granting
access. This is for an operator who wants central, time-bounded, auditable SSH access
instead of per-host key copying. It is honest about which pieces the running binary
serves and which are agent/library work today.
Before you start
- A running control plane and an API token from
Getting started (
trstctl token create). - The CLI/API pointed at your server via
TRSTCTL_SERVERandTRSTCTL_TOKEN— see Getting started. - An installed agent on the hosts you want to manage, enrolled as in Getting started. For what the agent can see and change on a host, see SSH.
Steps
Turn on the SSH certificate authority and bind it to your tenant. The CA's key lives in the separate signing service under a handle constrained to SSH-cert signing — it never enters the API process. See SSH.
protocols: ssh: enabled: true tenant_id: "11111111-1111-1111-1111-111111111111"-> the SSH CA is served at
/ssh/..., and its binary key-revocation list at/ssh/krl(the artifact a host'sRevokedKeysconsumes). The toggle is off by default and startup fails closed if you enable it without a tenant.Find the SSH access you already have, so you know what the certificates are replacing. Create an
sshdiscovery source and queue a run; trstctl records host keys and standing-access grants — and flags anauthorized_keysgrant whose owner is unknown as orphaned. Only fingerprints are stored, never private keys. See Discovery & inventory.cat > ssh-source.json <<'JSON' {"kind":"ssh","name":"fleet","config":{"targets":["10.0.0.10:22"]}} JSON trstctl-cli discovery sources create -f ssh-source.json echo '{"source_id":"<source-id>"}' | trstctl-cli discovery runs start -f - trstctl-cli discovery findings list --run_id <run-id>-> you get a list of standing-access keys to retire as certificates take over. The SSH discovery control surface (source/schedule/run/findings) is served; the host-key scan executes from the agent/library connector — see Discovery & inventory.
Make your hosts trust the CA's public key. The CA's key goes into a host's
TrustedUserCAKeysfile, referenced fromsshd_config. The agent does this additively and safely, and this trust-rewrite is a high-blast-radius change, so it is off by default and requires an explicit opt-in plus confirmation. See SSH.trstctl-agent --enroll-url https://localhost:8443 \ --bootstrap-token-file ./trstctl-bootstrap-token \ --server localhost:9443 \ --name edge-agent-1 \ --ca-bundle ./trstctl-ca.pem \ --ssh-trust-add-ca \ --ssh-trust-confirm \ --ssh-trust-reload-cmd 'systemctl reload sshd' \ --ssh-trust-health-cmd 'ssh -o BatchMode=yes localhost true'What the agent writes for you, additively:
# /etc/ssh/sshd_config TrustedUserCAKeys /etc/ssh/trusted_user_ca_keys-> the agent backs up the files, validates the new config (
sshd -t), reloads, runs your post-reload health command, and auto-rolls-back to the last-known-good on any failure — so a bad rewrite cannot lock you out. It never removes existing trust without an explicit confirmation. This applier is wired into the agent binary behind the opt-in; see Current limitations.Issue a short-lived user certificate tied to a verified identity, not handed to anyone who asks. The attested issuer runs an attestation check first and only then derives the certificate's principals from the verified result, defaulting to a short TTL. Every issuance is an immutable
ssh.cert.issuedevent. See SSH.-> the user connects normally and
sshdvalidates the certificate against the trusted CA with no stored key. Access expires on its own — no standing key left behind. The attestation-gated issuer is library-complete and tested; the served SSH CA mints user/host certs and publishes the binary KRL today — see SSH and Current limitations.Pull a certificate back before it expires. Revoking it puts its serial on the SSH CA's key-revocation list, served in OpenSSH binary format at
/ssh/krl, which a host'ssshdconsumes via itsRevokedKeysdirective. See SSH.-> a revoked certificate is reported as revoked by stock
ssh-keygen; budget for pushing the updated KRL to hosts, since distribution is push-based.
Where next
- migrate-from-existing-ca.md — do the same consolidation for X.509 certificates.
- onboard-a-team.md — isolate each team's access in its own tenant.
Journey: J8 Steps through: F43, F44, F45, F42