How to Use SSH Certificates Instead of Keys (One CA, No More authorized_keys Files)

SSH certificates: one CA, keys signed with an expiry, every server trusts it with one line. A lost laptop is revoked, not chased.

With four machines and three laptops, authorized_keys files are a maintenance job: a new laptop means touching every server; a lost one means finding and removing its key everywhere. SSH certificates replace that with a small certificate authority: you sign each laptop's key once, with an expiry and the usernames it may use; every server trusts the CA with a single line in sshd_config. The same trick for host keys ends the "authenticity of host can't be established" prompt for good. It's built into OpenSSH; no software to install.

Quick reference

TaskCommand
Make the CA (on a safe machine)ssh-keygen -t ed25519 -f ~/ssh-ca/user_ca -C "home user CA"
Sign a laptop's keyssh-keygen -s user_ca -I john-laptop -n john,root -V +52w id_ed25519.pub
Servers trust the CATrustedUserCAKeys /etc/ssh/user_ca.pub in sshd_config
Sign a host keyssh-keygen -s host_ca -I homeserver -h -n homeserver,192.168.1.50 -V +520w ssh_host_ed25519_key.pub
Clients trust host CA@cert-authority * ssh-ed25519 AAAA… in ~/.ssh/known_hosts
RevokeRevokedKeys /etc/ssh/revoked_keys + ssh-keygen -k
Inspectssh-keygen -L -f id_ed25519-cert.pub

1. Create the CA

On your most trusted machine (the laptop you use for admin, or an offline box), not on a server:

mkdir -p ~/ssh-ca && cd ~/ssh-ca
ssh-keygen -t ed25519 -f user_ca -C "home user CA"
ssh-keygen -t ed25519 -f host_ca -C "home host CA"

Two CAs: one signs users (laptops), one signs hosts (servers). Passphrases on both. Back up the private keys encrypted, off the server — whoever holds user_ca can log in anywhere. Only the .pub halves go out.

2. Sign a user key

Each laptop keeps its own key pair (3). Send its id_ed25519.pub to the CA machine and sign:

ssh-keygen -s user_ca -I john-laptop -n john,root -V +52w ~/incoming/id_ed25519.pub

It produces id_ed25519-cert.pub. Copy it back to the laptop next to the key (~/.ssh/id_ed25519-cert.pub); ssh picks it up automatically. ssh-keygen -L -f shows what's inside.

3. Servers trust the CA

On every server (and in the Ansible hardening role, 140):

sudo cp user_ca.pub /etc/ssh/user_ca.pub
echo "TrustedUserCAKeys /etc/ssh/user_ca.pub" | sudo tee -a /etc/ssh/sshd_config
sudo sshd -t && sudo systemctl restart ssh

Test from the laptop: ssh john@server — in, with no entry in authorized_keys. Keep authorized_keys for now as a fallback; remove it once every laptop has a certificate (AuthorizedKeysFile none for the strict version).

A certificate can also carry restrictions: -O no-port-forwarding, -O source-address=192.168.1.0/24, -O force-command=/usr/local/bin/backup-only.sh — a backup client's certificate that can run only the backup.

4. Host certificates: no more fingerprint prompts

Sign each server's host key:

scp john@server:/etc/ssh/ssh_host_ed25519_key.pub ~/incoming/homeserver.pub
ssh-keygen -s host_ca -I homeserver -h -n homeserver,homeserver.lan,192.168.1.50 -V +520w ~/incoming/homeserver.pub
scp ~/incoming/homeserver-cert.pub john@server:/tmp/

On the server:

sudo mv /tmp/homeserver-cert.pub /etc/ssh/ssh_host_ed25519_key-cert.pub
echo "HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub" | sudo tee -a /etc/ssh/sshd_config
sudo systemctl restart ssh

On every laptop, one line in ~/.ssh/known_hosts (or /etc/ssh/ssh_known_hosts for all users):

@cert-authority *.lan,192.168.1.*,192.168.2.* ssh-ed25519 AAAA...the host_ca.pub key...

Now a rebuilt server (74, 172) with a newly signed host key is trusted immediately — no "REMOTE HOST IDENTIFICATION HAS CHANGED", no blind yes. The prompt you've been clicking through since tutorial 2 was the attack surface for a man-in-the-middle; this closes it.

5. Revoke

A laptop is lost:

ssh-keygen -k -f revoked_keys -s user_ca -z 1 ~/incoming/lost-laptop-cert.pub

Copy revoked_keys to every server (Ansible, one run) with RevokedKeys /etc/ssh/revoked_keys in sshd_config. Or simply rely on the expiry — -V +4w certificates make revocation rarely necessary. Keep a list of what you've signed (-I identities, serials via -z) in BookStack (88).

6. Renewal

A year later, re-sign the same public key with a new -V. Script it: a tiny signing script on the CA machine, or step-ca (146) which has an SSH CA mode with web-based enrolment and automatic renewal — the same tool, both certificate worlds.

Troubleshooting

"Permission denied (publickey)" with a certificate. The principal (-n) doesn't include the username you're logging in as; or the certificate expired (ssh-keygen -L); or the server lacks TrustedUserCAKeys. ssh -v says which.

Host certificate ignored, still prompting. The @cert-authority pattern doesn't match how you typed the host (name vs IP); the -n list on the host cert must include it too.

sshd -t error about the cert file. The -cert.pub must sit next to the matching private host key and be readable.

Lost user_ca. Make a new one, re-sign every laptop, replace user_ca.pub on every server. Painful; that's why it's backed up encrypted.

Wrapping up

Two CA keys on a safe machine, user certificates with principals and expiry, one TrustedUserCAKeys line per server, host certificates so fingerprints are verified instead of accepted. New laptop: one signature. Lost laptop: one revocation. Rebuilt server: trusted at once. The last manual piece of SSH administration goes away.

Call us