Securing OpenSSH

A tutorial on the holistic approach to securing OpenSSH.
Avoid Using Passwords

If possible, stop using passwords for remote logins. You can accomplish this by setting up trust relationships using public key authentication. These trust relationships can be set up between any two user accounts, on the same system or across the network.

The first step to setting up one of these relationships is to create a private and public key, known as a key pair. Each key is stored in a separate file. By convention, the filenames are the same, but the public key file has an extra .pub extension. The private key stays secret and usually remains in the home directory of the account that will initiate the connection.

OpenSSH will refuse to use any private key file with lax file permissions. To form the trust relationship, the public key is appended to the ~/.ssh/authorized_keys file (usual location on most Linux builds of OpenSSH) on the destination side of the trust relationship. The authorized_keys file contains all the public keys trusted by the owner's account. These keys can be secured further by providing a passphrase, which is used to encrypt the private key. If a passphrase is specified, it needs to be provided before the private key can be used to make a connection. In the example below, we create a trust relationship between two accounts, account1 on a system named localbox and account2 on a system named remotebox.

Create account1's key pair (we will specify a passphrase when asked). The passphrase is not actually displayed as you type it, but it is shown below for demonstration. We specify that the pair should be based on a 2048-bit private key (the default is 1024, which recently has been proven to be much easier to crack):


[account1@localbox account1]$ ssh-keygen  -t rsa -b 2048
Generating public/private rsa key pair.
Enter file in which to save the key (/home/account1/.ssh/id_rsa):
<ENTER>
Created directory '/home/account1/.ssh'.
Enter passphrase (empty for no passphrase):
This%%%Is%%%My%%%Passphrase<ENTER>
Enter same passphrase again:
This%%%Is%%%My%%%Passphrase<ENTER>
Your identification has been saved in /home/account1/.ssh/id_rsa.
Your public key has been saved in /home/account1/.ssh/id_rsa.pub.
The key fingerprint is:
63:9f:75:d5:80:93:67:5e:d8:69:5a:69:69:4f:a0:76 account1@localbox

[account1@localbox account1]$ cat /home/account1/.ssh/id_rsa
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,9668032A1B3D23DA

2IKH5Xt+LR2/nftd8aPi1KPZ4Fn20upJKU1NUAK82HXBb59TPyzmr/05i56ZiPhO
UHJCScF+G/k44zheUnyWu+/65iVuzTaa+6q4eYaTna8ElA+PetmfwQF08L780NkU
+2VJeEyizXcro9J6oYYGhS+qWfHalmbX6w6IWuAh6jjEhCn+LTlZs1yjGFu5NHDr
sWSMNgounPS/ay8ZlNIV+iQB5l/v+bNWiC92ICYbZW0C+o2XKpNvACdUDpA/gfqk
b20utNOzBfGAGgmU2EJ5HGq8YQMCjVk0ZN/NVjGqUuACQmW0nB5jYrGE/ka/20xN
X4jZWxXGxNeS0PMdxlB5XXXXXXBMwCWx0AZ0SVYdoSbapZJKMsOdEolFU4IFEewm
NlgFXfe7vsdFseFsaSdfEkCHaHaMadeYouLooktoqz+mfkbwDpC8msnKcuRJShR9
09rZnoKW/ddvrJv5oIQYFqu7LYJr5ygpW3T3oiFgzsIg//1hAW4h0sTCBWUIGSkk
IWTxKFooQ3ABarsIzCHqPBazXnSJ5IVXXXXlglmH9ce5Z6YMNoUdfWBn4Mgc2gNB
xCk4KINXMJ7MJsmLxkwuABqcTq4SBCiipr6PLL5G2BKK6ljXLdJe4olDdb/GtxlH
mOXNuAWLD1eE5FfAOUSQLGDkeUThisIsNotARealPrivateKeycOBrhdykHI5Sh7
/hVyTVr9t6r6lRBEsMi1T+P2uBAuahNGCyDs+5F1P14y2RJ5GAlDVdM8bXOfnfsO
pHiXerStpKw6j85wxoKryzSAGs2eWXtrQKk8IMkDQug=
-----END RSA PRIVATE KEY-----

[account1@localbox account1]$ cat /home/account1/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAIEA54Q3QZLkpRaNN83WUMBGBE+/xZ88ud
+SlM74awZa8P6H3TNcEnrb3Lti58bsgjl3z0W5DXWvNRgszoQeBJYNVHlsVIUCp0Vj
Vr7aDUn0PiUVI2y658XBlbup5+isgMNuyB7BskVKs9aWYQNCbJVoNo+3wcvA9x+De5
Z7yBapi6E= account1@localbox

This created the two key files /home/account1/.ssh/id_rsa and /home/account1/.ssh/id_rsa.pub. Now, we copy the public key to account2@remotebox. You can do this with any method you find convenient. We use scp to copy the file, and then use cat to append to it:

[account1@localbox account1]$ scp /home/account1/.ssh/id_rsa.pub
 ↪account2@remotebox:./account1.id_rsa.pub
account2@remotebox's password:
id_rsa.pub            100%  243   538.1KB/s   00:00

Now we append account1's public key to account2's authorized_key file and set proper permissions on files:

[account2@remotebox account2]$ mkdir ~/.ssh
[account2@remotebox account2]$ chmod 700 ~/.ssh
[account2@remotebox account2]$ cat account1.id_rsa.pub >>
↪~/.ssh/authorized_keys
[account2@remotebox account2]$ chmod 600 ~/.ssh/authorized_keys
[account2@remotebox account2]$ rm account1.id_rsa.pub
[account2@remotebox account2]$ ls -l ~/.ssh/
-rw-------  1 account2 account2 243 Dec  9 09:42 authorized_keys

By placing the public key on the destination account2, we prove the identity of account1 when it tries to connect. As you can see below, we are prompted for the passphrase when we make the connection:


[account1@localbox account1]$ ssh account2@remotebox
Enter passphrase for key '/home/account1/.ssh/id_rsa':
This%%%Is%%%My%%%Passphrase<ENTER>
[account2@remotebox account2]$

After the basic trust relationship is set up, you can disable password authentication by locking the password using the passwd command and the -l option.

You can restrict this trust further by adding options to the authorized_keys file. In the example below, we include the from= option to add host-based checking, so the private key will be accepted only from predefined network addresses. We also add the command= option, which specifies the one and only command that will be executed after authentication to the remote account. This feature is most useful from inside scripts to create special-purpose trust relationships to automate tasks between systems or accounts:


[account2@kettle account2]$ cat  .ssh/authorized_keys
from="localbox",command="/bin/df -k" ssh-rsa
AAAAB3NzaC1yc2EAAAABIwAAAIEA54Q3QZLkpRaNN83WUMBGBE+
/xZ88ud+SlM74awZa8P6H3TNcEnrb3Lti58bsgjl3z0W5DXWvNRgszo
QeBJYNVHlsVIUCp0VjVr7aDUn0PiUVI2y658XBlbup5+isgMNuyB7Bs
kVKs9aWYQNCbJVoNo+3wcvA9x+De5Z7yBapi6E= account1@localbox

[account1@localbox account1]$ ssh  account2@remotebox
Enter passphrase for key '/home/account1/.ssh/id_rsa':
This%%%Is%%%My%%%Passphrase<ENTER>
10:32:15  up 8 days, 15:13, 16 users,  load average: 0.15, 0.12, 0.09
Connection to remotebox closed.
[account1@localbox account1]$

After the uptime command is executed, we are immediately dropped back to account1. This relationship is now locked in to performing only one operation. This could be a single command, script or a restricted shell. The command= option can be used to allow certain users to perform selected elevated privilege operations in a controlled manner. Similar functionality can be gained using tools like sudo, but OpenSSH allows these operations over the network, which is useful in some circumstances. If you have problems with any of these examples, you can run ssh with debugging turned on, using the -vvv command-line option. This usually helps in figuring out what is going wrong; most commonly, file permissions cause OpenSSH to ignore key files.

To facilitate the use of public key authentication in scripts, you can create a key pair for each remote operation and then specify which one to use by invoking ssh with the -i option and the filename of the private key.

For interactive sessions, you can use a program called ssh-agent to cache your decrypted private keys in memory, so you need to provide the passphrase only once. On some Linux distributions, ssh-agent is already hooked into the login process to start automatically. If so, all you have to do is use ssh-add to cache your private keys. If you are interested in ssh-agent, take a look at the ssh-agent and ssh-add man pages for detailed explanation of their uses.

One final comment about public key authentication: with the price and ease of use of modern USB Flash drives, you can consider keeping your passphrase-protected private keys on removable media rather than in your home directory. This lets you use them from multiple locations while maintaining only one copy.

______________________

Webinar
One Click, Universal Protection: Implementing Centralized Security Policies on Linux Systems

As Linux continues to play an ever increasing role in corporate data centers and institutions, ensuring the integrity and protection of these systems must be a priority. With 60% of the world's websites and an increasing share of organization's mission-critical workloads running on Linux, failing to stop malware and other advanced threats on Linux can increasingly impact an organization's reputation and bottom line.

Learn More

Sponsored by Bit9

Webinar
Linux Backup and Recovery Webinar

Most companies incorporate backup procedures for critical data, which can be restored quickly if a loss occurs. However, fewer companies are prepared for catastrophic system failures, in which they lose all data, the entire operating system, applications, settings, patches and more, reducing their system(s) to “bare metal.” After all, before data can be restored to a system, there must be a system to restore it to.

In this one hour webinar, learn how to enhance your existing backup strategies for better disaster recovery preparedness using Storix System Backup Administrator (SBAdmin), a highly flexible bare-metal recovery solution for UNIX and Linux systems.

Learn More

Sponsored by Storix