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:
scp ca_key.pub user@server:/tmp/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 2027-04-11T10: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 a line to your ~/.ssh/known_hosts that pastes in the contents of ca_key.pub (not a file path, known_hosts wants the actual key blob):
@cert-authority server.com,*.my-domain.com ssh-ed25519 AAAAC3Nza...your-ca-public-key... my-infrastructure-caNow 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.