Creating an using a SSH cert authority

Rationale TL;DR

Let’s suppose you would like to use a better solution to authenticate your ssh users all across your infrastructure.

The solution

Since OpenSSH 5.4 (2010) you can create CA (certificate authorities) and use them to authenticate:

  • Users
  • Hosts

It means, you can instruct your ssh deamon to authenticate specific users or authenticate any user from a host. To achieve that, it is advisable to use two different certificate authorities, that way if one is compromised you can still use the other one.

I’ll concentrate on users, a future post would talk about host authorities.

The first step is to create a certificate authority somewhere. It does not matter where you keep those files but you need to understand that the private key must remain safe. If you lose it your CA is compromised.

Let’s first create the user CA authority:

[root@harkserver ~]# ssh-keygen -t ed25519 -b 4096 -f /etc/ssh/harkserver_ed25519_user_ca -C "Harkserver user authority"
Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in harkserver_ed25519_user_ca.
Your public key has been saved in harkserver_ed25519_user_ca.pub.
The key fingerprint is:
SHA256:WNvsYXjKyEsLltfED5EXwRJXAcSqzngwk29o6crk6ho Harkserver user authority
The key's randomart image is:
+--[ED25519 256]--+
|        .=*+o.   |
|        .oo.     |
|        +o.      |
|       +.B       |
|     ...S *      |
|    =o.= B .     |
|E . +@= + o      |
| = .=+*o         |
|=o++.oo          |
+----[SHA256]-----+

Let me explain the flags:

  • The -t flag tells ssh-keygen to use the Edwards-curve Digital Signature Algorithm (EdDSA)
  • The -f tells ssh-keygen to keep the private and public keys in the /etc/ssh directory
  • The -b tells ssh-keygen to generate 4096 bits keys
  • The -C adds a comment in the public key

This will generate two files:

[root@harkserver ~]# ls -la /etc/ssh/*harkser*
-rw-------  1 root  wheel   419 Jun 26 10:53 /etc/ssh/harkserver_ed25519_user_ca
-rw-r--r--  1 root  wheel   107 Jun 26 10:53 /etc/ssh/harkserver_ed25519_user_ca.pub

User certificates

Now it’s time to issue user certificates. To do so we need to:

  • Generate the private key and the public key (the public, if I understand it correctly) works as a sort of CSR (signing request)
  • Sign the keys to generate the public certificate that would be used to log

To generate the cert:

[root@harkserver ~]#  ssh-keygen -f /etc/ssh/gus_harkserver_ed25519 -b 4096 -t ed25519
Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /etc/ssh/gus_harkserver_ed25519.
Your public key has been saved in /etc/ssh/gus_harkserver_ed25519.pub.
The key fingerprint is:
SHA256:VnIZf3OgnIRk4rO4LS1uMADMtjD+yZ6TUHQMlQNLt/8 root@harkserver
The key's randomart image is:
+--[ED25519 256]--+
|o  +=o. ..+.. .  |
|++..o=.. o.* o . |
|+oo.... + + = o .|
| o..  .. *   . o |
|  +.. ..S        |
| . +o  =.        |
|  o oo+ oE       |
|   = ..o         |
|    ...          |
+----[SHA256]-----+

This generated a public and private keys:

[root@harkserver ~]# ls -la /etc/ssh/*gus*
-rw-------  1 root  wheel  411 Jun 26 11:19 /etc/ssh/gus_harkserver_ed25519
-rw-r--r--  1 root  wheel   97 Jun 26 11:19 /etc/ssh/gus_harkserver_ed25519.pub

Now, it is time to sign the public key. To do so, we need the private CA key:

[root@harkserver ~]# ssh-keygen -s /etc/ssh/harkserver_ed25519_user_ca -I gus@harkserver -n gus /etc/ssh/gus_harkserver_ed25519.pub
Signed user key /etc/ssh/gus_harkserver_ed25519-cert.pub: id "gus@harkserver" serial 0 for gus valid forever

In this example, the ca private key is /etc/ssh/harkserver_ed25519_user_ca. I’m also telling ssh-keygen to add an identifier -I gus@harkserver so that I can identify a user login. Also, I’m granting that key to log as gus with the flag -n.

The resulting files are:

[root@harkserver ~]# ls -la /etc/ssh/*gus*
-rw-------  1 root  wheel  411 Jun 26 11:19 /etc/ssh/gus_harkserver_ed25519
-rw-r--r--  1 root  wheel  650 Jun 26 11:22 /etc/ssh/gus_harkserver_ed25519-cert.pub
-rw-r--r--  1 root  wheel   97 Jun 26 11:19 /etc/ssh/gus_harkserver_ed25519.pub

A new file appeared: /etc/ssh/gus_harkserver_ed25519-cert.pub. This is the public cert file. We can check its contents:

[root@harkserver ~]# ssh-keygen -L -f /etc/ssh/gus_harkserver_ed25519-cert.pub
/etc/ssh/gus_harkserver_ed25519-cert.pub:
        Type: ssh-ed25519-cert-v01@openssh.com user certificate
        Public key: ED25519-CERT SHA256:VnIZf3OgnIRk4rO4LS1uMADMtjD+yZ6TUHQMlQNLt/8
        Signing CA: ED25519 SHA256:WNvsYXjKyEsLltfED5EXwRJXAcSqzngwk29o6crk6ho
        Key ID: "gus@harkserver"
        Serial: 0
        Valid: forever
        Principals:
                gus
        Critical Options: (none)
        Extensions:
                permit-X11-forwarding
                permit-agent-forwarding
                permit-port-forwarding
                permit-pty
                permit-user-rc

As you can see, it’s valid forever. You can use the -V flag to tune the validity of the certificate.

Like the CA files, there’s one file that must remain private, the /etc/ssh/gus_harkserver_ed25519 must remain secret.

Configuring a ssh daemon to trust the User CA

Finally, we need to set up the ssh server so that it trusts the certificates issued by the user CA. To do so, open the sshd_config file (usually /etc/ssh/sshd_config ) and set the TrustedUserrCAKeys config:

TrustedUserCAKeys /etc/ssh/harkserver_ed25519_user_ca.pub

That way the server would trust user certificates signed by the CA. Remember to restart the service. Also, ensure you have another way to log into the machine (maybe a local ssh user with sudo ability or maybe access to the console), otherwise you may shoot yourself in the foot by kicking you out of the machine.

The last step would be to copy those keys to a remote machine and use them to connect to our server. For example, you can change your ~/.ssh/config with the following config:

Host home
    Hostname        my.server.example.org
    User            gus
    Port            22081
    IdentityFile    ~/.ssh/gus_harkserver_ed25519

In another post I’ll also try to explain how to revoke those certificates.