Passwordless SSH in Linux

In some cases you'll want to be able to SSH another server, without being prompted for password. For example, when dealing with PostgreSQL replication you'll need to execute a command on another server as postgres user:

ssh -T postgres@OTHERHOST /etc/postgresql/9.5/main/replscripts/disable_postgresql.sh

In such cases you'll want to avoid password prompt for many reasons, i.e.:

  • The previous line is part of some script so password prompt would break the script;
  • You don't know postgres' UNIX password anyway.

Create SSH Key

Create SSH key on HOST1 by executing:

root@HOST1:~# sudo -i -u postgres
postgres@HOST1:~$ ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/var/lib/postgresql/.ssh/id_rsa):
Created directory '/var/lib/postgresql/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /var/lib/postgresql/.ssh/id_rsa.
Your public key has been saved in /var/lib/postgresql/.ssh/id_rsa.pub.
The key fingerprint is:
e3:09:6d:0a:3e:bf:46:39:15:4c:ca:27:a4:1a:f1:4f postgres@HOST1
The key's randomart image is:
+--[ RSA 2048]----+
|  .   .o.        |
|   o + .o        |
|  . o E ..       |
|   o o +.        |
|  . . ooS        |
|   . .+= o       |
|    o...o        |
|     o.          |
|     .o.         |
+-----------------+

Explanations:

  • The first line starts postgres user impersonation session;
  • The second line is key creation command;
  • Select empty passphrase.

Copy SSH Key

The next step is to copy the newly created key (~/.ssh/id_rsa.pub) to HOST2. If you are able to SSH HOST2, you can transfer the key through SSH by executing:

postgres@HOST1:~$ ssh-copy-id postgres@HOST2

But since you'll need postgres' password at HOST2 for the previous command, chances are that you won't be able to transfer the key this way.

Manually Copy SSH Key

Alternative way to transfer the key is to simply copy key file (~/.ssh/id_rsa.pub) to HOST2 as you would copy any other file, and then on HOST2 execute (from the directory where you've copied the key file):

root@HOST2:~# sudo -i -u postgres
postgres@HOST2:~$ cp ~/.ssh/authorized_keys ~/.ssh/authorized_keys_Backup
postgres@HOST2:~$ cat id_rsa.pub >> ~/.ssh/authorized_keys

Explanation:

  • The second line creates just-in-case backup of authorized_keys file (assuming that the file already exists);
  • The third line appends the key to authorized_keys file.

Note: it may happen that ~/.ssh directory does not exists, in which case you should create one before creating authorized_keys file, and assign permissions appropriately:

postgres@HOST2:~$ mkdir ~/.ssh
postgres@HOST2:~$ chmod 0700 ~/.ssh

Test SSH

Finally you can test SSH by going back to HOST1 and executing something like:

root@HOST1:~# sudo -i -u postgres
postgres@HOST1:~$ postgres@HOST2 ls /tmp

The previous command (although executed at HOST1) will list content of /tmp directory at HOST2, without asking for password.

Host Authenticity

Although it is true that you can SSH without password this way, there's still one problem: at the first ssh execution against particular host you'll get something like:

The authenticity of host 'host2 (192.168.1.2)' can't be established.
ECDSA key fingerprint is dd:32:1b:ba:36:c4:9c:ee:2e:18:9e:aa:fb:45:91:a7.
Are you sure you want to continue connecting (yes/no)?

After confirming this for the first time, you won't be prompted again for this host. But obviously this confirmation prompt can also break the script. For this reason we'll create / change ~/.ssh/config:

Host *
    StrictHostKeyChecking no

It is also important to set the appropriate permissions to the newly created file, as described in Directory and File Permissions below. After that there won't be any prompts anymore.

The Same Key on Many Hosts

Although the previous procedure will accomplish the task, it might be too complicated in a scenario where we have multiple servers, and we want some user account (i.e. postgres) to be able to SSH every server form any server. In this case we would have to create the key on each server, then add this key to autorized_keys file on all other servers. Obviously it would cause countless repetitions of the previous steps, and number of repetitions exponentially grows with number of servers. (This is the problem you may encounter when establishing PostgreSQL HA cluster.)

The complexity can be significantly reduced if you don't create a new key for each host, but use existing one instead. Here's step-by-step guide:

Create SSH Key at the First Host

At the first host (HOST1) you'll create SSH key as described in Create SSH Key section, and create ~/.ssh/config file as described in Host Authenticity section above.

Create autorized_keys File

On the same host (HOST1) you'll create authorized_keys file by executing:

postgres@HOST2:~$ cat id_rsa.pub >> ~/.ssh/authorized_keys

At the moment this line authorizes user to SSH HOST1 from HOST1 (itself), but after copying these files to other servers (the next section) we'll accomplish what we want.

Copy All Files to All Other Hosts

There are four files you'll want to copy (all from ~/.ssh directory):

  • authorized_keys
  • id_rsa
  • id_rsa.pub
  • config

Since the same key will be used from all other servers, this time besides copying public key file (id_rsa.pub), we'll also copy private key file (id_rsa). All the files should be stored ~/.ssh directory, of course.

After ensuring directory and file permissions as described below, you'll be able to SSH from every host to any other host.

Directory and File Permissions

If you've copied files manually you should adjust ownership and permissions appropriately. Ownership might already been set appropriately, but it won't hurt to ensure:

chown postgres:postgres -R ~/.ssh

The next thing to do is to ensure appropriate permissions:

chmod 0700 ~/.ssh
chmod 0644 ~/.ssh/id_rsa.pub
chmod 0644 ~/.ssh/authorized_keys
chmod 0600 ~/.ssh/id_rsa
chmod 0600 ~/.ssh/config