OpenSSH Certificate Authority


openssh logo

Intro

OpenSSH supports a Certificate Authority (CA) function.

This allows you to distribute one or more trusted CA keys. Then if you want to give access to users, you simply sign their public keys with the CA private key.

Users then can login to a server without having to have their public keys in the authorized_keys file as long as their public key was signed by a trusted CA.

Furthermore, when signing keys, you can apply further restrictions such as:

  • user allowed to login as
  • validity periods
  • SSH restrictions similar to the options in the authorized_keys file. e.g. forced command, no-pty`, restrict tcp forwarding, etc.
  • IP addresses that the key can originate from
  • and more...

For larger organizations with lots of users and servers, makes managing authorizition keys a much simpler process.

Creating CA

To begin using OpenSSH certificates you first must generate an ssh key that will be kept secret and used as the certificate authority in your environment. This can be done with a command like:

ssh-keygen -f my_ssh_cert_authority

That command outputs two files:

  • my_ssh_cert_authority: The encrypted private key for your new authority
  • my_ssh_cert_authority.pub: The public key for your new authority.

Be sure you choose a passphrase when prompted so that the secret is stored encrypted. Other options to ssh-keygen are permitted including both key type and key parameters. For example, you might choose to use ECDSA keys instead of RSA.

Grab the fingerprint of your new CA:

$ ssh-keygen -l -f my_ssh_cert_authority
2048 2b:a1:16:84:79:0a:2e:38:84:6f:32:96:ab:d4:af:5d my_ssh_cert_authority.pub (RSA)

Configuring Hosts

Now that you have a certificate authority you'll need to tell the hosts in your environment to trust this authority. This is done very similar to user SSH keys by setting up the authorized_keys on your hosts (the expectation is that you're setting this up at launch time via cloudinit or perhaps baking the change into an OS image or other form of snapshot).

You have a choice of putting this authorized_keys file into $HOME/.ssh/authorized_keys or the change can be made system wide. For system wide configuration see sshd_config(5) and the TrustedUserCAKeys option.

If you are modifying the user's authorized_keys file simply add a new line to authorized_keys of the form:

cert-authority <paste the single line from my_ssh_cert_authority.pub>

A valid line might look like this for an RSA key:

cert-authority ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAYQC6Shl5kUuTGqkSc8D2vP2kls2GoB/eGlgIb0BnM/zsIsbw5cWsPournZN2IwnwMhCFLT/56CzT9ZzVfn26hxn86KMpg76NcfP5Gnd66dsXHhiMXnBeS9r6KPQeqzVInwE=

If configuring system-wide, modify your /etc/ssh/sshd_config to include:

TrustedUserCAKeys /etc/ssh/ca_keys

Copy the CA public keys:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAAAYQC6Shl5kUuTGqkSc8D2vP2kls2GoB/eGlgIb0BnM/zsIsbw5cWsPournZN2IwnwMhCFLT/56CzT9ZzVfn26hxn86KMpg76NcfP5Gnd66dsXHhiMXnBeS9r6KPQeqzVInwE=

You can have multiple CA public keys in this file. This can be used to keep CA keys off-line and rotate them on a regular basis. Storing offline CA keys is also useful to provide emergency access in the event of a compromised CA key.

Singing user public keys

At this point your host has been configured to accept a certificate signed by your authority's private key. Let's generate a certificate for ourselves that permits us to login as the user ubuntu and that is valid for the next hour (This assumes that our personal public SSH key is stored at ~/.ssh/id_rsa.pub) :

ssh-keygen -V +1h -s my_ssh_cert_authority -I bvanzant -n ubuntu ~/.ssh/id_rsa.pub

The output of that command is the file ~/.ssh/id_rsa-cert.pub. If you open it it's just a base64 encoded blob. However, we can ask ssh-keygen to show us the contents:

$ ssh-keygen -L -f ~/.ssh/id_rsa-cert.pub
/tmp/test_main_ssh-cert.pub:
    Type: [email protected] user certificate
    Public key: RSA-CERT f6:e3:42:5e:72:85:ce:26:e8:45:1f:79:2d:dc:0d:52
    Signing CA: RSA 4c:c6:1e:31:ed:7b:7c:33:ff:7d:51:9e:59:da:68:f5
    Key ID: "bvz-test"
    Serial: 0
    Valid: from 2015-04-13T06:48:00 to 2015-04-13T07:49:13
    Principals:
            ubuntu
    Critical Options: (none)
    Extensions:
            permit-X11-forwarding
            permit-agent-forwarding
            permit-port-forwarding
            permit-pty
            permit-user-rc

Using certificates

Let's use the certificate now::

# Add the key into our ssh-agent (this will find and add the certificate as well)
ssh-add ~/.ssh/id_rsa
# And SSH to a host
ssh ubuntu@<the host where you modified authorized_keys>

If the steps above were followed carefully you're now SSHed to the remote host. Fancy?

At this point if you look in /var/log/auth.log (Ubuntu) (/var/log/secure on Red Hat based systems) you'll see that the user ubuntu logged in to this machine. This isn't very useful data. If you change the sshd_config on your servers to include LogLevel VERBOSE you'll see that the certificate key id is also logged when a user logs in via certificate. This allows you to map that user bvanzant logged into the host using username ubuntu. This will make your auditors happy.

Further reading