Using SSH certificates

Pros and cons

In previous articles I’ve explained how to use traditional SSH keys and why connecting to a wrong server could expose your password. I was reminded of a newer form of authentication supported by OpenSSH; CA keys.

The CA key model is closer to how SSL certs work; you have an authority that is trusted by the servers and clients, and a set of signed keys.

Creating the CA key

Creating a certificate authority key is pretty much the same as creating any other key

$ mkdir ssh-ca
$ cd ssh-ca
$ ssh-keygen -f server_ca
Generating public/private rsa key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in server_ca.
Your public key has been saved in
The key fingerprint is:
The key's randomart image is:
+--[ RSA 2048]----+
|Bo*.+ .          |
|+@ +.+ .         |
|* o  .. .        |
|..    ..         |
|...  E  S        |
|...              |
|...              |
|..               |
|                 |
$ ls -l
total 8
-rw------- 1 sweh sweh 1766 Oct 30 09:30 server_ca
-rw-r--r-- 1 sweh sweh  403 Oct 30 09:30

Creating and using signed host keys

Now we can start using this key to sign our host’s key. This host is We use ssh-keygen (which has grown massively from its origins!) with the -h flag to indicate “host key”. Because it’s a certificate it can have an expiration date associated with it (-V) flag; in this case 52 weeks.

$ sudo ssh-keygen -s server_ca -I key_for_test1 -h -n -V +52w /etc/ssh/
Enter passphrase: 
Signed host key /etc/ssh/ id "key_for_test1" serial 0 for valid from 2016-10-30T09:43:00 to 2017-10-29T09:44:13
$ ls -l /etc/ssh/ssh_host_rsa_key-cert*    
-rw-r--r-- 1 root root 1332 Oct 30 09:44 /etc/ssh/

We now need to tell the server to offer this certificate. In your sshd_config file you need the line

HostCertificate /etc/ssh/

Now the client also needs to be told about the CA. It does this my adding the CA’s public key into the known hosts file. This can be the clients’s global entry:

$ cat /etc/ssh/ssh_known_hosts
@cert-authority * ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC/jf9ZrH1qtVB6Gxo31bPA77WGuJ92jb9EaWNp+ht9j+s5+ZLLUm8RM1+T8vBow54IF0uavv/YLcchKIa6vmZdKmMJU5HF6SEdplGqDMDdvd+6U/cm/NQbmS0uTsLQBnCh4zptJJKeC1lc9IOCMwnz1oVA6rGdUc09rZMIDYyW2QpeFArgye5Yi57OWGJl+61QeqBMoAy/hytrYbGXYQsra5c5+PpYdPn2MbXzXY5dLf4H9usyhB+xzx8iAk5Sym4HBL6DnTnOzKAXL5fkI9XKiS3u7Hb1+7CSc0gOYoEFS+8L8kZ5iAqK5kkA0ekQO8DhzPEyZnecqx9n1C6UVb5D

Now let’s see if this works. I have no known hosts file of my own:

$ cat .ssh/known*
cat: .ssh/known*: No such file or directory
$ ssh's password: 

Hey, it didn’t ask me to accept the key!

Now I deliberately mis-signed the key for test2. I specified -n instead of -n

What happens now?

$ ssh
Certificate invalid: name is not a listed principal
The authenticity of host ' (' can't be established.
RSA key fingerprint is 58:45:95:16:c0:98:aa:5f:68:99:36:38:66:18:79:80.
Are you sure you want to continue connecting (yes/no)? 

Nice, it warns that the certificate doesn’t match and then falls back to letting you accept the key. Let’s fix the cert and try again:

$ ssh's password: 


Client keys

Now how can we use CA keys to login to the server. This is very similar to signing host keys, but without the -h flag, and we specify the username this key is valid for.

First I’ll generate my ssh key and then sign it:

$ cd
$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/sweh/.ssh/id_rsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/sweh/.ssh/id_rsa.
Your public key has been saved in /home/sweh/.ssh/
The key fingerprint is:
The key's randomart image is:
+--[ RSA 2048]----+
|                 |
|                 |
|      o .        |
|     . +         |
|      . S *      |
|     . . B o .   |
|      o o E.+ .  |
|       o +.=..   |
|        ..o.+=o  |
$ ssh-keygen -s ssh-ca/server_ca -I user_sweh -n sweh -V +52w .ssh/
Enter passphrase:
Signed user key .ssh/ id "user_sweh" serial 0 for sweh valid from 2016-10-30T10:14:00 to 2017-10-29T10:15:01

We need to configure the server to accept signed keys; the CA’s public key needs to be accessible and sshd_config needs an extra line:

TrustedUserCAKeys /etc/ssh/

Now let’s try:

$ ssh
Enter passphrase for key '/home/sweh/.ssh/id_rsa': 

test2$ cat .ssh/authorized_keys     
cat: .ssh/authorized_keys: No such file or directory

It let me in!

In /var/log/secure I can see:

Oct 30 10:19:17 test2 sshd[1967]: Accepted publickey for sweh from port 38092 ssh2: RSA-CERT ID user_sweh (serial 0) CA RSA 04:f2:60:0a:89:c0:66:2d:1c:a9:da:ca:11:60:59:bf

This also works with ssh-agent

$ eval `ssh-agent`
Agent pid 2286
$ ssh-add
Enter passphrase for /home/sweh/.ssh/id_rsa: 
Identity added: /home/sweh/.ssh/id_rsa (/home/sweh/.ssh/id_rsa)
Certificate added: /home/sweh/.ssh/ (user_sweh)
$ ssh echo hello


Signed host keys can help in avoiding need to maintain a track of host keys, and so can solve the “initial trust” issue problem. It can also solve the “host rebuild” issue. However an automation system to sign these keys when a server is built is essential for this to work.

Similarly we don’t need to distribute authorized_keys files if the user can present a signed certificate. This requires a request system (preferably self-service) where the user can present their public key and get a signed result.

Certificate authentication isn’t supported by all clients; you can expect it in OpenSSH 6.2 onwards, and companies such as RedHat may have backported it to older versions. However desktop based ssh clients such as putty may not support it.

Certificate authentication isn’t as flexible as standard key based authentication in that we don’t have an authorized_keys entry to add restrictions (from=, command=, etc) but it can solve a number of problems, particularly around host key management and distributing of authorized_keys files for human accounts; build a new server, get the host key signed and automatically we have a trust and an authentication process working.

We just need the workflows to do the signing :-)