SSH Key Authentication Basics

SSH Key Authentication Basics

SSH (Secure Shell) allows remotely accessing the command line interface (cli) of a remote machine. This is very useful for administration of a machine that may be in a completely different country or building.

Because of this SSH is a very attractive target for attackers.

Defaults

The default is to login with a username and password.

┌───────┐                         ┌───────┐
│       │                         │       │
│       │───────Username─────────▶│       │
│       │                         │       │
│  SSH  │◀────Request Password────│  SSH  │
│Client │                         │Server │
│       │───────Password─────────▶│       │
│       │                         │       │
│       │◀────────Success!────────│       │
│       │                         │       │
└───────┘                         └───────┘

The problem with this model is that passwords can be bruteforced (weak passwords), they can be reused and then leaked in password breaches (credential stuffing). Generally SSH with only passwords is not a great idea.

Asymmetric Key Cryptography

The basis of SSH keys lies in asymmetric key cryptography. This is where you have a private key and a public key.

Given a piece of data, the private key can create a signature. The signature can be verified by the public key and the original data. However the public key can not create it's own signature.

┌─────────┐                                        ┌──────────┐
│         │                                        │          │
│         │               ┌─────────┐              │          │
│ Private │     Signs     │         │              │  Public  │
│   Key   │───────┬─────▶ │Signature│              │   Key    │
│         │       │       │         │              │          │
│         │       │       └─────────┘              │          │
└─────────┘       │                                └──────────┘
              ┌────────┐                                       
              │        │                                       
              │  Data  │                                       
              │        │                                       
              └────────┘                                       
                                                               
                                                               
┌─────────┐                                        ┌──────────┐
│         │                                        │          │
│         │               ┌─────────┐              │          │
│ Private │               │         │    Verifies  │  Public  │
│   Key   │               │Signature│───────┬─────▶│   Key    │
│         │               │         │       │      │          │
│         │               └─────────┘       │      │          │
└─────────┘                                 │      └──────────┘
                                       ┌────────┐              
                                       │        │              
                                       │  Data  │              
                                       │        │              
                                       └────────┘              
                                                               
                                                               
                                                               
┌─────────┐                                        ┌──────────┐
│         │                                        │          │
│         │               ┌─────────┐              │          │
│ Private │               │         │    Error!    │  Public  │
│   Key   │               │Signature│ X ◀───┬──────│   Key    │
│         │               │         │       │      │          │
│         │               └─────────┘       │      │          │
└─────────┘                                 │      └──────────┘
                                       ┌────────┐              
                                       │        │              
                                       │  Data  │              
                                       │        │              
                                       └────────┘              

These signatures are design to be mathematically infeasible to bruteforce or forge, meaning that they are very strong compared to passwords.

SSH Key Pairs

Using this knowledge we can now see how an SSH key works. The user (client) who wishes to authenticate to a server holds the private key, and the SSH server has the public key to verify the key is legitimate.

In reverse, the server with the public key can't use that to authenticate since it is only able to verify signatures - not create them.

┌───────┐                         ┌───────┐
│       │                         │       │
│       │───────Username─────────▶│       │
│       │                         │       │
│       │◀────────Challenge───────│       │
│       │                         │       │
│       │────┐                    │       │
│       │ Private                 │       │
│       │Key Signs                │       │
│  SSH  │◀───┘                    │  SSH  │
│Client │                         │Server │
│       │──────Signature─────────▶│       │
│       │                         │       │
│       │                   ┌─────│       │
│       │              Public Key │       │
│       │               Verifies  │       │
│       │                   └────▶│       │
│       │◀────────Success!────────│       │
│       │                         │       │
└───────┘                         └───────┘

Practical Setup Guide (Linux, MacOS)

These commands should all be performed as your regular user account, unless otherwise stated.

Creating the SSH Key Pair

On your SSH client (your destkop, laptop etc). Create a new ssh key pair in the default location (/home/$USER/.ssh/id_ecdsa). You will be prompted for a passphrase. This is a passphrase to encrypt the private key when not in use.

ssh-keygen -t ecdsa

⚠️ /home/$USER/.ssh/id_ecdsa is the private key. Never reveal this to anyone!

Add the Public Key to the Server (ssh-copy-id)

From the client you can automatically add the public key to the server. You will need to enter your username and password for this operation.

ssh-copy-id -f -i /home/$USER/.ssh/id_ecdsa.pub username@server-hostname

Add the Public Key to the Server (manual)

On the ssh client, view the public key. You may wish to copy-paste this files content.

cat /home/$USER/.ssh/id_ecdsa.pub

ssh to the server and run the following on the server.

cd ~
mkdir .ssh
touch .ssh/authorized_keys
chmod 600 .ssh/authorized_keys
$EDITOR .ssh/authorized_keys

In the editor, paste your ssh public key (one per line) and then save and quit.

SSH to the server

Now type ssh username@hostname and you will use your key to authenticate!

Hardening the Server

Now that you have ssh key authentication configured you can harden your ssh server to only allow authentication with ssh keys.

As root (sudo -s) add the following content to /etc/ssh/sshd_config.d/hardening.conf

UsePAM yes
PermitRootLogin no
PermitEmptyPasswords no
PasswordAuthentication no
AllowAgentForwarding no

Then restart sshd

systemctl restart sshd

Before logging out of root, ensure you can ssh to the server with key only. Try logging in with:

ssh -o PreferredAuthentications=password username@hostname

to ensure that password authentication is rejected correctly.