Configuring gpg-agent on a Mac
Update: As of GPG 2.1 all this might no longer be necessary. It looks like
gpg-agent
is started automatically. Hurray!
In my last article I detailed setting up GPG and git to automatically sign all of your git commits. This is a reasonable thing to do, but there’s an issue. GPG will prompt for your passphrase every time you need to sign something, so if, say, you’re rebasing a branch with twelve commits, you’ll need to type your passphrase twelve times.
If crypto’s hard to use, you’ll eventually give up and disable it. Enter
gpg-agent
.
gpg-agent
is a daemon that caches your GPG password. When GPG needs
authentication it’ll check gpg-agent
first to see if the password is cached.
If it’s cached, gpg-agent
will return it; if not, gpg-agent
will prompt the
user to enter their password through a pinentry
program and store it for a
certain amount of time.
GPG needs some information to know how to connect with gpg-agent
. It expects
this information to be stored in the GPG_AGENT_INFO
environment variable.
Only one instance of gpg-agent
should be running per machine, so we don’t want
to start it in our .bashrc
. Instead, we want to start it as a daemon when the
computer boots. On most other Unixes this would be fairly easy (we could start
it in our login shell, or maybe in our .xinitrc
), but it’s a bit more involved
on a Mac because Apple uses launchd
to start its services. Writing such a
service requires creating an associated plist in XML, and I just don’t know how
to do that. Instead I used the lovely LaunchControl program to create a
launchd
job for me.
The Steps
Install LaunchControl by downloading and installing the .app
file.
Run brew install gpg-agent
. pinentry
should have been installed as a
dependency.
Add a line containing use-agent
to your ~/.gnupg/gpg.conf
file. This tells
GPG to look for gpg-agent
and to use it if it’s available.
Configure gpg-agent
in ~/.gnupg/gpg-agent.conf
. Options are summarized in
the documentation, but I use:
default-cache-ttl 600
max-cache-ttl 7200
pinentry-program /usr/local/bin/pinentry
In particular, make sure that the pinentry-program
points to the pinentry
you just installed through brew!
Create, configure, and load a new job in LaunchControl. The job should run the following script:
/usr/local/bin/gpg-agent --daemon --enable-ssh-support --write-env-file /Users/<you>/.gpg-agent-info
Your configuration panel should look like this when everything’s set up right:
Read the environment variables in your .bashrc
. Since gpg-agent
wrote its
configuration to ~/.gpg-agent-info
, I used a script to scrape that:
if [[ $(uname) == Darwin ]]; then
if [ -f "${HOME}/.gpg-agent-info" ]; then
. "${HOME}/.gpg-agent-info"
export GPG_AGENT_INFO
export SSH_AUTH_SOCK
fi
fi
Set GPG_TTY
in your .bashrc
. This tells pinentry
where to prompt for the
password. If isn’t set pinentry
will silently fail and you’ll be in for an
extremely frustrating hour or so.
export GPG_TTY=$(tty)
Restart bash to reload the configuration. GPG should now cache passwords! If it
doesn’t, you may need to reboot your machine to reset launchd
.
Note that in the above snippet I first checked that $(uname) == Darwin
. This
isn’t necessary if you only use a Mac. However, if you share your dotfiles with
non-Mac machines (like I do), and if you start your agent through your
.xsession
(or something similar) on those machines, you’ll want to avoid
running this script, since your agents will be constantly stepping on each
others’ toes.
You might like these textually similar articles: