Securing SSH With Passwordless Public Key Authentication

| 9 min read

Introduction

When you launch a shell session to a remote computer or server via SSH, the default behavior will prompt you for a password. This is called "Password Authentication". We can use public ky cryptography to provide us an alternate method for authentication, that can provide us with added security, convenience, and scalability benefits. This method is called "Public Key Authentication", or "SSH Key Authentication", and it is the topic of this article.

Summary

We will talk about the motivation behind public key authentication. Why should you use it instead of password authentication? We will then explain what it is and how it works, then go through the setup process (which is fairly easy). We will then end with a discussion on best practices and security considerations.

Feel free to skip around if you only want the how-to.

Why Use Public Key Authentication?

Passwords Suck

The biggest and most important reason to use SSH keys is that passwords suck. Seriously, passwords have a ton of problems and are also annoying to use. You have to make them strong and complex, you have to use different ones for each account and use case, but at the same time you also have to remember them all. It's a bit contradictory, isn't it?

Depending on passwords for authenticating SSH means your security is only as good as your password's strength, uniqueness, and your users' handling of the password.

SSH cryptographic keys are random and longer than any password you will memorize, except you don't have to memorize them!

Having to Type a Strong Password Every Time you Authenticate

Having to type a password every time you authenticate is tedious, especially when the password is made longer and include different types of characters for added strength. While this is more about convenience, many users resort to unsafe methods, such as keeping the password in a non-encrypted note for easy copy-pasting.

While there are work-arounds that make it easier, such as making a password not required for a certain duration of time after it is entered, that does not eliminate the issue entirely, and in some cases may compromise security.

Passwords Prone to Human Error

We already discussed some of those above. Humans commit a lot of mistakes in favor of convenience when handling passwords. Writing them down on paper where others can see, writing them on notes on shared computers, sending them via unencrypted messages, making them weak, relating them to personal information (like using your dog's name) and so on.

Passwords Struggle at Scale

Consider the issues that arise due to scale, like in enterprise settings. For example, you have to share the password, and you have to make sure to do it via a secure method, where most people typically do not.

Even methods deemed secure have issues. It only takes one person messing up to compromise the security of the system, and suddenly everyone has to use a new password.

With SSH keys, every person, user, or connecting device can have their own key. Any of these keys can be invalidated without affecting the others.

SSH Keys Allow Secure Automation

SSH Keys allows for authentication without manual steps. As long as the client already has the right private key in an expected location, running the ssh command can authenticate immediately. This allows for secure automated tasks (including via shell scripts) involving SSH connections, which are often utilized in enterprise settings.

Passwords are Sent Over to the Server

This is not a significant concern, as OpenSSH employs state of the art cryptography to secure and authenticate the session, even when using passwords. While it is true that, with password authentication, the client must send the password to the server, the password is strongly encrypted, and it would be highly unlikely for someone to retrieve the password if the connection is intercepted.

Still, it is worth mentioning that with public key authentication, the key used for authentication technically never has to leave your computer, encrypted or not.

How does it work then, if it does not have to be sent over? How does the server know I am who I am? Let's find out in the next section!

How it Works

SSH Public Key Authentication, as evident from its name, uses Public Key Cryptography or Asymmetric Cryptography. This is contrasted with Private Key Cryptography, or Symmetric Cryptography.

Symmetric Cryptography

Private key cryptography involves the creation of a single (cryptographic) key called the private key. This key is usually stored in a file. If you look at it, you'll find it is a string of random characters. You can think of it as one really strong and long password that you don't have to memorize.

This key is used to encrypt data (whether it is messages, files, passwords, etc), but it is also the same key that can decrypt it. This is why it is called symmetric encryption. The same key is used for both encryption and decryption.

Public Key Cryptography

Public key cryptography, on the other hand, usually involves a pair of two keys: One key is called the private key, the other is the public key. The private key must be kept secret at all costs; keeping it secret is detrimental to the mechanism's security. Whereas exposing the public key is not as detrimental, and sometimes poses insignificant risks depending on the situation.

In public key cryptography, if a message is encrypted via one of the key pair, it can only be decrypted by the other key, and vice versa. For example, if we encrypt a message using the private key, we cannot decrypt that message even with the private key. But we can decrypt it using the public key, and only with the public key.

Encryption can Prove Identity

While encryption can be used to conceal and secure the content of a message, it can also be used to prove identity. This is sometimes called a Cryptographic Signature or Digital Signature. How does it work exactly?

Suppose I create a cryptographic public-private key pair (we will see how to do this later below). I give you the public key, while I keep the private key. Then, suppose I send you a message I encrypted using the private key. You decrypt it successfully, and are able to read it. Yay! But wait. What about proving identity?

Well, there is something else that happened here. The fact that you were even able to decrypt the message proves something: this message was encrypted using the private key. Not any private key, but the one that corresponds to the public key I gave you! This proves to you that this message came from me, and only me (or, possibly, someone who stole my private key).

Alternatively, suppose someone else sends you a message trying to pretend to be me. If they do not have my private key, then when you attempt to decrypt the message via the public key that I gave you, then it will fail to give you a readable message. This will prove to you that whoever sent this message is most likely not me.

This is crucial, because SSH uses this characteristic of asymmetric cryptography for authentication. It is a way for a client to prove they are who they are; a client that is granted access to SSH into the system.

How SSH Public Key Authentication Works

When using public key cryptography with SSH, first of all, we have to have our key pair as we discussed earlier.

The public key must be stored on the remote server that we would connect to or SSH into. This server may have several public keys belonging to more than one entity that may attempt to SSH into it.

The client holds the private key, where it will use it to prove its identity to the server when it attempts to connect. If the private key on the client matches with the public key on the server, then it should succeed. But how does it happen exactly?

The exact mechanism varies by protocol, which can be configured. But here is an example of how it commonly happens.

When the client initiates the SSH connection with the server, initially, the two machines create the initial handshake to calculate a secret shared key. This key does not grant the client access yet, but is used to secure the following communications.

Assuming the right configurations are set (discussed further down), the client creates a message based on the session ID, and signs it with the private key it has. It then sends both the signed message (but without session ID) and the corresponding public key to the server (alongside other data like username, protocol, etc).

On the server side, the supplied public key is checked to verify if it is in the authorized list of public keys for the supplied username. Then, the server prepends the session ID back to the signed message, and attempts to verify the signature. If that is successful, the server grants the client access, and a shell session is launched!

Using SSH Public Key Authentication

Generating SSH Key Pair

On the client (the device that will initiate the SSH connection to the server), use ssh-keygen to generate a SSH key pair. You can use the -t option to specify the type of key generated. The default is rsa, but ed25519 is another recommended alternative.

nezar@cosmicbytes ~ $ ssh-keygen -t ed25519

You'll get the following output, asking you to choose the file where the key will be saved. If you hit enter, it will save it in the default path it specifies.

Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/nezar/.ssh/id_ed25519): 

It will then ask you to enter an optional passphrase. The passphrase provides added security by encrypting the key and making it only accessible by entering the passphrase, but it does require you to type it whenever you initiate SSH connection. If you do not wish to use a passphrase and keep things passwordless, leave it empty and just hit Enter.

Enter passphrase (empty for no passphrase):
Your identification has been saved in /home/nezar/.ssh/id_ed25519
Your public key has been saved in /home/nezar/.ssh/id_ed25519.pub

Now we have our key pair generated!

Adding the Public Key to the Server's Authorized List

Next, we need to tell the server that if they ever get a SSH client attempting to authenticate with the private key we just generated, that they should accept it. To do this, we must first add the public key that we generated on the client to the server's authorized list.

Using ssh-copy-id

If you can already SSH to the server from the host (presumably via password), this can be automated using the ssh-copy-id utility. You can use it just like you would use the ssh command, but instead of it launching a shell session, it sends the public key to the server and adds it to its authorized list.

nezar@cosmicbytes ~ $ ssh-copy-id [user]@[server_address]

Replace [server_address] with the address to the server, and [user] with the remote user name on that server that you wish to authenticate SSH sessions with (remove the square brackets [] ).

If the server address is 192.168.1.50 and the user is "maple", then the command would be:

nezar@cosmicbytes ~ $ ssh-copy-id [email protected]

Manually

If you are unable to connect to the server via SSH, you can attempt to transfer it manually. To do this, transfer the public key file ending with .pub using your desired, secure transfer method to the server. The file should be found at the path /home/[your_user]/.ssh/ (where [your_user] is your user name on the client). Make sure not to transfer or touch the private key (the file that does not end with .pub), as exposing it could compromise your security.

After transferring the file to the server using your preferred method, launch a terminal or shell session on the server using the user you want the client to gain SSH authorization on.

Check if the home directory of the user has the .ssh directory. If not, make sure to create it:heart with the proper permissions.

# make sure you're in home directory
maple@server ~ $ cd ~
# check to see if .ssh directory exists
maple@server ~ $ test -d ".ssh" && echo ".ssh dir exists!" || echo ".ssh dir doesn't exist"
# create the directory if it does not exist
maple@server ~ $ mkdir .ssh
# set the right permissions
maple@server ~ $ chmod 700 .ssh

Add the content of the public key to the authorized_keys file under the .ssh directory. Make sure to append so as to avoid unintentionally erasing previous entries in there.

maple@server ~ $ cat path/to/key.pub >> ~/.ssh/authorized_keys
# make sure the right permissions are set on the file
maple@server ~ $ chmod 600 ~/.ssh/authorized_keys

And now we have our SSH public key authentication working! If you face any issues, restart ssh daemon to make sure changes took affect, or restart the machines altogether. Then you can attempt to SSH and observe our new authentication method in action.

Disabling Password Authentication

You can disable password authentication entirely on the server for enhanced security. This way, only SSH keys can be used. To do this, we need to set the PasswordAuthentication option in sshd_config to no.

Open the file /etc/ssh/sshd_config in your preferred text editor and add the following line:

PasswordAuthentication no

You can do this on a per-user basis using the Match User statement:

Match User maple
    Password Authentication no

Make sure you do this at the end of the file, so that other options are not also restricted to the user maple.

Future Considerations and Best Practices

We have successfully added Public Key Authentication to our SSH setup. While this comes with both security and convenience benefits, it is not free of pitfalls and cons.

For example, a common pitfall is improper key management. This can especially get difficult as the usage scales, like in an enterprise setting. When you're managing a large number of keys, it is important to keep track of which ones are in use, removing unused ones.

It is also important to ensure that each key is granted a limited set of privileges based on what is needed. Privileges need to be routinely revised to ensure a key's user is not granted more or less permissions than needed.

Key rotation is an important part of key management, and forgetting it is another common pitfall. Just like passwords, keys should be rotated too! This ensures that unused keys or secretly compromised keys are expired and their threats are eliminated.

Use passphrases wisely. Passphrases have a different security model than typical passwords. They are only used for unlocking a key that is only accessible on one device. They can delay an attacker from obtaining the private key from the private key file, as they are now forced to brute force it. Rotating passphrases is also advised.

It may also be worth considering SSH Certificates instead of Keys. They can offer benefits for enterprise scaling, but they are also with their own pros and cons. We will discuss them in a future article.

Thanks for reading!