Quite frequently there is a need to transfer files from one server to another without input from the console. The prime example of this would be a backup script using scp or rsync over ssh to transfer files to a holding area ready to be sent to tape. The problem with using scp or rsync commands to transfer files is that the ssh carrier requires a password to be entered before a ssh tunnel is created. If you’re kicking backup scripts off via the crontab then the process will eventually time out and the backup will fail. Fortunately a simple solution exists which is to allow key-based authentication negating the need for a username/password challenge.
First of all, it’s important to understand that keys can be generated for both version one and version two protocols. Version one uses an RSA key and version two uses a DSA key–I’ll cover both types in the examples below.
Step 1: Generate a key.
The first step is to generate a pair of keys (one public and one private) on the local system.
For SSHv1 we need to generate an RSA key pair:
# ssh-keygen
For SSHv2 we will generate a DSA key pair:
# ssh-keygen -t dsa
When prompted for a location, simply accept the default. Leave the pass phrase blank. A pair of keys will be generated in ~/.ssh/ called either id_rsa/id_rsa.pub or id_dsa/id_dsa.pub; the file ending in .pub is the public key and this is the file we need to transfer to the remote system.
Step 2: Move the public key to the remote computer
Enter the ssh directory:
# cd ~/.ssh
Now copy the public key to the remote system:
SSHv1:
# scp ./id_rsa.pub username@remoteip:/tmp
SSHv2:
# scp ./id_dsa.pub username@remoteip:/tmp
Replace ‘username’ with the username you want to log in to the remote system with and replace ‘remoteip’ with the IP address of the remote host. You will be prompted for a password.
We now need to open up an SSH session to the remote host.
Step 3: Importing the keys
Now using a console session on the remote system we need to navigate to the .ssh directory:
# cd ~/.ssh
For authentication using SSHv1, the public key needs to be imported to the file ‘authorized_keys’; for SSHv2, the authorisation file is called ‘authorized_keys2’.
# cat /tmp/id_rsa.pub > ~/.ssh/authorized_keys
# cat /tmp/id_dsa.pub > ~/.ssh/authorized_keys2
That’s it.
Step 4: Testing
Log off of the remote machine and try to reconnect:
# ssh remoteip
The SSH session should automatically connect without asking for a password. As a further test, try to send a file over using scp:
# scp ~/.ssh/id_rsa.pub username@remoteip:/tmp
The file should be transferred without prompting for the remote user’s password.
Step 5: Cleaning up
Once everything is working, reconnect to the remote server and remember to delete the key files that were transferred to the /tmp partition.
# rm /tmp/*.pub
The above is a simple example of utilising key-based authentication in conjunction with SSH. Because the above steps will allow full access to the remote machine with no need for a password, it’s important to connect from a trusted source. How far you want to go to secure this is a matter of preference. On the one hand, if you use the same passwords for accounts on multiple servers then the fact that one has been breached would mean that all others have also been breached, so there isn’t really any additional risk introduced. On the other hand, you may be using key-based authentication to connect systems that use different passwords; in this case, the risk of multiple systems being breached is significantly increased.
There are precautions that can be taken. By adding some flags to the authorized_keys file we can restrict what actions a specific client can execute while connecting using keys. Here’s an example:
no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,command=”/usr/bin/scp –r –t /tmp/test” KEY
This should precede the current key entry (represented by KEY). The above restricts any connection made with the relevant key so that only /usr/bin/scp can be executed. This example also disallows any types of traffic forwarding.
A useful tool called Authprogs allows easier implementation of these restrictions by acting as a middle man and allowing per-host settings to be applied via an easy-to-read configuration file. The program also creates logs and generates custom error messages, which make it quite easy to troubleshoot during the initial setup. I haven’t managed to get this working perfectly; my issue comes from the fact that some backup files are named differently each day (e.g., 01022007dbdump.dmp and 02022007dbdump.dmp the next day). I have tried to use wildcards in the configuration file, but as of yet it hasn’t worked as expected.
I hope this has proven useful, and I would be very interested to hear whether or not others have been able to restrict remotely executed commands where the desired command string is not static. Leave a comment to let me know how you would accomplish this task.