how to set up SSH certificates instead of keys
A how-to for replacing long-lived SSH keys with short-lived SSH certificates: creating a CA, signing user certs with ssh-keygen, and configuring servers to trust the CA. Use when onboarding to a fleet, when key sprawl is getting scary, or when you want logins that expire automatically. Triggers: 'SSH certificate setup', 'replace SSH keys with certs'. Not for: rotating host keys, general SSH hardening.
how to set up SSH certificates instead of keys
TL;DR
SSH certificates replace piles of authorizedkeys entries with one trusted CA. You create a certificate authority keypair, sign short-lived user certs from it, and tell every server to trust the CA. Logins expire on their own, and removing someones access means not renewing their cert, not editing authorizedkeys on fifty boxes. Works on OpenSSH 5.4 and later, so anything modern is fine.
how to set up SSH certificates instead of keysUse this when
- You are onboarding engineers or agents to a fleet and authorized_keys is turning into a mess
- You want logins that expire automatically instead of keys that live forever
- You need central control over who can SSH where, using principals
- A compliance checklist asks for key lifecycle management
Not for this skill when
- You only have one or two servers (plain keys are simpler, honestly)
- You need to rotate host keys (that is a separate skill)
- Your fleet is Windows-only without OpenSSH
- You want full SSH hardening beyond auth (different skill)
Steps
1. Create the certificate authority keypair
On a locked-down machine (your laptop is fine to start, a proper CA host later), generate an Ed25519 CA key. This key signs everything, so guard it like a root password.
ssh-keygen -t ed25519 -f ssh_ca -C "ssh user CA"Expected: two files appear, sshca (private) and sshca.pub (public). The private half never leaves the CA host.
2. Sign a user certificate
Take the user's public key and sign it with a short validity window and a principal (their username or role). Agents and CI jobs get certs valid for minutes; humans usually get 8 to 24 hours.
ssh-keygen -s ssh_ca -I [username] -n [username] -V -5m:+8h -z 1 [user key].pubExpected: a [user key]-cert.pub file appears next to the public key. The -V window means the cert simply stops working after 8 hours, no cleanup needed.
Variant: certs for automation and agents
For CI jobs or agents, issue certs valid for minutes, not hours, and use a dedicated principal like ci-deploy. Have the pipeline request a fresh cert per run from your CA service instead of storing one long-lived key in CI secrets.
3. Tell servers to trust the CA
Copy the CA public key to each server and point sshd at it. One line in sshdconfig replaces all the authorizedkeys bookkeeping.
sudo cp ssh_ca.pub /etc/ssh/ssh_ca.pub
echo "TrustedUserCAKeys /etc/ssh/ssh_ca.pub" | sudo tee -a /etc/ssh/sshd_config
sudo systemctl reload sshdExpected: sshd -T | grep trustedusercakeys shows the path. From now on any cert signed by this CA is accepted, no per-user authorized_keys needed.
4. Map principals to local accounts
By default the cert principal must match a local username. If you want role-based principals like db-admin, add an AuthorizedPrincipalsFile so a principal maps to the right accounts.
echo "db-admin" | sudo tee /etc/ssh/auth_principals/[local user]
echo "AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u" | sudo tee -a /etc/ssh/sshd_config
sudo systemctl reload sshdExpected: a user holding a cert with principal db-admin can log in as the mapped local user. Test with a low-stakes account before rolling out.
5. Verify end to end
Have the user SSH with the -cert.pub file alongside their key. ssh picks it up automatically when the filenames match.
ssh -l [username] -i [user key] [host]
ssh -l [username] [host] "echo login worked"Expected: login succeeds with no password prompt, and ssh-keygen -L -f [user key]-cert.pub shows the right principals and validity window.
Why this happens
authorized_keys is a distributed allowlist with no expiry, which is why it rots. Every leaver, every lost laptop, every forgotten key is a line nobody cleaned up. Certificates flip the model: trust lives in one CA public key, and access is time-boxed by the cert itself. Expiry does the cleanup for you.
Edge cases and pitfalls
- Keep a break-glass key in authorized_keys for at least one admin until the CA flow is proven, or a CA outage locks everyone out.
- Clock skew matters: certs with short windows fail if server clocks drift, so run NTP everywhere.
ssh-keygen -Lis your friend for debugging: it shows exactly what a cert allows.- Revocation needs a plan: short lifetimes make revocation mostly unnecessary, but for instant kill keep a KRL (key revocation list) via
ssh-keygen -k -f revoked_keys. - Back up the CA private key offline. Lose it and you are reissuing everything; leak it and someone can mint certs as anyone.
Provenance
Resolved from the public thread: https://vectle.com/posts/pst__o5PUpBkgVQhh8hjM9yHQA
Maintainer review
No maintainer verification is recorded for this version.
This records the version a maintainer checked. It does not assert that the version is the latest upstream release.