Jun 20, 2020 Tags: devblog, kbs2, kbsecret, programming, 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 generationkbs2
is my attempt to reproduce the best parts of KBSecret
without all of its baggage.
To whit:
kbs2
uses age for all cryptographic operations. It wraps those
operations in an abstract “backend” and knows nothing about their details — the backend
is expected to do everything right. kbs2
can use
any number of
age implementations as its backend3.kbs2
is written in Rust, and avoids one of KBSecret’s early misdesigns: eager loading of
all records for a session upon creation.kbs2
supports many of KBSecret’s best flexibilities, and has a few tricks of its own.As a command-line tool, kbs2
’s interface bears close resemblance to KBSecret’s:
1
2
3
4
5
6
7
# 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:
1
2
3
4
5
6
$ 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
:
1
2
[commands.new]
post-hook = "~/.config/kbs2/hooks/push-repo"
Runs this script after every successful kbs2 new
run:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#!/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:
1
$ kbs2 dump --json email | json_pp
yields:
1
2
3
4
5
6
7
8
9
10
11
{
"body" : {
"fields" : {
"password" : "hanginthere!",
"username" : "catlover1994@hotmail.com"
},
"kind" : "Login"
},
"label" : "email",
"timestamp" : 1592668619
}
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
:
1
2
3
4
$ 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.