zero-knowledge

ssh certificates part 2

This is the second part of the SSH certificate series, server side SSH certificates. You can find the first one here.

This post shows, what use server side certificates can be and how they can be created.

What use have server side certificates?

SSH certificates on the host side are used to extend the ssh host keys. These can be used to better identify a running system, as multiple names can be provided in the certificate. This avoids the message of a wrong host key in a shared IP system, as all IPs and names can be provided.

SSH certificates can also help to identify freshly deployed systems in that the system gets certified directly after the deployment by a build ca.

signing a host key

For this step, we need a CA key. How that can be generated was mentioned in the first part. We also need the host public key to sign. This can be either copied from /etc/ssh/ from the server or it can be fetch using ssh-keyscan.

ssh-keyscan foo.example.org

It can also take a parameter for a specific type

ssh-keyscan -t ed25519 foo.example.org

This is needed for some older versions of openssh, where ed25519 public keys were not fetched by default with ssh-keyscan.

The output returned looks like the following:

zero-knowledge.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPIP0JSsdP2pjtcYNcmqyPg6nLbMOjDbRf0YR/M2pu2N

The second and third field need to be put into a file, so that it can be used to generate the certificate.

A complete command would then look like this:

ssh-keyscan foo.example.org | awk '/ssh|ecdsa/ { print $2,$3 }' > host.pub

With the resulting file, we can now proceed to create the certificate.

ssh-keygen \
  -s ca.key \
  -V '+52w1d' \
  -I 'foohost' \
  -h \
  -n foo.example.org,bar.example.org \
  host.pub

The meaning of the options is:

The last option is the public key file to certify.

This results in a file host-cert.pub, which contains the certificate. It can be viewed like the SSH client certificate, with ssh-keygen.

ssh-keygen -L -f host-cert.pub

This file now has to be placed in the same directory like the public key on that host, with the same -cert.pub ending.

The last step on the server is to adjust the sshd_config, so that it includes the certificate. For that, add the following line for the fitting host key, for example:

HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub

With a reload, it should load the certificate and make it available for authentication.

Now the only thing left to do is to tell the client, that it should trust the CA to identify systems. For that, the public key of the CA has to be added to the file ~/.ssh/known_hosts in the following format

@cert-authority * <content of ca.pub>

The * marks a filter, so different CAs can be trusted depending on the domain.

With this, you are able to connect to your server only using the certificate provided by the server. When connecting with debugging on, you should get output like the following:

$ ssh -v foo.example.com
...
debug1: Server host key: ssh-ed25519-cert-v01@openssh.com SHA256:+JfUty0G4i3zkWdPiFzbHZS/64S7C+NbOpPAKJwjyUs
debug1: Host 'foo.example.com' is known and matches the ED25519-CERT host certificate.
debug1: Found CA key in /home/foo/.ssh/known_hosts:1
...

With the first part and now the second part done, you can already lock up your infrastructure pretty fine. In the next part, I will show some stuff I use to keep my infrastructure easily managable.