With plain SSH keys, every server keeps an authorized_keys list, and every client keeps a known_hosts list. With a few servers that’s fine. With dozens of servers and a changing team, it turns into sprawl: old keys never removed, new people waiting for their key to be copied everywhere, and users clicking “yes” on unknown host key warnings. SSH certificates solve both problems with a certificate authority (CA) that OpenSSH trusts natively. No extra software is needed.

How it works

  • You create a user CA key pair. Servers trust it with one line in sshd_config.
  • To give someone access, you sign their public key with the CA. The signed certificate states who they are (principals), and until when it’s valid.
  • Servers accept any valid certificate signed by the CA for an allowed principal. There’s no per-user authorized_keys.

Likewise, a host CA signs server host keys, so clients trust every server signed by it, with no more “authenticity of host can’t be established” prompts.

1. Create the user CA

On a secure machine, ideally offline or a dedicated admin box, not on the servers:

ssh-keygen -t ed25519 -f ssh_user_ca -C "user CA"

ssh_user_ca is the private CA key. Protect it like the keys to every server, because that’s what it is. ssh_user_ca.pub goes to the servers.

2. Trust the CA on each server

sudo cp ssh_user_ca.pub /etc/ssh/ssh_user_ca.pub
echo 'TrustedUserCAKeys /etc/ssh/ssh_user_ca.pub' | sudo tee /etc/ssh/sshd_config.d/20-ca.conf
sudo sshd -t && sudo systemctl reload ssh

Automate this across servers with Ansible or cloud-init. See Ansible playbooks.

3. Sign a user’s key

The user sends you their public key (id_ed25519.pub). You sign it:

ssh-keygen -s ssh_user_ca -I [email protected] -n deploy,alice -V +8h id_ed25519.pub
  • -I — the certificate ID, shown in server logs (who used it).
  • -n — principals: the Unix usernames this certificate may log in as.
  • -V +8h — valid for 8 hours. Short lifetimes mean expired access needs no revocation.

This creates id_ed25519-cert.pub. The user puts it next to their key. ssh picks it up automatically:

ssh deploy@web1

Inspect a certificate:

ssh-keygen -L -f id_ed25519-cert.pub

Server logs show the certificate ID:

Accepted publickey for deploy from 198.51.100.7 port 51234 ssh2: ED25519-CERT SHA256:… ID [email protected] (serial 0) CA ED25519 SHA256:…

Control who may log in as whom

By default, the principal must equal the target username. For more control, map principals per user on the server:

# /etc/ssh/sshd_config.d/20-ca.conf
TrustedUserCAKeys /etc/ssh/ssh_user_ca.pub
AuthorizedPrincipalsFile /etc/ssh/principals/%u
echo -e "ops\nalice" | sudo tee /etc/ssh/principals/deploy

Now any certificate with principal ops can log in as deploy. Issue ops certificates to the ops team, dev certificates to developers, and grant groups of people access per server role.

Restrict certificate abilities at signing time:

ssh-keygen -s ssh_user_ca -I ci-deploy -n deploy -V +1h \
  -O no-port-forwarding -O no-pty -O force-command=/usr/local/bin/deploy ci.pub

Host certificates: trusted servers

Create a host CA and sign each server’s host key:

ssh-keygen -t ed25519 -f ssh_host_ca -C "host CA"
# on/for each server:
ssh-keygen -s ssh_host_ca -I web1 -h -n web1.example.com,web1,203.0.113.10 -V +52w /etc/ssh/ssh_host_ed25519_key.pub

On the server, in sshd_config:

HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub

On clients, in ~/.ssh/known_hosts (or /etc/ssh/ssh_known_hosts):

@cert-authority *.example.com ssh-ed25519 AAAA…contents-of-ssh_host_ca.pub…

Clients now trust every server signed by the host CA. A rebuilt server with a new host key doesn’t cause scary warnings, as long as it’s re-signed.

Revocation

Short-lived certificates usually make revocation unnecessary. For longer ones, maintain a key revocation list:

ssh-keygen -k -f /etc/ssh/revoked_keys -s ssh_user_ca.pub compromised-cert.pub
echo 'RevokedKeys /etc/ssh/revoked_keys' | sudo tee -a /etc/ssh/sshd_config.d/20-ca.conf

Making it practical

Signing by hand works for small teams. Larger teams automate issuance with tools that check identity (SSO) and issue short-lived certificates: step-ca (Smallstep), HashiCorp Vault’s SSH secrets engine, Teleport, or cloud IAM-based SSH.

Quick reference

Task Command
Create CA ssh-keygen -t ed25519 -f ssh_user_ca
Trust CA (server) TrustedUserCAKeys /etc/ssh/ssh_user_ca.pub
Sign user key ssh-keygen -s ca -I id -n user -V +8h key.pub
Inspect cert ssh-keygen -L -f key-cert.pub
Principals per user AuthorizedPrincipalsFile /etc/ssh/principals/%u
Host cert ssh-keygen -s host_ca -h -I host -n names key.pub
Trust host CA (client) @cert-authority *.example.com ssh-ed25519 …

Related: ssh-keygen, YubiKey SSH and key-only SSH.

  • SSH
  • Security
  • DevOps