The perfect gpg-agent setup

When I first started using Debian properly, I played with gpg-agent and pinentry but I didn’t really understand the various bash initialisation scripts, and my botched setup annoyed me so much I disabled it again quite quickly (for example, if I left the machine logged in to GDM at home then logged in through SSH, pinentry dialogs stayed in GDM and had to be killed).

Now I’ve finally had time to get it sorted out, and this is part aide-memoire and part idiot check (hello, lazyweb). The brief:

  • gpg-agent should take care of both GPG keys and SSH keys, transparently;
  • pinentry should ask with pinentry-gtk2 at home, or at the current SSH session remotely;
  • nothing should be left lying around after a session.

I assume appropriate packages are already installed – at a minimum, gpg-agent and whichever pinentry you prefer.

Installing gpg-agent drops a hook into /etc/X11/Xsession.d, but now there are both gpg-agent and ssh-agent running. Disable ssh-agent because we’re going to let gpg-agent take care of everything: in /etc/X11/Xsession.options, comment out the line use-ssh-agent. In /etc/X11/Xsession.d/90gpg-agent, add the –enable-ssh-support parameter so the STARTUP variable looks something like:

STARTUP="$GPGAGENT --daemon --sh --enable-ssh-support --write-env-file=$PID_FILE $STARTUP"

and also disable ssh in gnome-keyring:

$ gconftool-2 --set -t bool /apps/gnome-keyring/daemon-components/ssh false

Now (after restarting your X session) you can use ssh-add to import a key into gpg-agent, and you should see a pinentry dialog asking for a password.

That takes care of X sessions, but it won’t work for SSH. This is where the different bash login scripts matter: ~/.bashrc is run for all non-login shells (that is, ones spawned from e.g. gnome-terminal) but ~/.profile is only run for login shells (that is, ones where you have to authenticate, such as SSH connections). So, at the bottom of ~/.profile, we just start another gpg-agent who doesn’t know about X:

eval $(gpg-agent --enable-ssh-support --daemon)

After restarting your SSH session and triggering a key operation, like signing a document, pinentry-curses should ask for your passphrase at the SSH shell and not leave dialogs stranded in the X session.

Finally, that second agent shouldn’t be left hanging around after we’ve finished, or there’ll be hundreds of them soon. Fortunately, the PID is recorded in the environment variable GPG_AGENT_INFO, but parsing that is a bit awkward when it’s also recorded alone in SSH_AGENT_PID. So in ~/.bash_logout, we just

kill $SSH_AGENT_PID

(Most of the pointers for this setup came from http://wiki.kumina.nl/index.php/Managing_ssh_keys_with_gpg-agent and http://stefaanlippens.net/bashrc_and_others)

5 Comments

  1. A great write-up! Just one question: have you tried playing around with the “keychain” package? 🙂

  2. Nick says:

    I second Peter’s keychain suggestion.

    http://www.gentoo.org/doc/en/keychain-guide.xml

    I use it everywhere to manage my ssh and gpg agents. You can usually get by with as little as

    eval $(keychain –eval –quick –quiet)

    in your bashrc.

  3. Anonymous says:

    I’ve never found a need for either ssh-agent or gpg-agent on a remote system; I only ever need them locally. I don’t allow remote access to any system with my GPG key on it, and I use SSH agent forwarding to trusted machines on the rare occasions I need it.

    On my local system, I let the X session scripts start gpg-agent, and I use libpam-ssh for ssh-agent.

  4. Elessar says:

    Very interesting! I am also looking for the perfect gpg-agent setup, though I would like to satisfy another constraint that is, I think currently unavailable: to have the agent ask for confirmation each time a software want to use a key, telling me what process it is.

Comments are closed.