_______ ____ ____ __ __ ____ __ ______ ______ /_ __// __// __// /_/ // _ / / / / __ // ____/ / / / __// /_ / __ // _ < / /_ / /_/ // /_ / /_/ /___//___//_/ /_//____//___//_____//_____/ techblog.koponen.se [ / ] [ howto ] [ reviews ] [ webapps ] [ youtube ] [ links ] [ about ] -------------------------------------------------------------------------
VERIFY SSH HOST KEYS WITH SSH CA
Just some very brief notes on how to verify SSH host keys with SSH CA.
I might extend this article later or write more on the subject.
In this HOWTO we have three machines:
A machine that will hold the CA (Certificate Authority), which is a private key that shouldn't leave this machine. Theoretically a machine holding a CA shouldn't be on a network, but in this case it's practical if this machine can reach any server it needs to create a certificate for.
A server (which is also listening on SSH) whose SSH public host key is going to be signed by ca1.
This machine wants to access server1 via SSH without any pre-existing knowledge of the SSH public host key. Normally this knowledge is transfered "by hand" by whoever setup server1 to the owner of client1. Commonly there's a bad practise of users just "connecting blindly" to the server and trust whatever SSH public host key their SSH client reports.
The idea is simple: ca1 manually verifies the host key of server1 and issues a certificate that server1 can configure into the SSH settings on server1. This way anyone who has the public CA certificate from ca1 can verify any SSH server that ca1 has verified. ca1 is thus a trustbroker between server1 and client1.
Something like this:
Pay attention to the prompt in the commands below as it indicates on which machine the commands are run.
First create the signing key on ca1 (step 03):
ca1:~$ mkdir ca ca1:~$ cd cd ca1:~/ca$ ssh-keygen -t rsa -b 4096 -f ca_signing.key -C ca_signing_key Generating public/private rsa key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in ca_signing.key Your public key has been saved in ca_signing.key.pub The key fingerprint is: SHA256:C1QaVSCyz4XIl8vyIdSfmBi+NADtr4UShoxuYFaKJmo ca_signing_key The key's randomart image is: +---[RSA 4096]----+ |.. . o.+o. | | ..o = B | |=.+ * B . | |BB.+ O * . | |X. oB X S | |oE..o* o . | |o. o. . . | | . | | | +----[SHA256]-----+ ca1:~/ca$
You need to collect the public keys you're going to sign (step 04):
ca1:~/ca$ mkdir server1 ca1:~/ca1$ scp server1.example.com:/etc/ssh/ssh_host_*_key.pub ./server1/ ssh_host_dsa_key.pub 100% 600 217.6KB/s 00:00 ssh_host_ecdsa_key.pub 100% 172 105.4KB/s 00:00 ssh_host_ed25519_key.pub 100% 92 63.3KB/s 00:00 ssh_host_rsa_key.pub 100% 736 487.5KB/s 00:00 ca1:~/ca$
Then you sign each key (step 05):
ca1:~/ca$ ssh-keygen -s ca_signing.key -I server1_host_rsa -h -Z server1.example.com -V -5m:+365d -z 1 server1/ssh_host_rsa_key.pub Signed host key server1/ssh_host_rsa_key-cert.pub: id "server1_host_rsa" serial 1 valid from 2022-11-01T22:44:04 to 2023-11-01T22:49:04 ca1:~/ca$ ssh-keygen -s ca_signing.key -I server1_host_dsa -h -Z server1.example.com -V -5m:+365d -z 2 server1/ssh_host_dsa_key.pub Signed host key server1/ssh_host_dsa_key-cert.pub: id "server1_host_dsa" serial 2 valid from 2022-11-01T22:44:11 to 2023-11-01T22:49:11 ca1:~/ca$ ssh-keygen -s ca_signing.key -I server1_host_ecdsa -h -Z server1.example.com -V -5m:+365d -z 3 server1/ssh_host_ecdsa_key.pub Signed host key server1/ssh_host_ecdsa_key-cert.pub: id "server1_host_ecdsa" serial 3 valid from 2022-11-01T22:44:21 to 2023-11-01T22:49:21 ca1:~/ca$ ssh-keygen -s ca_signing.key -I server1_host_ed25519 -h -Z server1.example.com -V -5m:+365d -z 4 server1/ssh_host_ed25519_key.pub Signed host key server1/ssh_host_ed25519_key-cert.pub: id "server1_host_ed25519" serial 4 valid from 2022-11-01T22:44:31 to 2023-11-01T22:49:31 ca1:~/ca$
Here's a breakdown what the different flags do:
-s ca_signing.key = Chooses which key to sign with -I server1_host_rsa = Identity of the certificate (like a label) -h = We are signing a host public key -Z server1.example.com = Sets/binds the certificate to this hostname -V -5m:+365d = The certificate starts to be valid 5 minutes ago and is valid up until 365 days from now -z 1 = Sets a serial number for the certificate, it is good custom to have this
Now transfer the certificate files back to server1 (step 06):
ca1:~/ca$ scp server1/ssh_host_*_key-cert.pub server1: ssh_host_dsa_key-cert.pub 100% 2217 468.4KB/s 00:00 ssh_host_ecdsa_key-cert.pub 100% 1789 957.7KB/s 00:00 ssh_host_ed25519_key-cert.pub 100% 1713 1.0MB/s 00:00 ssh_host_rsa_key-cert.pub 100% 2349 1.2MB/s 00:00 ca1:~/ca$
Install the certificates (step 07):
server1:~$ sudo mv ssh_host_*_key-cert.pub /etc/ssh/ server1:~$ sudo chown root.root /etc/ssh/ssh_host_*_key-cert.pub server1:~$
Add these four lines to /etc/ssh/sshd_config (step 07):
HostCertificate /etc/ssh/ssh_host_dsa_key-cert.pub HostCertificate /etc/ssh/ssh_host_ecdsa_key-cert.pub HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub
Restart the SSH service with the new settings (step 07):
server1:~$ sudo systemctl restart ssh server1:~$
Transfer the CA signing public key (ca_signing.key.pub) to client1 and put the file in ~/.ssh/ and add it as a CA to known_hosts on client1 (step 09):
client1:~$ cd .ssh client1:~/.ssh$ echo "@cert-authority *.example.com $(cat ca_signing.key.pub)" >> ~/.ssh/known_hosts client1:~/.ssh$
Do note that it will only verify when you ssh to server1 with the full FQDN server1.example.com. You could add the cert-authority with * instead of *.example.com, but it's in theory kind of sloppy.
There's more fun to be learned about SSH CA, but that might be another article in the future.