Almost all SSH users are familiar with public key authentication and use SSH private keys to authenticate themselves when logging into a remote machine. The SSH key mechanism is relatively simple; the user generates a private key and shares his public key with the administrators of devices he wants to access. To allow access, the administrator of a device places the users’ key in the target accounts authorized_keys file.
In practice, this mechanism does not scale well. So the OpenSSH developers introduced a certificate-based solution that uses trust in a certificate authority rather than individual public keys.
What is an SSH Certificate?
A certificate is a file that encodes a public key with information about a user’s identity and other options relevant to the use of the public key it contains.
What is a Certificate Authority?
A certificate authority is a public/private key that signs certificates. By trusting the certificate authority key, you can also trust the credentials of the user that has a certificate signed by it.
How does it work?
Instead of the administrator configuring authorized_key files with each user’s public key, they can instead configure the SSH server to trust a certificate authority key.
They can then distribute private keys and certificates signed by the authority to allow access to any of the server’s accounts automatically.
Creating an SSH Certificate Authority
An SSH certificate authority is just a plain SSH public/private key pair. You can generate one using the ssh-keygen command. Store this securely for later use in signing certificates.
ssh-keygen -t ed25519 -f id_ca
Configuring an SSH Server to Trust an SSH Certificate Authority
Copy the public key file of your CA to the SSH server and enable the TrustedUserCAKeys directive in /etc/ssh/sshd_config
Creating User Certificates
Again, using ssh-keygen, you should first make the user a public/private key pair.
ssh-keygen -t ed25519 -f id_user
You can then sign this with the CA key.
ssh-keygen -s id_ca -I lee -n lee id_user.pub
This command creates a key that is valid for the account lee. You can add more accounts to the certificate by modifying the -n argument, add a comma-separated list of principals that can be used by this certificate.
ssh-keygen -s id_ca -I lee -n lee,admin id_user.pub
So far, the certificates created will not expire. To create a certificate that expires, use the additional -V argument. For example, to make it valid for one year we could use
ssh-keygen -s id_ca -I lee -n lee,admin -V +365d id_user.pub
ssh-keygen -s id_ca -I lee -n lee,admin -V +52w id_user.pub
If you want to assign each certificate a unique serial number, you can use the -z argument. This value needs to be numeric, it will default to zero if omitted.
ssh-keygen -s id_ca -I lee -n lee,admin -V +52w -z 12345 id_user.pub
You can print out the contents of a certificate.
ssh-keygen -L -f id_user-cert.pub id_user-cert.pub: Type: email@example.com user certificate Public key: ED25519-CERT SHA256:BJLn251h7NTo/KZv35zHBWmSVRvk/T7zWc1ftNh4Yhg Signing CA: ED25519 SHA256:R/rWKMUga78Y8omb115t9Z4kzXu4MgsNx24xJzrvzz0 Key ID: "lee" Serial: 12345 Valid: from 2020-08-27T12:49:00 to 2021-08-26T12:50:01 Principals: lee admin Critical Options: (none) Extensions: permit-X11-forwarding permit-agent-forwarding permit-port-forwarding permit-pty permit-user-rc
Creating Host Certificates
We have until now dealt with user certificates for user authentication. However, you can also use OpenSSH certificates for host keys.
It’s general practice to maintain a separate CA key for host keys.
ssh-keygen -t ed25519 -f id_host_ca
Now we can generate a host key.
ssh-keygen -t ed25519 -f ssh_host_ed25519
To sign the host key, we have to use the -h command-line switch because the user and host keys are separate and not interchangeable.
ssh-keygen -s id_host_ca -I server1.example.com -n server1.example.com -h ssh_host_ed25519.pub
Configure the Server to use the Host Certificate
Now we have the certificate; we can configure the server to present this when users connect by adding the HostCertificate sshd_config directive.
Configure the Client to Trust the Certificate Authority
Users can trust all the hosts signed by a CA by adding a known_hosts entry using @cert-authority tag in the known_hosts file.
@cert-authority *.example.com <PUBLICKEY>
Where <PUBLICKEY> is the contents of the CA public key file id_host_ca.pub that we generated in the first step in this section.
You can also add this to /etc/ssh/ssh_known_hosts on any system to have the CA trusted by all users.