SSHing Into Servers Using Signed Temporary Certificates
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).
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
-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.
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
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
-t
stands for "test mode", telling the SSH service to just validate/test.
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/.
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
-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
.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
- How to give temporary access with SSH using certificate authority?
- Simplifying TLS And Using It For Docker
- Lecture - Manage SSH With HashiCorp Vault
- ServerFault - How do I connect to ssh with a different public key?
- SuperUser - SSH - how to specify path for user certificate?
- Youtube - SSH Certificate Authority Rocky Linux 8
- This is the same concept but in reverse, in which we add signed public keys to the servers so that I as the client only need to trust one CA, and not add hundreds of server public keys to may trusted hosts file.
- HashiCorp Vault documentation - Signed SSH Certificates
- man7.org - ssh_config(5) — Linux manual page
- RedHat Docs - Using OpenSSH Certificate Authentication
First published: 26th February 2024