26 Jul, 2008
Ordinarily when I'm working with remote servers I just issue a command like this:
ssh james@example.com uptime 14:49:47 up 21 days, 2:52, 0 users, load average: 0.00, 0.14, 0.41
This runs the remote command uptime on the remote server as user james. You can also get a command prompt with:
ssh james@example.com
For both of these examples you have to remember and type the password for james each time. If you administer a lot of servers this can quickly become tedious. One solution is to use SSH keys.
Let's say I have a laptop with a user james and at laptop.com and a server with a ian account at server.com. I want to be able to login to server.com as ian whilst logged into my laptop as james. To do this I need a SSH key pair. The private key stays on my laptop, the public key has to be added to a special authorized_keys2 file in the .ssh directory in ian's home directory on the server.
Create the key pair on the laptop without entering a password. Just press enter twice at that point:
james@laptop:~$ ssh-keygen -t dsa Generating public/private dsa key pair. Enter file in which to save the key (/home/james/.ssh/id_dsa): Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/james/.ssh/id_dsa. Your public key has been saved in /home/james/.ssh/id_dsa.pub. The key fingerprint is: cd:9a:39:7a:ec:7a:77:8e:a3:09:85:aa:b3:e7:b7:93 james@laptop
This creates two files: /home/james/.ssh/id_dsa and /home/james/.ssh/id_dsa.pub. The id_dsa.pub file is the public key which you should place on any server you want to be able to sign in to without a password. The id_dsa file is your private key which stays on the laptop. You should never distribute or publish the private key because anyone with access to it will be able to login to any servers which have the public key set up. Having said that I'm going to show you what both keys look like because I'm not actually using these specific keys myself:
james@laptop:~$ cat /home/james/.ssh/id_dsa -----BEGIN DSA PRIVATE KEY----- MIIBugIBAAKBgQC9psPVFyJeJey3AjtjTa6Ep/E1NA/BhPwmQakI0vafkjO9w/HK Z0VuHd8svp0fn/KcRCcgQhd0mFFRxU8JLf57GoVcPvRmHanFs0t6AqZmb6wpy3Zv fmYFtnZThCgrUSbNFf6DvvRh3Cp+7OsUKP+MHJE0NI0XvG3m/VQbeeuSbwIVAJeC 6m1aXZ4EL/xaM25yk3C8qpPZAoGACCPPnaevWG7gWI7fG/aEGW6uwAAjKIWrO4Fc vTzt1fXZcXXDsiHSSQ7sbbpyeStNMjW2tTLS7SXcGld8JbGiTt2aLh6X8n9aMa2f lHRZjYGLylIFSHuj+L7y4qAYXt740l/ADYwjegeTzcD5QtR2GvgEmlCIkywAdZ9o DcCc0i0CgYAlDA66+66CEKi/mn6R1cc3UeZ0fADGZeqWgZjamzRlXCmPleA1UFZB lR40YUDUFfZ4a+p1JJpW9epNXmcVnbZsbfw+aVhR4EAgw4DN89hvilgD9Qjr8UN2 Ocxz5D5dIQrV+oK79CEobLs/uL2A/lofTZndzhSSYUdxy8wHBaNtawIUcnmU5Uzm JCiJBTwWgUqBTRLzzs0= -----END DSA PRIVATE KEY----- james@laptop:~$ cat /home/james/.ssh/id_dsa.pub ssh-dss AAAAB3NzaC1kc3MAAACBAL2mw9UXIl4l7LcCO2NNroSn8TU0D8GE/CZBqQjS9p+SM73D8cpnRW4d3yy+nR+f8pxEJyBCF3SYUVHFTwkt/nsahVw+9GYdqcWzS3oCpmZvrCnLdm9+ZgW2dlOEKCtRJs0V/oO+9GHcKn7s6xQo/4wckTQ0jRe8beb9VBt565JvAAAAFQCXguptWl2eBC/8WjNucpNwvKqT2QAAAIAII8+dp69YbuBYjt8b9oQZbq7AACMohas7gVy9PO3V9dlxdcOyIdJJDuxtunJ5K00yNba1MtLtJdwaV3wlsaJO3ZouHpfyf1oxrZ+UdFmNgYvKUgVIe6P4vvLioBhe3vjSX8ANjCN6B5PNwPlC1HYa+ASaUIiTLAB1n2gNwJzSLQAAAIAlDA66+66CEKi/mn6R1cc3UeZ0fADGZeqWgZjamzRlXCmPleA1UFZBlR40YUDUFfZ4a+p1JJpW9epNXmcVnbZsbfw+aVhR4EAgw4DN89hvilgD9Qjr8UN2Ocxz5D5dIQrV+oK79CEobLs/uL2A/lofTZndzhSSYUdxy8wHBaNtaw== james@laptop james@laptop:~$
Notice that the public key is actually just one long line in three parts, a type, the public key itself and a comment. In this case the comment is james@laptop but you can change this to anything you like which helps you remember which private key the public key is associated with.
Let's set up the public key on the ian account on server.com:
james@laptop:~$ scp /home/james/.ssh/id_dsa.pub ian@server.com:james_laptop_public_key.pub Enter password:
You'll have to enter the password because the key isn't yet set up. Next we need to add this public key to ian's .ssh/authorized_keys2 file. This file can have multiple entries because it is possible that ian wants to allow access to many different user accounts on different machines. This is why we didn't copy the id_dsa.pub directly to /home/ian/.ssh/authorized_keys2 which we could have done if we were sure the file didn't exist or was empty.
SSH into the ian@server.com account and enter your password:
james@laptop:~$ ssh ian@server.com
If the ian account has never used SSH before you should run this command and make a connection with your regular password to create the .ssh directory on the remote server:
ian@server:~$ ssh laptop.com
This will create a .ssh dir in ian's home directory with the proper permissions. Now we need to append the james_laptop_public_key.pub file to the authorized_keys2:
ian@server:~$ cat james_laptop_public_key.pub >> ~/.ssh/authorized_keys2 ian@server:~$ exit logout Connection to server.com closed. james@laptop:~$
At this point the public key is set up on the remote server and the private key is set up on the laptop. You can now ssh or scp from the james account on the laptop to the ian account on the server without typing a password:
james@laptop:~$ ssh ian@server.com ian@server:~$
Caution!
It is very bad practice to actually have passwordless keys set up in this way because anyone who hacks your laptop will also have access to your server without needing the password. Read on to learn about ssh-agent.
It is very important that no-one other than you can read your private key id_dsa file because anyone with that file will also be able to access your server. For that reason you should always make sure the file has permissions of 600:
james@laptop:~$ chmod 600 /home/james/.ssh/id_dsa
You can repeat the process described above to add your public key to the authorized_keys2 files on lots of different user accounts on lots of different servers. You only need the one private key though. This will allow you to log in to all those different accounts using the same private key and without needing a password.
Be aware though, if using a passwordless key for access to one server is a bad idea for security, using the same key on multiple servers is even worse because a hacker then has access to even more servers.
Although the SSH private key we've been using so far is designed to allow you to sign in to lots of different servers you can also create a different private key for each one if you prefer. To create a new private key you'll need to specify a filename, otherwise you will overwrite the id_dsa and id_dsa.pub files you've just created:
james@laptop:~$ ssh-keygen -t dsa -f identity
You'll need to add the contents of identity.pub to the end of the authorized_keys2 file on the remote server as you did before. Now you need to specify the key to use when you use an ssh command:
james@laptop:~$ ssh -i identity ian@server.com
It is much safer to use a key with a password. To generate a key with a password run this command but this time enter a password when prompted:
james@laptop:~$ ssh-keygen -t dsa
This will over-write the existing passwordless private key and public key. You'll need to add the new public key line to the authorized_keys2 files of all the accounts on all the servers you wish to have access to. (You should probably remove the old lines too).
Now when you try to ssh in to the server you will be prompted for a password. This is the password of the key, not of the account on the server:
james@laptop:~$ ssh ian@sever.com Enter passphrase for key '/home/james/.ssh/id_dsa':
If you are using a desktop environment such as GNOME (or are using Mac OS X for example) you might get a popup which asks you to enter the password instead of entering the key password on the command line as shown in the example above. Once you have entered it, GNOME will remember the password for the current session so you don't have to enter it again.
You can achieve a similar result if you are just working on the command line by using a program called ssh-agent:
james@laptop:~$ ssh-agent bash
This will put you in a bash shell which is spawned by ssh-agent. Next you'll need to add your key:
james@laptop:~$ ssh-add
This will try and add the default key id_dsa to the key manager. To add a key with a different name, enter:
james@laptop:~$ ssh-add /location/of/key
After this, the ssh-add program will ask you for your password. After you entered your password the key is loaded in the key manager ssh-agent.
You can now login to the remote servers without entering your password again. As you can see this set up is much safer than just using a passwordless key to start with and it isn't significantly more hassle.
You can have a look at your currently loaded keys with:
james@laptop:~$ ssh-add -l 1024 45:1b:f8:87:15:31:2f:4a:38:c5:f3:b0:e5:de:62:8f (DSA)
Now having keys with passwords and working with ssh-agent is fine for every day use but useless for automated tasks such as cron jobs because the cron script would need to have the password listed in plain text.
Luckily there is a way around this. One feature of sshd is that you can specify options in the authorized_keys2 file.
Create a new private key without a password this time:
james@laptop:~$ ssh-keygen -t dsa -f .ssh/single_use_identity
Edit the public key .ssh/single_use_identity.pub so that the comment says something like james@laptop_single_use_identity otherwise once it is copied to the server it might be difficult to identify.
Copy the public key to the remote server and add it to the end of the auhorized_keys2 file as before.
Once the sign in works correctly find the public key line representing the private key you are using in the remote server's authorized_keys2 file again and add the following right at the front of the line with a single space between it and the ssh-dss line that is currently at the front:
command="uptime",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty
The above text needs to be all on one line with no carriage returns in it. When the user signs in they will only be able to run the command listed in the command option. Let's try it:
james@laptop:~$ ssh ian@server.com -i single_use_identity 16:30:39 up 21 days, 4:33, 0 users, load average: 0.04, 0.01, 0.00 Connection to server.com closed.
As you can see, this time the uptime command was run and then the connection was closed. The key can now only be used to execute the uptime command.
If you ignored the advice to create a new private key for the single use identity and instead just modified the old one you might now find you can't sign in to the server because it keeps printing the uptime and closing the connection. To sign into the server now you will need to disable ssh-agent. You can do this with this command:
james@laptop:~$ ssh-add -d Identity removed: /home/james/.ssh/id_dsa (/home/james/.ssh/id_dsa.pub)
You can now sign in as usual:
james@laptop:~$ ssh ian@server.com Agent admitted failure to sign using the key. ian@server.com's password:
If you are using GNOME or Leopard you might need to move your private and public keys temporarly and logout of your desktop session and log back in again to force the agent to forget your identity:
james@laptop:~$ mv .ssh/id_dsa .ssh/id_dsa.bak james@laptop:~$ mv .ssh/id_dsa.pub .ssh/id_dsa.pub.bak james@laptop:~$ ssh ian@server.com ian@serve.com's password:
Then you can change the remote authorized_keys2 file back, logout, and move the public and private key back:
ian@server:~# exit logout Connection to server.com closed. james@laptop:~$ mv .ssh/id_dsa.bak .ssh/id_dsa james@laptop:~$ mv .ssh/id_dsa.pub.bak .ssh/id_dsa.pub
If you want to use a single purpose key to handle backups with rsync you should add a cron job on your laptop to run the rsync command:
james@laptop:~$ crontab -e
Add this line:
0 10 * * * rsync -aHxvz --delete --progress --numeric-ids -e "ssh -c arcfour -o Compression=no -x -i /home/james/.ssh/single_use_identity" ian@server.com:/home/ian /home/james/ian_backup/
This will then invoke rsync on the laptop to back up information from the server at 10am every day using the SSH private key for james on the laptop.
At the moment though the private key is associated with a public key on the server which is only capable of running the uptime command. In order for rsync to work the server needs to be allowed to run the rsync --server command to start the rsync. We need to change the line in the authorized_keys2 file on the server to look like this:
command="/home/ian/secure-rsync",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty
(Note you might need to log out of your session and back in to get your agent to forget your identity so you can sign in with a password again as mentioned earlier)
Next create the /home/ian/secure-rsync script on the remote server and make it look like this:
#!/bin/sh case "$SSH_ORIGINAL_COMMAND" in *\&* | *\;* | *\|*) echo "Access denied" ;; rsync\ --server*) $SSH_ORIGINAL_COMMAND ;; *) echo "Access denied" ;; esac
Note: This script doesn't display correctly in Wordpress. Copy it from here instead: http://www.barryodonovan.com/misc/publications/lg/104/
This script ensures that only the rsync server is allowed to be run. Make it executable:
ian@server:~$ chmod a+x secure-rsync
Now test the rsync command from the laptop:
james@laptop:~$ rsync -aHxvz --delete --progress --numeric-ids -e "ssh -c arcfour -o Compression=no -x -i /home/james/.ssh/single_use_identity" ian@server.com:/home/ian /home/james/ian_backup/
If rsync isn't installed you can install it with:
sudo apt-get install rsync
It will need to be installed on both the laptop and the server.
If it works without a password you can leave your cron job to run and it will provide daily backups (providing your laptop is on and connected to the internet at the time of the backup!)
One thing to note is that if you have multiple keys installed on the server and laptop it is possible that rsync is happening over the default connection rather than the passwordless single use one. You can check it isn't by temporarily moving the id_dsa and id_dsa.pub files as mentioned earlier whilst testing the rsync command.
That's it, hopefully everything you need to know to be productive with SSH keys. I'm by no means on expert on all this so feel free to point out any mistakes I've made in the comments.
Any time things don't work just add the -v switch which means "verbose". SSH will display exaclty what is going on which makes debugging much easier. A common problem is that one of the computers is using SSH 1 rather than SSH 2. This guide was for SSH 2 so if you are trying to use it with an SSH 1 computer I'm afraid it won't work.
Copyright James Gardner 1996-2020 All Rights Reserved. Admin.