Administering multiple users and their SSH keys across multiple machines can become a hassle. One thing we can do to ease management and allow easier scaling is to create an SSH CA.
Creating an SSH Certificate Authority allows us to authenticate hosts to users and vice-versa, no longer needing to verify via TOFU on every new machine, having to sync multiple user keys across multiple servers, and managing associated authorized_keys
files. With a few caveats;
- The pubkey of the CA still needs to be synced across servers.
- KRLs, a type of CRL, when generated by
ssh-keygen
are binary files, although you don’t seem to necessarily need to use this format. - There appears to be no OSCP mechanism, meaning KRLs need to be synced across servers.
- ‘Principals’ (restrictions on what certificates validate) can be tricky if the same user has different usernames, or hostnames change.
The CA keypair is generated the same as a normal ssh keypair;
ssh-keygen -f /etc/ssh/ca
From here we can sign existing keys with the -s
option:
# For user keys:
# Note that principals (-n) must match the username on the remote machine.
# Otherwise you can override with the 'AuthorizedPrincipalsFile' sshd_config option on the remote host.
ssh-keygen -s /etc/ssh/ca -I $(whoami) -n $(whoami) ~/.ssh/*.pub
ssh-add ~/.ssh/*.pub
# And host sshd keys:
ssh-keygen -s /etc/ssh/ca -I $(hostname) -n $(hostname) -h /etc/ssh/*.pub
for i in /etc/ssh/*-cert.pub; do echo "HostCertificate $i" >> /etc/ssh/sshd_config; done
# and restart sshd
There are a few options to add some security, used above is -n
to restrict which users and hosts the key is valid to authenticate, also of note is -V
to specify a validity period.
At a minimum, you should specify -n
when signing host keys, otherwise said key becomes valid for any host.
You will have to distribute the CA pubkey to all hosts you wish to use it for verification on. As this is a public key, it doesn’t need to be protected from reading, just tampering, and can be hosted on something like a trusted fileserver.
Now we need to tell ssh that we want to use our CA for authentication, we can do this either at the system or user level:
# For host verification:
# System-wide:
echo "@cert-authority * $(cat /etc/ssh/ca.pub)" >>/etc/ssh/ssh_known_hosts
# Per user:
echo "@cert-authority * $(cat /etc/ssh/ca.pub)" >>~/.ssh/known_hosts
# For client verification:
# System-wide:
echo "TrustedUserCAKeys /etc/ssh/ca.pub" >>/etc/ssh/sshd_config
# Per user:
echo "cert-authority,principals=$(whoami) $(cat /etc/ssh/ca.pub)" >>~/.ssh/authorized_keys
Finally, signed keys can be revoked if needed:
# System-wide:
echo "RevokedKeys /etc/ssh/revoked_keys" >> /etc/ssh/sshd_config
echo @revoked $(cat $key_to_revoke.pub) >> /etc/ssh/revoked_keys
# Per user:
echo @revoked $(cat $public_key_to_revoke) >> ~/.ssh/known_hosts
Or via ssh-keygen
:
echo "RevokedKeys /etc/ssh/revoked_keys" >> /etc/ssh/sshd_config
ssh-keygen -k -f /etc/ssh/revoked_keys -u -s /etc/ssh/ca $key_to_revoke.pub
References
- https://www.lorier.net/docs/ssh-ca.html
- https://engineering.fb.com/security/scalable-and-secure-access-with-ssh/
- https://jameshfisher.com/2018/03/16/how-to-create-an-ssh-certificate-authority/
- https://ef.gy/hardening-ssh
- https://blog.habets.se/2011/07/OpenSSH-certificates.html
This post is to be considered a public draft as I continue to mess with SSH CAs and learn the quirks