Monthly Archives: December 2007

SSH Key Management and Presence

There are a number of excellent guides to setting up public key authentication for ssh, but they tend to stop short of describing how to integrate presence events like a screensaver turning on. It’s a topic that isn’t possible to cover in a generic way, since it depends heavily on your operating system, distribution, desktop environment, and preferred shell. I present here the information I’ve pulled together to get things running under Linux, specifically Fedora 8 with Gnome and Bash.

First off, if you’re not already quite familiar public key authentication, go read the three part IBM developerWorks series on the topic (1, 2, 3), which is the best primer I’ve found. I’m using public key authentication with encrypted keys, am caching my credentials with ssh-agent, and am using keychain as my interface to ssh-agent. My primary goal was to automatically run keychain --clear to clear my credentials any time I left my system unattended. I also outline how to run keychain ~/.ssh/id_rsa when you return to your system (or whenever you open a shell) in order to reload your ssh key.

Login

When I log in to my system, keychain runs and does some housekeeping. It starts an ssh-agent process if one isn’t already running and prompts for the passwords to my ssh keys if they aren’t already loaded, or if all that has already been done it just reports its status and exits. The following lines can be placed in ~/.bash_profile which is executed when you log into your system (via remote ssh session, text console, and oddly enough gnome executes bash_profile on login as well).

if [ "$PS1&" ]; then
/usr/bin/keychain ~/.ssh/id_rsa
source ~/.keychain/yourhostname-sh
fi

The “if” statement ensures that keychain is only run for interactive shells. Because keychain generates output on execution it can confuse some programs that run non-interactively, notably sftp breaks if you don’t do this.

New Shell

I actually like keychain to run every time I start a new shell, not just when I first log in. This means that I can clear my credentials manually if I won’t be using ssh for a while and when I open a fresh terminal window (or “window” in a screen session, or whatever) keychain automatically prompts me for my password. This can be done by placing the same lines from above in ~/.bashrc instead of bash_profile (bashrc is executed from bash_profile, so you only need one or the other).

Screensaver

When my screensaver turns on, it’s an indication that I’m away from my desk and that my credentials should be cleared. To my knowledge, gnome-screensaver does not provide per-user screensaver-on and screensaver-off scripts where you can easily add these sorts of things (it should, if you ask me). It does, however, emit a DBUS signal that you can listen for and act on. I found some folks using python scripts to handle similar needs and adapted them for my purpose, others have done similar things with bash script. Once you’ve customized your DBUS signal listener script, add it to your default gnome session using System –> Preferences –> Personal –> Sessions so that it’s automatically started when you log in.

#!/usr/bin/python
import dbus
from dbus.mainloop.glib import DBusGMainLoop
import gobject
import os

def clear_keychain(state):
"""Called when screensaver on/off events occur"""

# clear ssh keys when screensaver turns on
if state == True:
os.system('/usr/bin/keychain --clear')

# Load ssh keys when screensaver turns off
#     if state == False:
#          os.system('/usr/bin/keychain id_rsa')

# Connect to the gnome session bus:
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
bus = dbus.SessionBus()

# Listen for SessionIdleChanged signals
bus.add_signal_receiver(clear_keychain,'SessionIdleChanged','org.gnome.ScreenSaver')
loop = gobject.MainLoop()
loop.run()

Logout

Logging out of the system (whether from a remote ssh session, a local text console, or a graphical gnome session) is an indication that my workstation is going to be idle for a while and that my credentials should be cleared. This can be (mostly) accomplished by making an addition to ~/.bash_logout. This file is run any time a non-gnome login shell exits, like a remote ssh session or a local text console session (but not terminal windows in gnome, screen windows, or other non-login shells):

/usr/bin/keychain --clear

For some utterly insane reason, gnome doesn’t execute bash_logout even though it does execute bash_profile on login, and it doesn’t provide a sane alternative. The only method I’m aware of for running a script on gnome-logout involves xsession hackery, but I’ve punted on this issue since I rarely exit my gnome session. If you find an elegant solution, leave a comment.

Other SSH Tips

  • SSH Aliases: This is somewhat off-topic for this article, but is such a great timesaver that it bears a quick mention in any article about ssh. You can define short names for hosts you ssh to often in ~/.ssh/config.
  • Clearing Credentials At Login: An alternative to all of this, and one of the strategies suggested in the developerWorks series is to start keychain with the –clear option in .bash_profile or wherever you call it from. The assumption is that by clearing your credentials on login instead of logout, you can stay authenticated all the time (and gain the benefit of being able to run cron scripts) but an attacker will lose access to your credentials the moment they try to access your account. It’s an interesting strategy, but not one I’m entirely comfortable with. I prefer to clear my credentials when they’re not being used, and designate special-purpose keys with appropriate constraints for cron jobs.

Conclusion

With the tips in the developerWorks series, and the information in this article, you can have an incredibly convenient ssh key management setup while you’re using your computer and know that your credentials will be automatically cleared when you’re away from your system.