Password-less ssh with password protected keys for use in cron
Let's say you want to regularly synchronize a directory from one machine to another. One common solution is to setup SSH keys with no passwords and then schedule rsync to push the files over the network.
The major problem with this is someone could “steal” the private key from the source machine and use it to access the destination machine anytime. The solution I will present involves using ssh-agent via keychain to automate setting up a password protected private key that cron can be used in cron scripts.
First create an SSH keypair with ssh-keygen. Use the defaults and enter a reasonable password when it asks:
$ ssh-keygen
This creates an RSA keypair of the default length with the default name of id_rsa and id_rsa.pub.
If you already have a keypair, you can add or change the password with ssh-keygen like so:
$ ssh-keygen -f ~/.ssh/id_rsa -p
Next append the public key to the ~/.ssh/authorized_keys files for the desired user on the destination host. One not so well known but very convenient way to do this is with ssh-copy-id:
$ ssh-copy-id user@machine
This will copy our id_rsa.pub file to the specified user on the specified host. See the manual page for ssh-copy-id for more options. ssh-copy-id will append the public key only if it does not already exist in the authorized_keys file. It will also create the necessary directories and
I recommend using the least privilege principle here and not allowing anything to ssh into a host as root. In other words the destination user should never be root. You should try ssh with this key and make sure it works as expected.
Next setup keychain. Keychain is the glue between ssh-agent which stores ssh keys and UNIX execution environment. Keychain is included in most distros package repositories. On modern Debian style machines you can add it with apt-get:
$ apt-get install keychain
Keychain hooks into your shell environment via the .rc file. Most linux users use bash so add this to either .bashrc or .profile:
eval `/usr/bin/keychain --quiet --eval`
This executes the keychain program that searches for an ssh-agent and starts one if one is not already running. Keychian emits some shellcode which defines two shell variables SSH_AUTH_SOCK and SSH_AGENT_PID. The eval runs this code in your current environment and makes these variables available to commands executed later.
You should fire up another terminal window and log in to the source box a second time. Don’t close the first window until you have logged in and proven you don’t have any errors preventing you from logging in.
Once you login a second time, add the key to your keychain:
$ ssh-add
You will be asked for the keys password and it will be saved by the ssh-agent which keychain made for you. You can view which ssh keys an agent has with `ssh-add –l` and you can delete a key from an agent with `ssh-add –d `. See the man page for more options including how to add more than a single key.
The value add of keychain is that it finds the same ssh-agent for you the next time you login. Try sshing to the destination machine and you should not get asked for a password. Logout and login again the ssh a second time and again you will not be asked for a password because ssh reuses the same ssh-agent which already as the opened private key in memory.
Since the ssh key is password protected it is useless to a rouge user unless they can also get the password to unlock it. Of course they can use the current environment to launch attacks but restricting the commands allowed in the destination authorized_keys file can mitigate this as well.
Finally we will hook this into cron. Keychain creates a couple shell scripts that aid in setting up the proper environment when .rc files are not used. Follow this example for cron:
# Prepend this to your cron jobs
. ~/.keychain/myhostname-sh && rsync ...
Where myhostname is the actual name returned by the hostname command.
If you are in a shell script try this:
HOSTNAME=`hostname`
KEYCHAIN=${HOME}/.keychain/${HOSTNAME}-sh
if [ -f $KEYCHAIN ]
then
. ${HOME}/.keychain/${HOSTNAME}-sh
fi
Congratulations, you now have an environment that can automatically sync files without human intervention using a secure key system that is password protected yet still automated.
Next steps would be restricting the keys use on the destination host by adding restrictions to the authorized_keys file.