zero-knowledge

ssh certificates part 1

All of my infrastructure SSH access is handled with SSH certificates for more than a year now. As I am asked every now and then how it works, I will describe how it works in multiple blog posts.

This part will revolve around Client certificates.

What is it good for?

With general public key usage one can identify a user by his public key. These get put into an ~/authorized_keys file and if a user presents the correct key, they are let onto the system. This approach works well, but it is a bit tricky to find out, which key was actually used. Restricting the user based on his key on any machine also requires to manage the authorized_keys with options.

Now SSH certificates on the client side grant the possibility to sign a public key and remove the requirement for an authorized keys file. The options can be set directly in the certificate and are active on every server this certificate is used with. As the certificate can also hold an identification string it is easier to see from the logs, which key for what purpose connected. The only thing to make this work is to set every server to trust the signee and no authorized keys file has to be managed anymore.

generating the CA

First we need a SSH key for the purpose of a CA. This should not be the same key as your normal key in a production environment. The key is generated any other key with ssh-keygen

ssh-keygen -t ed25519 -C CA -f ca.key

You can choose any key type you want, it works with all types and any type can sign any type. The -C flag adds a comment to the key.

Now we can sign a public key.

signing a user key

First we sign a user public key foouser.pub.

ssh-keygen \
  -s ca.key \
  -I 'foouser' \
  -n foouser \
  foouser.pub

Now what do all these options mean?

To restrict the IP address for the public key, one can use the following line

-O source-address="127.0.0.1,192.168.42.1"

Any option from ssh-keygen(1) requires its own -O options, for example:

-O clear -O no-pty -O force-command="/opt/foo/bin/do_stufff"

A good source for further options is the ssh-keygen man page.

After the command was executed, a file foouser-cert.pub shows up. The content can be inspected using ssh-keygen again:

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

To get the authentication working with this key, two steps have to be taken. First is to put the generated certificated in the same directory like the private key, so that the ssh agent will sent the certificate. Second is to put the CA onto the server, so that it will trust all created certificates.

This is done with the following option in the sshd_config

TrustedUserCAKeys /etc/ssh/ssh_user_certs

where the content of the file /etc/ssh/ssh_user_certs is the ca public key. It is possible to put multiple CAs into that file.

Now one can connect to the server using the newly created key

ssh -vvv -I foouser <yourserver>

Which should print a line like

debug1: Server accepts key: pkalg ssh-ed25519-cert-v01@openssh.com blen 364
debug1: Offering ED25519-CERT public key: /home/foouser/.ssh/id_ed25519
debug3: sign_and_send_pubkey: ED25519-CERT SHA256:YYv18lDTPtT2g5vLylVQZiXQvknQNskCv1aCNaSZbmg

These three lines state for my session, that the server accepts certificates and that my certificate was sent.

With this, the first step to using SSH certificates is done. In the next post I will show how to use SSH certificates for the server side.