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.

Update (Tue 04.09.2012 20:44):

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...).

[ published on Sun 24.08.2008 17:17 | filed in interests/crypto | ]
Debian Silver Server
© Alexander Zangerl