I have some machines on my local network that I want to be able to log into from any other machine on my network.
This can be done by generating SSH key pairs for each user/client, then putting each of the public keys in each other machine's authorized_keys file.
It sounds simple, but it is a nightmare scenario.
Every machine needs to know about every public key for every other client on the network, and adding or removing a machine means manually managing all of those public keys.
For a small number (<= 2) of machines it is manageable and possibly even preferable, but I would argue that 3 or more machines requires a different strategy for the sanity of the network admin, and this is where SSH Certificates come in.
The general idea with SSH Certificates is that you establish 2 certificate authorities: a User CA and a Host CA. The User CA is for authenticating users to hosts, and the Host CA is for authenticating hosts to users.
For the User CA, you distribute the User CA public key to every host you need to recognize it, then configure each host to trust it. You get user public keys and sign them with the User CA private key, then distribute those keys back to the clients. Each host that trusts your User CA will trust public keys signed by the CA.
For the Host CA, you get host public keys and sign them with the Host CA private key, then distribute those keys back to the hosts. Then you configure each host to offer its certificate to users logging in.
This guide is the result of my notes from learning about and implementing both User and Host CAs on my local network. The majority, but not all, of these commands will need to be run as the root user, but I will not be distinguishing these in this guide due to the impossibility of generalizing such things for arbitrary networks. In other words, I have no idea and cannot have any idea what your user account situation is on your local network, so if you are following this guide and run into permissions errors, it is on you to make sure you are executing commands with the correct privileges.
Establishing a User CA is as simple as creating a key pair.
For my example, I created an /etc/ssh/ca_keys directory, so this guide will do the same:
# Create User CA key pair
ssh-keygen -t ed25519 -f /etc/ssh/ca_keys/user_ca_key -C "User CA"For each host that needs to recognize the User CA, distribute the User CA's public key.
Recommend placing it in /etc/ssh/ on the host.
# Possible script to distribute User CA public key
scp /etc/ssh/ca_keys/user_ca_key.pub remote_host:/etc/ssh/user_ca_key.pubConfigure the host to trust the User CA public key:
# nano /etc/ssh/sshd_config
TrustedUserCAKeys /etc/ssh/user_ca_key.pubRestart the sshd service after this:
sudo service sshd restart
# Or with systemctl
sudo systemctl restart sshd
# Or with launchctl
sudo launchctl unload /System/Library/LaunchDaemons/ssh.plist
sudo launchctl load -w /System/Library/LaunchDaemons/ssh.plist For each user that needs to be able to remotely access a machine, acquire and sign their public key. These can be generated by the User CA and distributed to the machines that require them, or they can be generated on the client machines and sent to the User CA for signing.
# Possible script to acquire user keys
scp remote_host:~/.ssh/id_ed25519.pub /etc/ssh/user_keys/clientname-id_ed25519.pubssh-keygen -I "Client name" \ # -I is a comment or identifier logged at login
-s /etc/ssh/ca_keys/user_ca_key \ # -s indicates we are using the private key at /etc/ssh/ca_keys/user_ca_key to sign a public key
-n username1,username2 \ # -n is a comma-separated list of user names that are allowed to login with this cert
-z 1 \ # -z is a serial number used for logging
-V +52w \ # -V is a date string indicating how long the certificate is valid for
/etc/ssh/user_keys/clientname-id_ed25519.pub # This is the user public key we are signingFully expanded out:
ssh-keygen -I "Client name" -s /etc/ssh/ca_keys/user_ca_key -n username1,username2 -z 1 -V +52w /etc/ssh/user_keys/clientname-id_ed25519.pubThis will output a certificate at /etc/ssh/user_keys/clientname-id_ed25519-cert.pub
# Possible script to distribute user certificates
scp /etc/ssh/user_keys/clientname-id_ed25519-cert.pub remote_host:~/.ssh/id_ed25519-cert.pubAt this point, the client should be able to remotely log into the host with no password.
Once again, establishing a Host CA is as simple as creating a key pair.
We will reuse the ca_keys directory from the User CA section:
# Create Host CA key pair
ssh-keygen -t ed25519 -f /etc/ssh/ca_keys/host_ca_key -C "Host CA"For each host that needs to allow remote access, acquire its host public key.
This will usually be in /etc/ssh/, example: /etc/ssh/ssh_host_ed25519_key.pub.
These keys are generated automatically when openssh-server is installed.
# Possible script to acquire host keys
scp remote_host:/etc/ssh/ssh_host_ed25519_key.pub /etc/ssh/host_keys# Signing host public key with Host CA private key creates host certificate:
ssh-keygen -I "Host name" \ # -I is a comment or identifier logged at login
-s /etc/ssh/ca_keys/host_ca_key \ # -s indicates we are using the private key at /etc/ssh/ca_keys/host_ca_key to sign a public key
-h \ # -h indicates this is creating a host certificate
-n hostname \ # -n is a comma-separated list of host names that are authenticated with the CA
-z 1 \ # -z is a serial number used for logging
-V +52w \ # -V is a date string indicating how long the certificate is valid for
/etc/ssh/host_keys/ssh_host_ed25519_key.pub # This is the host public key we are signingFully expanded out:
ssh-keygen -I "Host name" -s /etc/ssh/ca_keys/host_ca_key -h -n hostname -z 1 -V +52w /etc/ssh/host_keys/ssh_host_ed25519_key.pubThis will output a certificate at /etc/ssh/host_keys/ssh_host_ed25519_key-cert.pub.
# Possible script to return host keys
scp /etc/ssh/host_keys/ssh_host_ed25519_key-cert.pub remote_host:/etc/ssh/# nano /etc/ssh/sshd_config
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pubYou may also need to run chown root:root /etc/ssh/ssh_host_ed25519_key-cert.pub in order to make sshd recognize the certificate.
Restart the sshd service after this:
sudo service sshd restart
# Or with systemctl
sudo systemctl restart sshd
# Or with launchctl
sudo launchctl unload /System/Library/LaunchDaemons/ssh.plist
sudo launchctl load -w /System/Library/LaunchDaemons/ssh.plist At this point, your hosts should present their certificates to clients logging in.
You can see this by running ssh -v remote_host.
You will see a line in the logging output that reads something like debug1: Server host certificate: [email protected] ....
- https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Certificate-based_Authentication
- https://goteleport.com/blog/how-to-configure-ssh-certificate-based-authentication/
- https://docs.redhat.com/en/documentation/red_hat_enterprise_linux/6/html/deployment_guide/sec-using_openssh_certificate_authentication
- https://www.youtube.com/watch?v=jJ_NDOm7WKk