Securing Secure Shell

Secure shell is the de facto standard method of accessing remote and local systems. It also has a great number of other administrative uses too. Surprisingly SSH hasn't been very secure lately because in its default configuration SSH uses passwords. Brute force attacks look for common login names and passwords in an attempt to guess a valid combination and gain access to your computer. If SSH on your system is accessible from the Internet you are almost certainly being attacked every day.

Why not just use secure passwords?

Secure passwords can be very effective in combating brute force attacks but it can be hard to ensure that all passwords are suitably complex and changed on a regular basis. If you have many users using the system, or you have junior system administrators with access, or you have a lot of software that requires user IDs you will likely find that controlling passwords is hard to do.

Even with good passwords they can only be so secure. This article discusses asymmetrical key authentication with key lengths of 2048 bits. For a password to be as effective as 2048 random bits it would have to be almost 800 characters long.

Another reason to avoid using passwords is that key-based authentication is easier to use once set up and it can make for automated command execution and data transfer. This makes things like data synchronization, backup and administrative tasks much easier.

Asymmetric keys... What are they?

An asymmetric key pair are two keys that are cryptographically related. Data encrypted with one key is decryptable only by the other key and vice versa. One key is considered public and does not need to be secured. The other key is considered private and should be protected and kept secret.

This type of encryption can be used for lots of purposes. The same type of keys are used to create web certificates and other network encryption. It's also used in email security. Because of the nature of the keys they can be used to ensure that only the recipient can read a message. To do this the sender encrypts using the public key. Or the keys can be used to authenticate the source of a message. If the public key can decrypt a message it must have been encrypted by the holder of the private key. This last method is what is used to authenticate users.

What will it be like to use keys for authentication?

To use a key for authentication one first creates the key pair. By default both the public and private keys are placed in the .ssh directory inside your home directory. By default the private key is protected by password. Once created you copy the public key to the remote server and place it in the remote user's .ssh/authorized_keys file.

With the keys in place you use ssh to access the remote server, the ssh client asks for the private key password so that it can decrypt the private key file. Once ssh has the key it uses it for authentication with the remote server and you are logged in.

I know what you're thinking. If you had to supply a password how is that different from using a password on the server? The difference is that the password is used to decrypt the private key file on your local system and attackers don't have access to this file so they can't use a brute force technique. In other words the password is not used to authenticate with the server, only to decrypt the key file.

Also the ssh client remembers your password so on subsequent uses you are not prompted for a password.

Sounds great, how do I set it up

First you have to generate a key.
Then you have to place your public key on the remove server.
Then you should configure the remote server to accept key-based authentication.
Then I strongly recommend that you take additional measures to further configure the server for increase security.

Generating Keys

Okay the first step is to create your own keys. This is the easy step, we use the ssh-keygen command.

ssh-keygen -t rsa -C 'john@mycompany.com'

By default this command will create a 2048 bit RSA key pair. You will be asked for the file where to store the key. If this is your first time doing this just press enter to accept the default.

You will also be asked for a pass phrase. Note the work "phrase", use something long and complex.

The results from that command should look like:

Generating public/private rsa key pair.
Enter file in which to save the key (/home/john/.ssh/id_rsa):
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /home/john/.ssh/id_rsa.
Your public key has been saved in /home/john/.ssh/id_rsa.pub.
The key fingerprint is:
43:cc:f7:8f:01:fb:5f:e2:2c:45:b5:e5:a2:8f:89:6c john@mycompany.com
The key's randomart image is:
+--[ RSA 2048]----+
|                 |
|       o        o|
|        + o    o |
|       . .    o. |
|        S . oo . |
|         . . +.  |
|         . .o o .|
|          E + .o |
|         .    +  |
+-----------------+

You now have two files in your .ssh directory, an id_rsa and an id_rsa.pub.

The id_rsa is your private key. Keep this file protected. You can look at the file using the command view ~/.ssh/id_rsa.

The id_rsa.pub file is your public key. This is the key you will be placing on remote servers. View this key using the command view ~/.ssh/id_rsa.pub

Notes on Using SSH

Before we begin you should know the commonly used SSH client options.

By default ssh logs into a remote server using the same user name as the local session. So if you are logged in as john ssh will try to log you in as john on the remote server. To alter this behaviour change the server name that you use to look like an email address.

To login as root on a remote.server.com use one of these command:

ssh root@remote.server.com
ssh -l root remote.server.com

By default ssh uses the ~/.ssh/id_rsa file to find the key to use for authentication. You can have many different keys and instruct ssh to use a different file using the -i keyfile argument.

To use the ~/.ssh/work_key file as your key use this command:

ssh -i ~/.ssh/work_key remote.server.com

By default ssh uses the well-known TCP port 22 to connect to a remote server. You can change this behaviour using the -p portno argument.

To use port 2222 as the remote server port use a command like this:

ssh -p 2222 remote.server.com

You can configure these on a per-host basis by creating a ~/.ssh/config file. If you access hosts frequently that require special options you can configure those options in this file and avoid having to use arguments on the command line.

To do this we create a section for each host. This section has the same effect of using all the above arguments on the command line. Only with this file set up you don't have to supply any arguments.

Host remote.server.com
  User root
  IdentityFile ~/.ssh/work_key
  Port 2222

You can add several Host sections to this file. Each section begins with the Host line.

Placing your key on the remote server

Now that you have your key pair, you can place the public key onto the remote server so that you can use it to authenticate.

Your public key needs to be configured in the remote server to allow for authentication. To do this you have to edit the .ssh/authorized_keys file in the remote user's home directory. So if your local user is 'john' and you want to authenticate as 'root' on the remote server using your key, you need to place the contents of the ~john/.ssh/id_rsa.pub file from your local system into the ~root/.ssh/authorized_keys file on the remote system.

We can do this in many ways, but each way results in the contents of your id_rsa.pub file being placed in the remote user's authorized_keys file.

If the .ssh file doesn't exist you can either ssh to another server (even localhost) and the directory will be automatically created. You can also create it manually:

mkdir ~/.ssh
chmod 0700 ~/.ssh

Cut-and-Paste Method

Login to the remote server using SSH and edit the remote ~/.ssh/authorized_keys file and cut-and-paste the public key text into the file.

File Transfer Method

Copy the file to the remote server in anyway you can and add it to the end of the authorized_keys file:

cat /tmp/id_rsa.pub >> ~/.ssh/authorized_keys

Configuring the remote server

By default the remote server is likely already configured to use keys for authentication so if you don't have root access on the server, don't worry it will probably work.

If you are the administrator of the remote server you can verify that it is configured for public keys using this command:

/usr/sbin/sshd -T | grep pubkey

If the following text is displayed, then public key authentication is enabled.

pubkeyauthentication yes

Advanced Configuration

Just because you are using keys for authentication doesn't mean that you are now immune to brute force attacks. This section talks about many ways to make your server more secure. I recommend that you enforce at least the first two measures.

Disallow Password Authentication

The best way to prevent the success of a brute force attack is to stop using passwords. This section tells you how to configure the server to disallow the use of passwords entirely.

NOTE: Make sure that key based authentication is working before continuing. If you don't then you will not be able to remotely login to this server after making these changes.

Edit the /etc/ssh/sshd_config file and search for the text PasswordAuthentication (note the upper and lower case). You may find that it is commented out with a # sign. If it is remove the comment sign. Change the setting from yes to no so the line looks like this:

PasswordAuthentication no

Save the file and check to make sure the configuration works using this command:

/usr/sbin/sshd -T | grep passwordauthentication

You should see the effective configuration displayed on the screen. It should look like this:

passwordauthentication yes

Then tell the server to re-read it's configuration using this command:

pkill -1 sshd

Restricting Who Can Login

Another good method of securing a server is to restrict who can login. There are many ways to do this but I find that using a group is easiest way to do this.

First create a group called "ssh-users":

groupadd ssh-users

Then add your user to the group:

usermod -G ssh-users john

Repeat that for every user who should be allowed to login to ssh.

Now we need to modify the /etc/ssh/sshd_config file to tell sshd to allow logins only by that group. Using an editor open that file and search for the text AllowGroups. If the line begins with a # then remove the #. If you can't find it then add it to the end of the file. The line should look like this:

AllowGroups ssh-users

Make sure your change is valid using the command /usr/sbin/sshd -T | grep allowgroups. And reload the server config using pkill -1 sshd.

Changing the Port

Another common technique for protecting a server is to change the TCP port number from the default 22 to something else. This is a good way to prevent the numerous log messages from brute force attempts.

Edit the /etc/ssh/sshd_config file and locate the text Port. If the line begins with a # delete the character. The resulting line should look like this:

Port 2222

The above line sets the port to 2222. I recommend that you choose a different port.

Test the configuration change with /usr/sbin/sshd -T | grep port and, if it's correct, reload the server using pkill -1 sshd.

To instruct ssh to use the new port use the -p 2222 option, for example:

ssh -p 2222 root@remote.server.com

Other ways to secure SSH

There are many ways to further configure ssh to be more secure. I won't cover those in this document, but I will mention them in case you are looking to secure your server more.

Firewalling
If the server only needs to provide ssh access to a short list of hosts you can use firewall rules to prevent access by any other hosts.
Restriction by Host
The /etc/ssh/sshd_config file allows specifying a hostname in the AllowUsers configuration. You can restrict which users can login from which hosts.
Port Knocking
Port knocking is a technique that allows one to send a specific sequence of packets to a firewall to instruct it to open certain ports. Using port knocking you would close access to ssh in the firewall and configure the firewall to open the port to any host that successfully completes the knock sequence.
Intrusion Detection/Prevention
There are tools that allow firewalls and systems to scan for attacks and when they occur the firewall is adjusted to prevent access from the offending host. Often this involves watching for repeated unsuccessful access from a host. If it tries too many times and fails the host is blocked.

Further Reading

man ssh
Command line options for the ssh client
man ssh_config
Additional information on options for your .ssh/config file
man sshd_config
Additional information on options for configuring sshd
man sshd
Command line options for sshd
man ssh-keygen
Command line options for ssh-keygen