Creating an using a SSH cert authority
26 Jun 2021 | tags: opensshRationale 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 tellsssh-keygen
to use the Edwards-curve Digital Signature Algorithm (EdDSA) - The
-f
tellsssh-keygen
to keep the private and public keys in the/etc/ssh
directory - The
-b
tellsssh-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.