Tuesday, June 8, 2010

More secure Secure Shell

Hakone-Zaiku, a japanese wooden "safe" (this one is closed)

When we connect to a remote machine using Secure Shell (SSH), we routinely must type the password that we use on this remote machine. But SSH allows for public key authentication, where the remote machine has a public key, and it grants access to whoever has the corresponding private key (broadly speaking; if you want a proper explanation please refer to e.g. this book's section or the "Authentication" section of the ssh(1) man page). A possible analogy is a lock-and-key pair, where the lock may be accessible to everybody as long as you keep the key with yourself. It is also similar to PGP cryptography.

But with SSH it is also possible to encrypt the private key with a passphrase, such that the file with the private key is not enough for authentication. In the lock-and-key analogy, this would be equivalent to these modern cars where the owner's fingerprint is necessary to unlock the doors, besides the key.  So far I have always used empty passphrases (that is, the private key was unencrypted), but now that we're migrating to a more secure server I'm better trying a distinct passphrase for each remote machine I connect regularly.

To create the public/private key pair is relatively simple, this is how I did it:
23:30[myPC:~] ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/home/leo/.ssh/id_rsa): /home/leo/.ssh/id_rsa-theirPC
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/leo/.ssh/id_rsa-theirPC.
Your public key has been saved in /home/leo/.ssh/id_rsa-theirPC.pub.
The key fingerprint is:
a2:c3:1f:1c:fc:ae:df:2f:af:77:aa:1d:81:00:6a:ed leo@myPC
The key's randomart image is:
+--[ RSA 2048]----+
|=+oo             |
|+=*+o            |
|+=o++.           |
| .=.E.           |
| o o. o S        |
|  o  o .         |

Here I have chosen the standard RSA algorithm, but gave a custom name to my private (id_rsa-theirPC) and public (id_rsa-theirPC.pub) files. This is because I want to use this pair for connecting only to theirPC machine (any name would do, BTW). You cannot see, but I chose a fancy passphrase for that too. The next step is to send the public file id_rsa-theirPC.pub to the remote machine and there, to include it into the list of public keys:
23:35[theirPC:~] cat id_rsa-theirPC.pub >> /home/leo/.ssh/authorized_keys
To test if this configuration is working, we can do the following:
23:37[myPC:~] ssh -i ~/.ssh/id_rsa-theirPC theirPC.bigcorp.com
(notice how we must explicitly tell SSH about the location of the private key, otherwise it would fall back to your password at the remote host). If everything went fine, we can automatize the process by creating a configuration file for the SSH client with our customizations:
23:39[myPC:~] cat ~/.ssh/config
Host theirPC
HostName theirPC.bigcorp.com
IdentityFile ~/.ssh/id_rsa-theirPC
This way we can easily include more and more remote machines, and in the example above I could connect with the command "ssh theirPC". But the problem is that with more machines we connect to, the more times we need to type long passphrases into. To solve this you can use ssh-agent to keep the authentication keys (the unencrypted private keys) in memory for all commands spawned from it. That is, ssh-agent acts over a command (which can be a terminal, or startx), and all commands called from it will inherit the authorization keys. But sometimes this is not enough, you might want authentication keys shared between sessions (even after logout). For me the solution was keychain (not the Mac OSX application!), which is a wrapper around ssh-agent (and its low-level friend ssh-add).

Both keychain and ssh-add can read from the terminal prompt, but normally they will use a program that provides the passphrase dialog window. This program is generally called ssh-askpass, but each window manager offers its own implementation as well. In my case I'm using ksshaskpass, that can be integrated with the  KDE Wallet system (which is installed under the name kwalletmanager). The kwallet is an application that manages passwords and passphrases, storing them in encrypted "wallets". That is, you only need to type one master password per wallet.

I will skip the details of kwallet configuration - it suffices to say that you should create at least one wallet and it will prompt you when creating or retrieving passwords - and comment on the keychain program. The installation instructions always tell us to call keychain from .bash_profile (like here), but this didn't work for me since I must make sure it is called only after KDE is up. When following the instructions, I had kwallet asking for my wallet's password (or ssh-askpass asking for the passphrase for id_rsa-theirPC, when I deactivated kwallet) before startkde being called, and thus the keyboard was unresponsive. Maybe because I have an exotic keyboard configuration. Anyway, the solution to that was to create an executable to be called after startkde, and the place to put these custom "daemons" is in ~/.kde/Autostart:
23:39[myPC:~] cat ~/.kde/Autostart/keychain.sh

# initialize SSH key management ("keychain" wrapper for ssh-agent)
# depends on a ssh_askpass (which for KDE is ksshaskpass)
keychain ~/.ssh/id_rsa-theirPC ~/.ssh/id_rsa-anotherPC
source ~/.keychain/${HOSTNAME}-sh
Keychain can also handle GnuPG signatures and several SSH private keys, like in the id_rsa-anotherPC example. Now, when I start a KDE session I am asked about my wallet password, which then offers my SSH passphrases  whenever requested. To be germane, it is actually more nuanced: the program requesting the passphrase will trigger the "upper-level" program to or offer the passphrase or ask another program for it (like in the hierarchy ssh -> ssh-agent -> keychain -> ssh-askpass -> kwallet).

Some general comments:
  • your private keys should not be accessible or readable by anybody but you ("chmod 600 /home/leo/ssh/id_rsa-theirPC");
  • the passphrase can have spaces, punctuation marks etc. So you can mix passwords, but avoid literature quotes! The larger the better;
  • avoid leaving private keys on your remote hosts, that you are unlikely to use to access other machines;
  • do not share private keys among machines, these should be present only in the machines you physically access (in my case these are my desktop and my laptop, which have different configurations);
  • you can change the passphrase later with "ssh-keygen -p id_rsa" (I haven't tried this, but I believe in the man page ;)
  • within kwallet, you can see the passwords and passphrases of open wallets in plain text. I usually panic, but these wallets are themselves encrypted...
  • I haven't tried, but it should be also possible to a) work with ssh-agent and ssh-add without keychain (launching them before the KDM or GDM display managers, or even in Autostart); b) do not use kwallet/ksshaskpass, by using the original x11-ssh-askpass or on the terminal; c) some other killer-app that I don't know about yet.

A Hakone-Zaiku opened. I never cracked the encryption key of these :(

No comments:

Post a Comment

Before writing, please read carefully my policy for comments. Some comments may be deleted.

Please do not include links to commercial or unrelated sites in your comment or signature, or I'll flag it as SPAM.


Related Posts with Thumbnails