Using SSH PKA on Linux

30 November -0001

The Secure SHell (SSH) is an increasingly popular way for linux machines to communicate securely. SSH has become the de facto remote shell access protocol, replacing telnet but also providing alternatives to file transfer protocol (FTP) and in some cases virtual private networking (VPN). SSH can be used to connect security to a remote machine, transfer files, and even tunnel connections to remote locations.

Public key authentication (PKA) is a method whereby your client machine authenticates to a server using a cryptographic key (instead of a username and password combination). PKA has a massive advantage in strength over traditional password authentication because keys are exponentially more difficult to guess than traditional password authentication, making brute force attacks nearly impossible. PKA is also provides a layer of convenience for users. Keys are protected by a password on the client machine, and once unlocked can be used repeatedly to log in to remote resources without constantly having to type usernames and passwords.

Public keys can also present a security problem. The "island hopping" attack utilizes public keys to jump from one compromised host to another host using keys rather than password guessing. For this reason it is important to protect your public keys with a strong password, and also to hash your host lists so that if your keys are compromised it won't be possible for an attacker to correlate the keys to the hosts they belong to.

To generate an initial public key pair you must use the ssh-keygen command. There are many different options available for key generation. Reading the manual page is a worthwhile endeavour. The main points to be aware of are that there are two types of keys, DSA and RSA, which refer to the cryptographic algorithms used to generate them. RSA keys can be used for SSH protocols 1 or 2 (version 1 has some serious security concerns and should not be used) and DSA can only be used for version 2. DSA keys default to 1024 bits in length whereas RSA keys default to 2048 bits, which is exponentially larger in terms of security. Of course, attackers will likely attempt to guess your passphrase to unlock keys rather than brute force their encryption so in many senses the size difference is moot.

To generate your initial keypair use the command:

$ ssh-keygen -t rsa

This will then prompt you to confirm the filename of the resulting key file, a passphrase to use (which should be suitably long and complex - remember, this will be the target for attackers!), and then will generate the keys. By default you should have two new keys in your home directory under the .ssh directory named id_rsa and id_rsa.pub like so:

$ ls -lah .ssh
total 28K
drwx------.  2 justin justin 4.0K Apr 21 13:45 .
drwx------. 60 justin justin 4.0K Apr 21 13:08 ..
-rw-------.  1 justin justin 1.8K Apr 21 13:45 id_rsa
-rw-r--r--.  1 justin justin  419 Apr 21 13:45 id_rsa.pub
-rw-r--r--.  1 justin justin 9.7K Apr 21 13:30 known_hosts

The public key is the one we'll upload to our intended remote host. This host must be configured to allow public key authentication in order for the operation to work, but that is a simple configuration in /etc/ssh/sshd_config. As part of this process you should also take a moment to update your /etc/ssh/ssh_config file, which is the SSH client configuration. Add the line:

HashKnownHosts yes

To the end of the file to ensure your .ssh/known_hosts file is hashed, which changes hostnames in the file from clear text to hash values. This will change entries such as:

192.168.0.3 ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA+zhdf/+fy4kfvx0cDE+gEExTUiuABFxvaQnarzqfQeZUzYShdxZuAHmMQXrZ/uf+yjPgRErJJf9WhwZm6kYkJe2APq4Kb3vxqSyjfiy767SFkrhmyG2kx7QHS6NrxELuzMj7YXI/opELzJgUJmppJaIilbnAK6yli2+X6Wvch5GiwjQ0PxDOjMWY5QiS9vSqlOssGGxX5T2W4eRufN/IyJVQ5Kap0B8LBMkfHb+Aecpwn8brOEiHzKEkd8hAxlcHzH9TAGNuJOy/hGUtqQyUtdPhJ6f77c7iU487eIFykxUpksyGHibmmR0qzxQkY7mSix766tIbRzY6A0gnxT7pSw==

To values that look more like the following:

|1|pgzSWbN2P3Fxe9ESNULkjq9mH8M=|2gxkJQRafsEzpaxwQP1qmPKqKQM= ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA0AFJlXEOmgsPnPsb70GiNGfWK+eoMEntHwzVKxPNLm8RgP0p9Qc1x+qOd7jiIIg183NvYzzNm8yRgx8xGtJySDZTweh+pzRzIFNJuX1KzavBcBcsXrhS4iUm1XPFcAsHio1j4pQPLXRcY+5RndCNP7yekgX5uZayFxiKb3bi8QlXTnBN/0HX2WHN9LDs4oTh58YHnWEEZWVrYgnysVddy36WueuWylO4sMXS3Vu5zvC2DmP74nvqxIGD6g+CpfvVRxQS5ogz0GdTm8c4wsAzdgtMRt1lb3DXq/lAfjHnTNwYJjLtrWm/8XMbOIdLo7yV/rg7Lzy3dKvFaU391mTCYw==

As you can see, the host for the first entry is clearly legible to any attacker with access to the file, whereas the host for the second example is inscrutable.

Once you have you public keys you need to upload them to your target host. This is most easily done using the rsync command over SSH like so:

$ rsync ~/.ssh/id_rsa.pub username@target_host

Once the key is on the target you'll need to append it to the .ssh/authorized_keys file in your user home directory on the remote machine (or .ssh/authorized_keys2 depending on the host configuration). To do this simply log into the remote machine and append the key file using:

[you@remote ~] $ cat id_rsa.pub >> .ssh/authorized_keys

Alternatively you can just cut and paste the file using a text editor, such as vi. The public key should just be a block of text such as:

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD42mN5DbzSbCh5Fz4r2JyUFgvPqbE0jN5FidbZW/YqqE0zJF5n7Gi+eagXAGVcs0fDncrrsihwb6gWeP4jghc7jfRrpVcmrkCqdDxaBlRpIcjwICY3V2yMSnrevYEewyHri7nI+b2VMPFp2xE9crhQlMQj363FIhsQBNgPTk6wrDMcz2ccObOaP4Xfyf4PKjjyqa3WvrENDcUdLvHX6MEh+6wBhL5tT4/dmtePFLLdJb7Sl3gFVapCNw4ztgslF8WaWajkXM9/uDHgdt8ohW+d5qAzCmjV6fqacDHBPJ3iimhupiIUTTinQY1ShSR2EmgolTCqbg5WlvIYgRY4tdKP justin@laptop.jukeane01.sas.upenn.edu

The public key is designed to be shared, but the private key (id_rsa) must be kept secure. That is the key used for authentication. It is protected by the passphrase, but exposing the key opens the possibility of brute force attacks on the passphrase.

Once the public key is uploaded you should be able to SSH into the remote host and be prompted for your key passphrase rather than your remote credentials. This strategy frees you up to choose an insanely complex passphrase for the remote resource and rely on your keys for authentication, protecting your credentials from easy password guessing attacks.