The Linux in-kernel secret store (aka "key retention service") is a cool thing and not just useful to the AFS and Kerberos implementers. Actually, it works perfectly well as a general-purpose passphrase store, but the userland tools are somewhat idiosyncratic. Here are some extra bits and tricks that I use to make this more convenient.
Almost three years ago I saw the first mentions of this kernel store idea and had a number of fruitful discussions with the original developer (David Howells). I also contributed a few patches to the userland tools (keyutils is the name of the package).
The keyutils consist of two primary tools: keyctl and request-key. keyctl is the do-it-all read/write/request frontend, and request-key is called by the kernel if you request a secret that is not yet known. request-key can be configured to shell out to other programs (e.g. pinentry) to prompt for the secret to store. Secrets (or keys as the docs call these blobs) are stored in multiple keyrings, have permissions etc. Very nifty and well thought-out.
key id versus key label
The first problem that I have with the keyutils is that while secrets have a settable textual description, the tools use an autogenerated numeric identifier to refer to the secret in any subsequent operation.
From the perspective of wanting to store a secret for, say, fetchmail-sucking my email from a server, this is inconvenient: I can set the secret with a description like "main-mail-key" but if I want to retrieve its content, I must search the keyring first to get the id of the key labelled "main-mail-key" and run another keyctl with this id.
I find that inconvenient, so I quickly cobbled up a small application
which does all that for me (in a fashion similar to quintuple-agent's
interface). It lists, puts, deletes and gets keys,
it is called kk
and its C source is here. (If you prefer shell,
here's a bash-implementation of
the same thing.)
prompting locally and elsewhere
Adding new keys to the environment when you have the data ready is straightforward, but that's not the interesting case. For the dynamic case the keyutils have an on-demand mechanism to request a key from somewhere, and that is quite nifty - if you manage to convince it to use X11.
If asked for a nonexistent key the kernel runs /sbin/request-key
with sundry parameters as a callback, which is then expected to
create/prompt for data and
instantiate a suitable key.
You can, of course, write your own request-key to prompt on an X display,
mount usbsticks or whatever, but that is not efficient. Instead, most of
the things you might want to do are fairly easy using the config features
upstream built into request-key already.
Looking at the request-key.conf
manpage you'll find all kinds
of nice features, the most useful ones IMHO being the macro and key lookup
caps and the pipelining.
I like accessing my machines from work/afar, and I dislike storing secrets
longer than necessary. Having changed pretty much all my environments
that need passphrases to use the kernel store, I often need to update this
kernel store remotely...and as conveniently as possible, so manually
priming the keystorage with kk
or keyctl
is out.
To do this, I use the pinentry programs (from the gnupg/gnupg-agent combo)
and a small helper of mine, called askkey
(whose C source
lives here). The pinentry
things are convenient because they can prompt on an X display, take care of
all the screen/keyboard grabbing in a sane/safe fashion and so on.
The main issue with remote, asynchronous prompting (ssh-forwarded X11) is that the kernel-spawned request-key has no idea of your (preferred) DISPLAY variables or your X authentication info. My askkey helper takes care of dealing with this issue.
In my setup, request-key.conf
lists askkey
with these arguments:
create * * * |/usr/local/bin/askkey %u %g %d %{user:_display}
request-key
thus hands askkey
user and key info,
as well as a user's
_display key contents. The pipe makes request-key
use askkey
's output
as the key material.
askkey
itself does a setuid, sets the desired env vars and runs
pinentry-gtk to prompt the user and retrieve the passphrase.
The environment vars needed for this X11 program come from
the "key" named _display
. This key I set to
DISPLAY=:0.0|XAUTHORITY=/home/az/.Xauthority
on local logins. The benefit of this scheme is that I can easily change that
key on the fly for remote connections to localhost:10.0
, and
thus the prompts follow me around.
I've updated my askkey wrapper to not wait forever for pinentry to report back; instead it times out after 120 seconds and kills the pinentry process (which at that point is presumed hung or unattented, and which might have grabbed and locked the keyboard...).