ENOSUCHBLOG

Programming, philosophy, pedaling.


Goodbye KBSecret, hello kbs2

Jun 20, 2020

Tags: programming, devblog, kbsecret, ruby, rust

A little over three years ago, I began work on a new secret manager: KBSecret.

KBSecret’s distinguishing features were as follows:

Less distinguishing but also notable features were its customizability and adherence to POSIX-ish best practices: each kbsecret subcommand was designed to behave well in the presence of $EDITOR, $PAGER, $IFS and so forth; all outputs were designed to be easily consumable and composable with tools like awk, grep, and xargs. Each subcommand was also completely introspective and capable of emitting its own flags and fully expanded positional arguments via --introspect-flags.

KBSecret is written in heavily metaprogrammed Ruby, meaning that it was slow to begin with. Aggressive customizability added to its performance woes, and KBFS’s latency pushed it over the edge: kbsecret list would regularly take over a second of wall time just to list the records in a session. This was fine for my local purposes, but frustrated prospective users.

More glaringly, KBSecret has always relied on Keybase and KBFS to securely store its secrets when at rest. This was historically a non-issue: Keybase was an independent startup with a competent team1 and had taken pains to open-source virtually all of their client-side code, including KBFS itself.

Now that they are owned by Zoom, the future of Keybase and KBFS is less certain. To avoid repeating aspersions about Zoom2: it’s just not clear whether the Keybase client and server will receive the maintenance they require. Building a secret manager around a service whose future is uncertain doesn’t make a lot of sense.

All told, KBSecret is a bit of a dead end: it’s slow, difficult to maintain, and depends fundamentally on a service that’s currently somewhere between “acquihire” and “incredible journey”.

kbs2: the next generation

kbs2 is my attempt to reproduce the best parts of KBSecret without all of its baggage.

To whit:

As a command-line tool, kbs2’s interface bears close resemblance to KBSecret’s:

# NOTE: -k login is the default and can be omitted
$ kbs2 new -k login email
Username: catlover1994@hotmail.com
Password: [hidden]

$ kbs2 pass email
hunter2

versus the old:

$ kbsecret new login email
Username? catlover1994@hotmail.com
Password? [hidden]

$ kbsecret pass email
hunter2

Full CLI documentation is available here.

kbs2, in the interest of simplicity (and unlike KBSecret), does not have any notion of separate sessions. It also does not have native functionality for sharing secrets between multiple users. Because it doesn’t piggyback on top of KBFS, it does not natively sync secrets between multiple machines.

kbs2 makes up for some of these deficiencies by being even more configurable than KBSecret. It supports hooks, allowing users to augment the built-in commands with additional functionality, like synchronization.

For example, the following block in ~/.config/kbs2/kbs2.conf:

[commands.new]
post-hook = "~/.config/kbs2/hooks/push-repo"

Runs this script after every successful kbs2 new run:

#!/usr/bin/env bash

# push-repo: a kbs2 post-hook to sync the underlying git repo to the remote after any changes

set -eo pipefail

>&2 echo "[+] post-hook: ${0}"

[[ -n "${KBS2_HOOK}" ]] \
  || { >&2 echo "Fatal: Not being run as a hook?"; exit 1; }

git add -A . 2>/dev/null
git commit --no-gpg-sign -m "$(date)" 2>/dev/null
git pull --rebase 2>/dev/null
git push origin master 2>/dev/null

See the configuration documentation for supported hooks, and the hooks documentation for what hooks can do.

Like KBSecret, kbs2 uses JSON as its underlying serialization format. You can use kbs2 dump --json to consume this format in your own custom commands:

$ kbs2 dump --json email | json_pp

yields:

{
   "body" : {
      "fields" : {
         "password" : "hanginthere!",
         "username" : "catlover1994@hotmail.com"
      },
      "kind" : "Login"
   },
   "label" : "email",
   "timestamp" : 1592668619
}

Next steps

kbs2 is still an alpha-quality project. Like all alpha-quality projects (and especially those that deal with cryptography and secret management), kbs2 should only be used by those willing to risk data loss and/or compromise.

If you’re one of those people: you can install it today via cargo:

$ cargo install kbs2
# load kbs2's tab completions into the current shell!
$ eval "$(kbs2 --completions=bash)"
$ kbs2 init

There are also open issues that could use your help, as well as a contrib directory for external functionality that may be useful to the larger community. The hacking docs have more details on local development.


  1. From the perspective of this outsider, of course. 

  2. Zoom’s history of dubious security practices is easy enough to find online. 

  3. You can read more about how kbs2 uses age (and particularly key wrapping) here