Having to type (and remember) numerous SSH passwords for my sites everyday always drove me mad. So-called 'public key authentication' is one way to end this struggle and work more effectively. I've read several HOWTOs covering this feature but had no time (or shall I say – was far too lazy) to try it myself. One day, finally, SSH got the better of me so I decided to dig into it. Here is what I've found.
Introduction
Let's start with the basics – believe me, it might save you a fair share of time hacking and solving problems. However, if you feel confident in different aspects of SSH, you may just skip to next section.
First and foremost, you have to know there are two versions of Secure Shell protocol: SSHv1 and SSHv2. Those are in fact different protocols which are not compatible with each other but some SSH servers and client may support both (while other will only support one version). Today there is no valid reason to use SSHv1 because it has some serious security issues so I'll assume we're talking SSHv2 from now on.
But there is more – you will find two popular implementations of SSH protocol: SSH (commercial, but free for educational and non-commercial use) and OpenSSH (open-source, free-as-in-speech). There are some not-so-subtle differences so it's important to know which versions are installed on both sides, remote and local. To find out, type 'ssh -V' (note the capital 'V') in local and remote shells:
user@local:~# ssh -V
OpenSSH_3.8.1p1 Debian-8.sarge.3, OpenSSL 0.9.7d 17 Mar 2004
user@remote:~$ ssh -V
ssh: SSH Secure Shell 3.0.1 (non-commercial version) on i386-unknown-freebsd4.4
In this example, local
host has OpenSSH installed, whereas remote
is using non-commercial version of SSH.
You can get more information about the history of SSH and differences between two versions at OpenSSH.org and in Secure Shell FAQ.
Generating public/private key pairs
Public key authentication is based on asymmetric cryptography principles – this way a user is authenticated by a pair of keys: public, which is not secret, and private, known only to user. You generate your keys using ssh-keygen
command. It is available both in SSH and OpenSSH although syntax might be slightly different.
But first we shall create directory structure on all local and remote hosts, paying close attention to permissions (for OpenSSH):
user@local:~$ mdkir -p ~/.ssh
user@local:~$ chmod 700 ~/.ssh
user@local:~$ cd ~/.ssh
user@local:~/.ssh$ chmod 600 *
For SSH, you do the same but directory name shall be /.ssh2
instead of /.ssh
.
Note: With recent versions of SSH and OpenSSH you can simply run ssh-keygen
on every machine – it will create the directory and set all permissions.
Select a good secure (alpha-numeric, mixed-case, 8-character or longer) passphrase and we'll procede to generate the keys – just keep in mind that there is no indication (asterisks or whatever) when you're typing the passphrase. First in OpenSSH:
user@local:~$ ssh-keygen -t dsa -b 1024
Generating public/private dsa key pair.
Enter file in which to save the key (/home/user/.ssh/id_dsa):
Created directory '/home/user/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/user/.ssh/id_dsa.
Your public key has been saved in /home/user/.ssh/id_dsa.pub.
The key fingerprint is:
bc:59:e9:7e:40:76:50:8f:28:04:1f:40:34:75:6c:e5 user@local
And now for SSH:
user@local:~$ ssh-keygen -t dsa -b 1024
Generating 1024-bit dsa key pair
6 Oo.oOo.oOoo.
Key generated.
1024-bit dsa, user@local, Sun Feb 27 2005 20:46:37 +0300
Passphrase :
Again :
Private key saved to /home/user/.ssh2/id_dsa_1024_a
Public key saved to /home/user/.ssh2/id_dsa_1024_a.pub
Setting up public key authentication
Either way, both keys are now stored on your hard disk. Private key shall be kept, ahem, private and public key is going to be uploaded to all your remote servers to provide authentication.
Local OpenSSH, remote OpenSSH
If both local and remote machines are running OpenSSH the process is pretty straight-forward. Transfer your public key to remote host via FTP or SFTP and then merge its contents with remote host's ~/.ssh/authorized_keys2
file:
user@local:~/.ssh$ scp id_dsa.pub user@remote:~/.ssh/local.pub
user@local:~/.ssh$ ssh user@remote
user@remote's password:
user@remote:~$ cd .ssh/
user@remote:~/.ssh$ cat local.pub >> authorized_keys2
user@remote:~/.ssh$ rm local.pub
Et voila! You can log out and re-login with a new passphrase instead of your old password:
user@local:~$ ssh user@remote
Enter passphrase for key '/home/user/.ssh/id_dsa':
user@remote:~$
Local SSH, remote SSH
With SSH on both sides it isn't much harder. It's just that instead of pasting your entire public key into ~/.ssh/authorized_keys2
you mention it in ~/.ssh2/authorization
file:
user@local:~/.ssh2$ scp id_dsa_1024_a.pub user@remote:~/.ssh2/local.pub
user@local:~/.ssh2$ ssh user@remote
Password:
user@remote:~$ cd .ssh2/
user@remote:~/.ssh2$ echo "key local.pub" >> authorization
Log out and re-login – you shall now be prompted to enter your passphrase:
user@local:~$ ssh user@remote
Passphrase for key "/home/user/.ssh2/id_dsa1024_a" with comment "1024-bit dsa, created by user@local Sun Feb 27 2005 20:46:37 +0300":
user@remote:~$
Local OpenSSH, remote SSH
Now here comes the tricky part – well, fear not, I've 'been there, done that' and have it all covered for you. So, since SSH and OpenSSH use a different pubkey format, we will have to convert our local key so it could be used by the remote side:
user@local:~$ ssh-keygen -e -f ~/.ssh/id_dsa.pub > ~/.ssh/local_ssh.pub
user@local:~$ scp ~/.ssh/local_ssh.pub user@remote:~/.ssh2/local_ssh.pub
user@local:~$ ssh user@remote
Password:
user@remote:~$ echo "key local_ssh.pub" >> ~/.ssh2/authorization
This should be it – log out, log in and you are all set! Easy, eh?
Local SSH, remote OpenSSH
This setup is not much more different – you just have to do a conversion backwards. But first generate your keys, upload the pubkey to remote server and log in with your old password:
user@local:~$ scp ~/.ssh2/id_dsa_1024_a.pub user@remote:~/.ssh/local_ssh.pub
user@local:~$ ssh user@remote
user's password:
user@remote:~$ ssh-keygen -i -f ~/.ssh/local_ssh.pub > ~/.ssh/local.pub
user@remote:~$ cat ~/.ssh/local.pub >> ~/.ssh/authorized_keys2
user@remote:~$ rm ~/.ssh/local*.pub
Nothing too scary, right? Again, you can log out, re-login and, if everything went right, will be prompted to type in your new passphrase.
What could possibly go wrong?
So you've done everything as described above and still can't login with your shiny new passphrase? Well, it happened to me as well. I've spent about 2 hours trying to get it right, tried everything but still couldn't get it work. Fortunately, the host which denied me to authenticate with pubkey had rather unrestrictive shell setup so I could view SSH server config files in /etc/ssh2/sshd2_config
file. There were these lines:
#AllowedAuthentications hostbased,publickey,password
AllowedAuthentications password
Apparently admins have quietly disabled public key authentication and all I tried was in vain! It made me kinda mad so I decided to write this article. At least I hope it will help you not to make the same mistake, hehe.