Skip to content
Go back

SSH CA: Finally Ditch authorized_keys

By SumGuy 5 min read
SSH CA: Finally Ditch authorized_keys

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:

  1. Deciding who can sign keys (just you, or a small trusted team)
  2. Deciding when certificates expire (could be 8 hours, could be a year)
  3. 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.

Terminal window
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:

/etc/ssh/sshd_config
# Trust user certificates signed by this CA
TrustedUserCAKeys /etc/ssh/ca_key.pub
# Optional: keep using authorized_keys as a fallback
PubkeyAuthentication yes

Copy ca_key.pub to every server at /etc/ssh/ca_key.pub, then reload SSH:

Terminal window
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:

Terminal window
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:

Give Alice two files: her private key (alice_key) and the certificate (alice_key-cert.pub). She puts both in ~/.ssh/:

Terminal window
ls -la ~/.ssh/
-rw------- alice_key
-rw-r--r-- alice_key-cert.pub

SSH 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:

Terminal window
ssh-keygen -s ca_key \
-I "alice-daily-$(date +%s)" \
-n "alice,developers" \
-V "+8h" \
alice_key.pub

Every 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:

Terminal window
ssh-keygen -L -f alice_key-cert.pub

Output:

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:

Terminal window
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.pub

Add this to your ~/.ssh/known_hosts:

@cert-authority server.com,*.my-domain.com /path/to/ca_key.pub

Now 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:

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.


Share this post on:

Send a Webmention

Written about this post on your own site? Send a webmention and it'll show up above once verified.


Previous Post
RAG on a Budget: Building a Knowledge Base with Ollama & ChromaDB
Next Post
Docker BuildKit: Stop Waiting for Your Images to Build

Discussion

Powered by Garrul . Sign in with GitHub or Google, or post anonymously.

Related Posts