Programster's Blog

Tutorials focusing on Linux, programming, and open-source

SSHing Into Servers Using Signed Temporary Certificates

SSH

Introduction

This tutorial outlines how one can manually create signed OpenSSH certificates in order to grant temporary access to a servers. This is what Vault (by HashiCorp) essentially does under the hood when one configures it to grant users temporary access to a server. The only difference is that we are doing performing the actions manually, and due to the slow nature of doing things manually, we will need to set a TTL/expiry that has a longer duration (e.g. many minutes instead of seconds).

The methodology outlined here is to do with OpenSSH certificates, which are somewhat different from x509 certificates. While OpenSSH primarily uses its own certificate format, it also has limited support for x509 certificates, so they may also work.

Steps

Create The Certificate Authority (CA)

Create the key for our certificate authority. This only needs to be done once, as this is essentially the key that will be trusted by our servers, and will sign our later generated "client" keys, to grant temporary access to our server(s). These server resources will only accept these temporary keys if they have also been configured to trust our certificate authority, which also means that if you wish to swap out the certificate authority key, you will need to reconfigure all of the servers again with this new key.

Create the private key for our certificate authority.

ssh-keygen -f cert_auth -b 4096

The -f specifies the filepath for the newly generated certificate (in this case a relative path instead of absolute), and the -b specifies the number of bits for the key, in this case being 4096 bits stong. For compatibility reasons for other systems you may need to reduce this down to 2048.

You don't have to call the file cert_auth but it does help prevent confusion.

This will have generated the private key at the path specified, and a public key of the same name but with the .pub extension attached. You need to remember this for the later steps where I refer to the public and private keys.

Configure Server

The sub-steps within this section need to be repeated for all of the servers that you wish to make use of this SSH methodology for. Thus you will likely need to refer back to here when you deploy a new server.

Copy The Public Key To Server

Copy the certificate authority (CA) public key to the server.

Set Key Path / Permissions

Now we need to move it to where it needs to be ensure the correct ownership/permissions are applied to it:

mv -i cert_auth.pub /etc/ssh/cert_auth.pub
sudo chmod 0600 /etc/ssh/cert_auth.pub
sudo chown root:root /etc/ssh/cert_auth.pub

Configure SSH Service To Trust The Key

Now we need to configure the SSH service on the server to know about the key and trust other keys that are signed by it.

sudo editor /etc/ssh/sshd_config

Now find the TrustedUserCAKeys and add the filepath to it like so.

# Allow access from signed keys
TrustedUserCAKeys /etc/ssh/cert_auth.pub

On my Ubuntu 20.04 machine, the clause didn't exist, so I needed to add it. There can only be one of these clauses, with it containing just one filepath. If you already have an entry with a different filepath, then you will need to simply add your new CA public key to the end of that file on its own line (each public key needs to be on its own line in that file). You may wish to refer to the manual page for this entry.

Validate SSH Config and Apply

Now let's validate that our SSH config is valid and we didn't make some sort of typo/mistake:

sudo /usr/sbin/sshd -t 

The -t stands for "test mode", telling the SSH service to just validate/test. If everything is successful you will get no output from the command. Only if something is wrong will you see any output, which will be error messages.

Assuming that came back clear, then we need to tell the SSH service to make use of the new configuration (reload rather than restart):

sudo service ssh reload

We have now finished setting up the server to trust keys that are signed by our CA.

Create Client Signed Public Key

Now let's create a key that will be signed by our CA in order to grant a user temporary access to our resources.

Create Key Pair

ssh-keygen -f myTemporaryKey

Sign Temporary Public Key

Now assuming that the certificate authority's private key is only on the server where we left it, copy the public key of this temporary key over to the server so that it can sign it. Please note that we are able to keep the client's private key a secret from the certificate authority, and we are able to keep the certificate authority's private key a secret from the client.

scp myTemporaryKey.pub my-ca-server:/home/programster/.

This is just for demonstration purposes. Transfer the public key to the area that has the CA private key so that we can run a command later to sign it.

Now sign this public key to grant it temporary access to our resources:

USER_REAL_NAME="Programster"
TTL="+1d"
CA_PUBLIC_KEY="cert_auth"
SSH_USERNAMES="admin,ubuntu,root"
USERS_PUBLIC_KEY="myTemporaryKey.pub"

ssh-keygen \
  -s $CA_PUBLIC_KEY \
  -I $USER_REAL_NAME \
  -n $SSH_USERNAMES \
  -V $TTL \
  $USERS_PUBLIC_KEY

The -n is for specifying any number of principals (usernames) that the key can be used to login as. This way you could restrict the key to only be able to login as a specific user account. If you wish to allow the key to be used to login as any username then simply just remove this line, as that is the default behaviour.

After having performed this action, you will have a new, signed version, of the public key, which will have the -cert.pub suffix instead of just .pub. Also the contents of the file will start like so:

ssh-rsa-cert-v01@openssh.com XXXXXXXXXX...

... instead of

ssh-rsa XXXXXXXXXX...

Login

Now let's test everything worked by trying to login using our freshly minted OpenSSH certificate and public key. We can do this by running either of the following commands (both will work although I believe the first is more technically correct).

ssh \
  -i /path/to/private/key \
  -o CertificateFile=/path/to/signed-cert.pub \
  username@10.0.23.5
ssh \
  -i /path/to/private/key \
  -i /path/to/signed-cert.pub \
  username@10.0.23.5

SSH Defaults

  • If your signed public certificate is in the same folder as the private key, and has the same name with either just the .pub or -cert.pub suffix, then it will automatically be used and work without being manually specified.

  • If your private key is at ~/.ssh/id_rsa it will automatically be used and would not need specifying.

SSH Config File

For repeated quick access to a server, its nice to configure the connection details in the ~/.ssh/config file, and create an alias for the server which can be done like so:

Host my-server-alias
    User myUsername
    Port 22
    Hostname 192.168.0.1
    IdentityFile /path/to/private/key
    CertificateFile /path/to/signed/public/key

I also found that through manual testing, one can just use IdentityFile twice instead of using CertificateFile and it will still work:

Host my-server-alias
    User myUsername
    Port 22
    Hostname 192.168.0.1
    IdentityFile /path/to/private/key
    IdentityFile /path/to/signed/public/key

Again, if the public key is in the same folder as the private key, with the same name but with the .pub or -cert.pub suffix attached, it will automatically work without needing to be specified.

If you entered all of the details correctly, the file permissions on the certificates were correct, and the expiry time was not reached, then you should have successfully logged into the server.

References

Last updated: 26th February 2024
First published: 26th February 2024