1. Overview

ssh-copy-id is a useful tool for SSH connections to a remote host without using a password. Basically, it copies the SSH key into the remote host’s authorized_keys file, which is by default in the $HOME/.ssh directory.

In this tutorial, we’ll discuss how to automate the usage of ssh-copy-id.

2. Analyzing the Problem

We have two machines: host1 and host2. Let’s try to connect from host1 to host2 using ssh:

[alice@host1]$ whoami
alice
[alice@host1]$ ssh host2
alice@host2's password:
[alice@host2]$

Our username is alice, as the whoami command shows. Once we enter the correct password, we can connect to host2.

But we don’t want to enter the password each time we connect from host1 to host2 using ssh. We can use the ssh-copy-id command for this purpose:

[alice@host1]$ ssh-copy-id alice@host2
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "home/alice/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed – if you are prompted now it is to install the new keys
alice@host2's password:

After printing a bunch of information, ssh-copy-id asks for the password of alice on host2. Let’s enter the password:

alice@host2's password:

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'alice@host2'"
and check to make sure that only the key(s) you wanted were added.

After we enter the password of alice on host2, ssh-copy-id informs us that the key was added.

Now, let’s test whether connecting from host1 to host2 asks for the password:

[alice@host1]$ ssh host2
[alice@host2]$

This time, ssh doesn’t ask for the password. Therefore, we’re able to successfully log in to host2 from host1 without using passwords.

Then, what’s the problem? We may have many remote hosts with the same username and password combination. If we’re the system administrator and want to configure the system for SSH connections without using passwords, then it’s tedious to enter the password manually for each host while using ssh-copy-id. It would be nice to automate the process to use in shell scripts.

We’ll find a solution to this problem next.

3. The sshpass Command

We’ll use the sshpass command to manage the password authentication of ssh in scripts. sshpass runs ssh in a mode known as the keyboard-interactive password authentication mode, but in non-interactive mode.

3.1. The -p Option

We can use the -p option of sshpass for providing the password on the command line.

We’ll repeat the process of giving access from host1 to host2 using ssh without asking password. However, we had already given this permission using ssh-copy-id in the previous example. Therefore, we must first revert the permission for connecting from host1 to host2 without providing a password:

[alice@host1]$ ssh host2
[alice@host2]$ rm /home/alice/.ssh/authorized_keys
[alice@host2]$ exit
logout
Connection to host2 closed.
[alice@host1}$ ssh host2
alice@host2's password:

First, we connect from host1 to host2 using ssh. As we can see from the output above, ssh doesn’t ask for the password because of the usage of ssh-copy-id in the previous example.

Then, we delete the file /home/alice/.ssh/authorized_keys on host2. In the earlier example, ssh-copy-id had copied our public key into this file.

Finally, after logging out of host2 using exit, we try to reconnect from host1 to host2. This time, ssh asks for the password.

Now, instead of directly using ssh-copy-id, let’s use it together with sshpass:

[alice@host1]$ sshpass –p my_secret_password ssh-copy-id alice@host2
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "home/alice/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed – if you are prompted now it is to install the new keys
alice@host2's password:

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'alice@host2'"
and check to make sure that only the key(s) you wanted were added.

This time, we pass the ssh-copy-id alice@host2 command as the command that will be run by sshpass. We also provide the password from the command line using -p my_secret_password. Here, my_secret_password is the password of alice on host2. ssh-copy-id doesn’t ask for the password during the configuration, therefore, it’s possible to use ssh-copy-id in a script for the configuration of ssh for many hosts.

Now, let’s check whether we can connect to host2 from host1 using ssh:

[alice@host1]$ ssh host2
[alice@host2]$

We’re able to connect to host2ssh doesn’t ask for the password this time.

So, we can achieve our goal using the -p option. However, since we have to provide the password on the command line, this isn’t a secure choice.

3.2. The -f Option

Instead of providing the password on the command line, we can store the password in a file. We must pass the name of the file to sshpass using its -f option. The password must be the first line in the file.

Let’s try the -f option. First, we must delete the file /home/alice/.ssh/authorized_keys on host2 to revert the permission we gave in the previous example. After having deleted the file, let’s use sshpass with its -f option:

[alice@host1]$ sshpass –f passwd_file ssh-copy-id alice@host2
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "home/alice/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed – if you are prompted now it is to install the new keys
alice@host2's password:

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'alice@host2'"
and check to make sure that only the key(s) you wanted were added.

The -f passwd_file part of sshpass specifies that sshpass must get the password from the file passwd_file. Let’s check the content of passwd_file:

[alice@host1]$ cat passwd_file
my_secret_password

The file contains the password of alice. Now, let’s check whether connecting from host1 to host2 asks for a password while using ssh:

[alice@host1]$ ssh host2
[alice@host2]$

ssh doesn’t ask for the password, and we can connect to host2.

If the file consists of multiple lines, sshpass only uses the first line as the password.

This method is more secure than using the -p option. We may set the permissions of the file that stores the password so that others can’t get its content. Additionally, it’s a good idea to encrypt the file.

3.3. The -e Option

Another way of getting the password is the environment variable SSHPASS. We must use the -e option of sshpass for using the password stored in the SSHPASS environment variable.

After having reverted the permission we gave in the previous example, let’s use sshpass with its -e option:

[alice@host1]$ SSHPASS=my_secret_password sshpass –e ssh-copy-id alice@host2
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "home/alice/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed – if you are prompted now it is to install the new keys
alice@host2's password:

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'alice@host2'"
and check to make sure that only the key(s) you wanted were added.

First, we set the value of the environment variable SSHPASS to the password of alice on host2 using SSHPASS=my_secret_password. Then, we use sshpass with its -e option.

Now, let’s try to connect to host2 from host1:

[alice@host1]$ ssh host2
[alice@host2]$

Again, ssh doesn’t ask for the password — as we expected.

It might be a good idea to clear the command line history in this case for the sake of security.

3.4. The -d Option

sshpass can also read the password from an open file descriptor. We must use its -d option for this purpose.

After having reverted the permission in the previous example, let’s try the -d option:

[alice@host1]$ exec 6<passwd_file 
[alice@host1]$ sshpass –d 6 ssh-copy-id alice@host2
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "home/alice/.ssh/id_rsa.pub"
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed – if you are prompted now it is to install the new keys
alice@host2's password:

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'alice@host2'"
and check to make sure that only the key(s) you wanted were added.

[alice@host1]$ exec 6<&-

First, we open the file passwd_file for reading and assign the file descriptor 6 to it using exec 6<passwd_file. Then, we pass this file descriptor to sshpass with its -d option. The key is copied to the remote host. Finally, we close the input file descriptor using exec 6<&-.

Now, let’s connect from host1 to host2:

[alice@host1]$ ssh host2
[alice@host2]$

Again, we’re able to connect to host2 without any password, as expected.

4. Conclusion

In this article, we discussed the usage of sshpass for automating ssh-copy-id.

First, we discussed the -p option, which is useful for providing the password on the command line.

Next, we looked at the -f option, which lets us get the password from a file.

Then, we used the -e option to have sshpass get the password from the SSHPASS environment variable.

Finally, we saw that we can use the -d option to read the password from an open file descriptor.