The Moment You Realize You’ve Lost Control
It’s 2 AM. Your manager asks: “Do we still have SSH access for the contractor who left three months ago?” You SSH into your jump box and run cat ~/.ssh/authorized_keys on each of your 12 servers. Six servers later, you still don’t know the answer. Half the keys have comments from 2019. One just says # removed? maybe?. You find a key with Bob’s name on it — but was that Bob the DevOps guy or Bob the intern?
This is life without an SSH Certificate Authority.
You’ve been copy-pasting SSH keys across your infrastructure like it’s 2005. Every new person means updating authorized_keys on every server. Every person leaving means hoping you remember which key was theirs. Want to rotate keys? Enjoy visiting 15 machines. Need to revoke access instantly? Tough luck — you’re touching every box anyway.
There’s a better way, and it’s been in OpenSSH for over a decade.
What an SSH Certificate Authority Actually Is
An SSH CA is stupidly simple: you create a special key that signs other SSH keys, and your servers trust anything signed by that CA key. Instead of scattering public keys across authorized_keys files, you sign a user’s key once, they get a certificate valid for whatever you say, and every server accepts it automatically.
Here’s the magic: you don’t touch authorized_keys again. Ever. You manage access by:
- Deciding who can sign keys (just you, or a small trusted team)
- Deciding when certificates expire (could be 8 hours, could be a year)
- Revoking entire certificates if someone leaves (optional — just don’t re-sign their key)
It’s certificate-based authentication, like HTTPS for SSH.
Setting Up Your SSH CA
First, create the CA keypair. Keep this safe — this is your master key.
ssh-keygen -t ed25519 -f ca_key -C "my-infrastructure-ca" -N ""# Generates ca_key (private) and ca_key.pub (public)Now tell your servers to trust this CA. Edit /etc/ssh/sshd_config:
# Trust user certificates signed by this CATrustedUserCAKeys /etc/ssh/ca_key.pub
# Optional: keep using authorized_keys as a fallbackPubkeyAuthentication yesCopy ca_key.pub to every server at /etc/ssh/ca_key.pub, then reload SSH:
sudo scp ca_key.pub user@server:/tmp/sudo ssh user@server "sudo mv /tmp/ca_key.pub /etc/ssh/ && sudo systemctl reload sshd"That’s it. Now every server trusts certificates signed by your CA.
Signing a User’s Key
When someone joins the team and gives you their public key (alice_key.pub), sign it:
ssh-keygen -s ca_key \ -I "alice-user@company" \ -n "alice,developers" \ -V "+52w" \ alice_key.pub# Generates alice_key-cert.pub (valid for 52 weeks)Breaking that down:
-s ca_key— sign with your CA private key-I "alice-user@company"— identity (for logging, doesn’t have to match username)-n "alice,developers"— principals (server-side usernames this cert can use)-V "+52w"— validity period (52 weeks from now; could also be “+8h” for short-lived)alice_key.pub— the key to sign
Give Alice two files: her private key (alice_key) and the certificate (alice_key-cert.pub). She puts both in ~/.ssh/:
ls -la ~/.ssh/-rw------- alice_key-rw-r--r-- alice_key-cert.pubSSH will automatically use the certificate if both files exist. Magic.
Short-Lived Certificates: The Killer Feature
Here’s where SSH CAs become dangerous to your previous life. Instead of signing keys for a year, sign them for 8 hours:
ssh-keygen -s ca_key \ -I "alice-daily-$(date +%s)" \ -n "alice,developers" \ -V "+8h" \ alice_key.pubEvery morning, you (or a cron job) re-sign the key. Alice’s certificate expires in 8 hours. If she leaves and you stop signing, her access vanishes automatically. No revocation lists, no cleanup, no guessing whether Bob still has access.
You can also mix principals: sign Bob’s key for only the web principal, so he can only SSH as the web user, not root or admin.
Reading a Certificate
Want to see what’s inside a certificate? SSH has you covered:
ssh-keygen -L -f alice_key-cert.pubOutput:
Type: user certificate Public key: ED25519-CERT SHA256:abc123... Key ID: "alice-user@company" Valid: from 2026-04-12T10:00:00 to 2026-04-19T10:00:00 Principals: alice developers Critical Options: (none) Extensions: permit-pty permit-port-forwarding permit-agent-forwarding permit-X11-forwarding permit-user-rc Signature: ...No mysteries. You know exactly when it expires, who can use it, and what they can do.
Optional: Host Certificates (Bonus)
Tired of The authenticity of host 'server.com' can't be established? Sign your server keys with the same CA:
ssh-keygen -s ca_key \ -h \ -I "my-server.com" \ -n "server.com,192.168.1.10" \ -V "+365d" \ /etc/ssh/ssh_host_ed25519_key.pubAdd this to your ~/.ssh/known_hosts:
@cert-authority server.com,*.my-domain.com /path/to/ca_key.pubNow you’ll never see that scary authenticity prompt again. Your client trusts the CA, so it trusts the server.
Why This Actually Matters
You’ve just replaced scattered, unversioned authorized_keys files with auditable, time-bound, principal-restricted certificates. You know:
- Exactly who has access (check who you signed a cert for)
- Exactly when it expires (check the validity period)
- Exactly what they can do (check the principals)
No more “I think Bob left?” SSH dives at 2 AM. No more manual key rotations across 20 servers. No more authorization sprawl.
Start small: create a CA, sign certs for your dev team, and watch the chaos disappear.