// Tutorial //

How To Create an SSH CA to Validate Hosts and Clients with Ubuntu

Published on March 20, 2014
Default avatar
By Justin Ellingwood
Developer and author at DigitalOcean.
How To Create an SSH CA to Validate Hosts and Clients with Ubuntu

Status: Deprecated

This article covers a version of Ubuntu that is no longer supported. If you are currently operate a server running Ubuntu 12.04, we highly recommend upgrading or migrating to a supported version of Ubuntu:

Reason: Ubuntu 12.04 reached end of life (EOL) on April 28, 2017 and no longer receives security patches or updates. This guide is no longer maintained.

See Instead: This guide might still be useful as a reference, but may not work on other Ubuntu releases. If available, we strongly recommend using a guide written for the version of Ubuntu you are using. You can use the search functionality at the top of the page to find a more recent version.

Introduction

When configuring a large amount of servers that have many users, keeping SSH access in line for your infrastructure can get complicated. There are quite a few ways of implementing a centralized authentication authority, such as LDAP, but these are sometimes overkill.

SSH actually has the functionality to use a certificate authority to authenticate servers and clients. This works both ways. Using this system, you can authenticate a host to a client, avoiding confusing messages about being unable to validate the authenticity of the host. You can also validate the client to the host, allowing you to register a new SSH key in one place and allow access across your organization.

We’ll discuss how to leverage these certificates in both of the ways discussed above. We’ll be demoing this on three Ubuntu 12.04 VPS instances. One will serve as the host, another as the client, and the third will function as the certificate authority.

How To Configure Host Certificates

We will start by configuring certificates that will authenticate our servers to our clients. This will allow our clients to connect to our servers without needing to question the authenticity of the server.

We begin on the machine that we will be using as the certificate authority. In this example, we’ll refer to this as “auth.example.com”.

Generating Signing Keys

First, we need to generate some RSA keys that will function as the signing keys. Use any user you’d like, but the root user is probably a good idea. We will be creating keys called “server_ca” and “server_ca.pub” since these will be used to authenticate our servers.

Let’s create these keys in our home directory:

cd ~
ssh-keygen -f server_ca

You will be asked if you’d like to create a passphrase. This will add an additional layer of protection to your key in the event that it falls into the wrong hands. Once this is finished, you’ll have a private and public key in your home directory:

ls

server_ca   server_ca.pub

Signing Host Keys

Now that we have our keys, we can begin signing our host keys.

We should start by signing the host key of the certificate authority itself. We can do this using the following syntax:

<pre> ssh-keygen -s <span class=“highlight”>signing_key</span> -I <span class=“highlight”>key_identifier</span> -h -n <span class=“highlight”>host_name</span> -V +52w <span class=“highlight”>host_rsa_key</span> </pre>

Let’s go over what all of this means.

  • -s: This is the private key that we just created that we will use to sign all of the other keys.
  • -I: This is a name that is used to identify the certificate. It is used for logging purposes when the certificate is used for authentication.
  • -h: This marks the resulting certificate as a host key, as opposed to a client key.
  • -n: This is used to identify the name (user or host) that is associated with this certificate.
  • -V: This specifies how long the certificate is valid for. In this instance, we specify that the certificate will expire in one year (52 weeks).

Afterwards we specify the key that we want to sign.

In our case, to sign our own host RSA key, we will use a line that looks like this. We are going to identify this server as “host_auth_server”. We will be prompted for the passphrase we used when creating the signing key:

ssh-keygen -s server_ca -I host_auth_server -h -n auth.example.com -V +52w /etc/ssh/ssh_host_rsa_key.pub

Signed host key /etc/ssh/ssh_host_rsa_key-cert.pub: id "host_auth_server" serial 0 for auth.example.com valid from 2014-03-20T12:25:00 to 2015-03-19T12:26:05

As you can see from the output, our certificate is valid for one year. It has been created in the same directory as our server host key (/etc/ssh/) and is called “ssh_host_rsa_key-cert.pub”.

Now that we have signed our host key on the certificate authority itself, we can sign the host key for the separate SSH server we’re trying to authenticate to clients.

Copy the host key from our SSH server. We’ll refer to this machine as “sshserver.example.com”. You can do this using scp:

cd ~
scp root@sshserver.example.com:/etc/ssh/ssh_host_rsa_key.pub .

Now, we can create a certificate from this file using the same method we used above. We’ll need to change some values to refer to the new host we’re signing:

ssh-keygen -s server_ca -I host_sshserver -h -n sshserver.example.com -V +52w ssh_host_rsa_key.pub

Signed host key ssh_host_rsa_key-cert.pub: id "host_sshserver" serial 0 for sshserver.example.com valid from 2014-03-20T12:40:00 to 2015-03-19T12:41:48

Now, we need to copy the generated certificate file back onto the host. Again, we can use scp for this:

scp ssh_host_rsa_key-cert.pub root@sshserver.example.com:/etc/ssh/

Afterwards, we can delete both the SSH server’s public key and certificate from our authentication server:

rm ssh_host_rsa_key.pub ssh_host_rsa_key-cert.pub

We now have the signed certificates in place, we just need to configure our components to use them.

Configuring Components to Use Host Certs

First, we need to continue with both of our servers (auth.example.com and sshserver.example.com) to make them aware of the certificate files we created.

On both of these machines, we’ll have to edit the main SSH daemon configuration file. Make sure you are editing the sshd_config file, not the ssh_config file:

sudo nano /etc/ssh/sshd_config

If you can find a HostCertificate line, modify it. Otherwise, add this to the bottom of the file. We need to establish to path to our host certificate file:

HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub

Save and close the file when you are finished.

Now, restart the SSH daemon to make these changes happen:

sudo service ssh restart

Do this on all of the servers you are configuring host certificates for.

Now, our servers are configured to use the certificate, but our client does not know how to check the certificate that the server will present.

On our client machine, which we’ll be referring to as “client.example.com”, open or create the “~/.ssh/known_hosts” file:

nano ~/.ssh/known_hosts

We need to remove any entries that have to do with the servers we’re configuring for certificate entry. It may be best to delete everything.

Afterwards, we need to add a special entry that specifies the public key that we should use to check the certificate that our hosts will give us during login. Start it off with @cert-authority. Afterwards, it can include a domain restriction where the key will be applied, followed by the public certificate authority key that we’ve been signing everything with.

On your certificate authority machine, you can get the public certificate signing key by typing:

cat ~/server_ca.pub

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCxC+gikReZlWEnZhKkGzhcNeRD3dKh0L1opw4/LQJcUPfRj07E3ambJfKhX/+G4gfrKZ/ju0nanbq+XViNA4cpTIJq6xVk1uVvnQVOi09p4SIyqffahO9S+GxGj8apv7GkailNyYvoMYordMbIx8UVxtcTR5AeWZMAXJM6GdIyRkKxH0/Zm1r9tsVPraaMOsKc++8isjJilwiQAhxdWVqvojPmXWE6V1R4E0wNgiHOZ+Wc72nfHh0oivZC4/i3JuZVH7kIDb+ugbsL8zFfauDevuxWeJVWn8r8SduMUVTMCzlqZKlhWb4SNCfv4j7DolKZ+KcQLbAfwybVr3Jy5dSl root@auth

Using this information, the line in your ~/.ssh/known_hosts file should look like:

@cert-authority *.example.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCxC+gikReZlWEnZhKkGzhcNeRD3dKh0L1opw4/LQJcUPfRj07E3ambJfKhX/+G4gfrKZ/ju0nanbq+XViNA4cpTIJq6xVk1uVvnQVOi09p4SIyqffahO9S+GxGj8apv7GkailNyYvoMYordMbIx8UVxtcTR5AeWZMAXJM6GdIyRkKxH0/Zm1r9tsVPraaMOsKc++8isjJilwiQAhxdWVqvojPmXWE6V1R4E0wNgiHOZ+Wc72nfHh0oivZC4/i3JuZVH7kIDb+ugbsL8zFfauDevuxWeJVWn8r8SduMUVTMCzlqZKlhWb4SNCfv4j7DolKZ+KcQLbAfwybVr3Jy5dSl root@auth

Save and close the file when you’re done.

Now, when you visit the SSH server for the first time from your client (using the full hostname), you should not be asked whether you trust the remote host. This is because the host has presented its host certificate to you, signed by the certificate authority. You’ve checked your known_hosts file and verified that the certificate is legitimate.

How To Configure User Keys

Now that we’ve learned how to authenticate servers to our users, we can also configure our certificate authority to authenticate our users to our servers.

As before, this process will start on our certificate authority server. We will need to generate a new set of keys, this time, to sign user certificates:

ssh-keygen -f users_ca

Again, select a passphrase so that your key will be protected if someone gains access.

Configuring Servers to Accept Logins with the User Certification

When you are done, you will need to copy the public key onto each of your SSH servers that need to validate user authenticity. We will do this using scp as usual:

scp users_ca.pub root@sshserver.example.com:/etc/ssh/

We need to modify our SSH daemon configuration on our SSH server to look for this key.

On our “sshserver.example.com” host, open the configuration file:

sudo nano /etc/ssh/sshd_config

At the bottom, below our HostCertificate line, we need to add another line that references the file we just copied over:

TrustedUserCAKeys /etc/ssh/users_ca.pub

Again, we’ll need to restart the SSH daemon for these changes to take place:

sudo service ssh restart

Signing User Login Keys

Now that the servers are configured to trust keys signed by the users_ca key, we need to actually sign the users’ authentication keys so that this scheme will work.

First, we need to get our client key onto the certificate authority server with scp. From the cert server, type:

<pre> cd ~ scp <span class=“highlight”>username</span>@client.example.com:/home/<span class=“highlight”>username</span>/.ssh/id_rsa.pub . </pre>

Now that we have the key on the cert machine, we can sign it using our users_ca key. This will be very similar to last time we signed keys using the server_ca keys, only now, we don’t include the -h parameter, because these are user keys.

The command we want is something like this. Change the “username” value to reflect the name of the user you’re signing for easier management:

<pre> ssh-keygen -s users_ca -I user_<span class=“highlight”>username</span> -n <span class=“highlight”>username</span> -V +52w id_rsa.pub </pre> <pre> Signed user key id_rsa-cert.pub: id “user_username” serial 0 for username valid from 2014-03-20T14:45:00 to 2015-03-19T14:46:52 </pre>

You will be prompted for the users_ca passphrase that set during the key’s creation. Now, we have an id_rsa-cert.pub file in our directory that we need to transfer back onto our client machine:

<pre> scp id_rsa-cert.pub <span class=“highlight”>username</span>@client.example.com:/home/<span class=“highlight”>username</span>/.ssh/ </pre>

Now, when you log into sshserver.example.com from your client computer, you should not be asked for your authentication details, even if you’ve never before logged into this server as this user.

Conclusion

By signing your host and user keys, you can create a more flexible system for user and server validation. This allows you to set up one centralized authority for your entire infrastructure, in order to validate your servers to your user, and your users to your servers.

While perhaps not the most powerful way of creating centralized authentication, it is easy to set up and leverages existing tools without requiring a lot of time and configuration. It also has the advantage of not requiring the CA server to be online to check the certificates.

<div class=“author”>By Justin Ellingwood</div>

If you’ve enjoyed this tutorial and our broader community, consider checking out our DigitalOcean products which can also help you achieve your development goals.

Learn more here


About the authors
Default avatar
Developer and author at DigitalOcean.

Still looking for an answer?

Was this helpful?
10 Comments

This textbox defaults to using Markdown to format your answer.

You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

why did you create two different CA for host and users? host key are signed with the -h switch, so I cannot use host key/cert to authenticate me as user on different host (and viceversa cannot use users cert to spoof an host)… what is the advantage in having two different CAs for the two use-case?

Excellent, I have been looking for this info for a very long time.

I am still concerned about the integrity of this system because ultimately all this still rely on a password. Say I setup my android tablet, my phone or even some pc somewhere, if someone gets hold of one of these the server protection comes down to just a password and only if the server side require the user password. I wouldn’t be surprised if most of these ssh clients on these devices allow a one click login.

I thought of adding second factor like say google-authentication but again how do I know the google app is not on the same device as the ssh client?

Food for thoughts… Thanks, YG

Great article, but is there a way that I can check the validity of the signed key of a user ?

Great article. Is it possible to setup such auth on Windows SSH client? Which one?

I have one server and 3 clients accessing it. I want to opt for certificate based ssh but i am unable to understand why one needs a separate CA server? Is it possible to have the CA on my host server itself? If yes then how do the configurations change?

Thanks this is great <3 If you have enough servers/users to have a certificate authority, woudln’t revoking a certificat still be as painfull as not having a ca?

@jellingwood, thanks for your reply!

Very helpful article, thanks! Question: for this to work the user has to live locally on the server that the client wants to SSH to (target machine.) Is there a way to be able to do this without having to create a local user on the target machine? For example in LDAP we can set some attributes at the LDAP server to dictate what the user can do on the machine, and thus the target machine does not need to have any record of the user. If there a way to do the same with the certificate being generated?

Very clear and easy to follow. I think there is one step missing in the Signing User Login Keys section where the client keypair has not been created anywhere so when you do the copy to the CA the key does not yet exist.

How would one connect using putty?