envbox: keeping secret environment variables secure
In my day to day work and evening and weekend side work, I do most almost all of my development working on remote systems. This has a number of advantages that are for another post, but this post is about one of the limitations.
Most developers have a tool belt that they’re continually improving, and as I work on mine I come across commands - like hub
- that require1 putting a secret value into an environment variable, usually for authentication.
For instance, to use hub, I need to do something like this:
$ export GITHUB_TOKEN=ba92810bab08av0ab0157028bb
$ alias git=hub
$ git create username/repo
$ git pull-request -o
If I were only running git/hub commands on my local desktop, I could put the environment variable export into my shell and be done with it. But on any remote system, I only have these options:
- Run
export GITHUB_TOKEN=..
in my shell before any command that requires it. This isn’t good because the token is now in my history, and any command that I run has access to the value. - Run each command that needs the token like this:
GITHUB_TOKEN=... git create ...
. This solves the access issue, but it still pollutes my history. It’s also cumbersome to deal with when running many commands. - Add the export to my dotfiles. This solves the history problem (and the “remembering to enter the variable” problem), but then my token is available to anyone that I share my dotfiles with.
I wanted something that I could use to securely manage these kinds of environment variables while making it convenient to expose them to specific commands. So I wrote envbox.
Envbox is written in Go, primarily because the language is quite suitable for these sorts of problems, but also because there’s a NaCl secretbox implementation in the Go “Sub Repositories”, and I thought it was a good fit for this problem.
Usage
After installation (instructions in the README), the first step is to set up envbox by generating a key:
$ envbox key generate -s
c348603fe1a708277666222a1e549b7c02b22419b3cfe44d0dd5800b3da27b56
This key is used to encrypt each of the environment variables. Next up is to add a new environment variable:
$ envbox add -n GITHUB_TOKEN
value: aeijfalsjiegliasjefliajsefljaef
$ envbox list
GITHUB_TOKEN=aeijfalsjiegliasjefliajsefljaef
Then, when running a command that needs the variable:
$ envbox run -e GITHUB_TOKEN -- bash -c 'echo $GITHUB_TOKEN'
aeijfalsjiegliasjefliajsefljaef
Or, more apropos for the above example:
alias git='envbox run -e GITHUB_TOKEN -- hub'
Storage
Envbox stores each variable in its own file on disk:
$ hexdump -C ~/.local/share/envbox/7ebac232c337c78af91cc4341d650a90a9044d0b259059e8.envenc
00000000 79 80 8b 0d e2 9c c1 85 0c 36 1c bb 6c 94 f6 3c |y........6..l..<|
00000010 25 55 fb c1 00 3a 6c 3e e4 b7 ad c3 bc cf a5 75 |%U...:l>.......u|
00000020 76 57 cb 23 c2 91 13 20 79 df 9d d8 72 89 05 26 |vW.#... y...r..&|
00000030 90 d5 f1 9e 05 26 51 fb f5 fd 3d d9 65 fa 3d b9 |.....&Q...=.e.=.|
00000040 79 ee 35 7e 6a 83 8e fd 32 56 9e f1 f7 1d ef 23 |y.5~j...2V.....#|
00000050 05 03 a2 3c cc f0 6b 8d cc 08 31 8c f2 d2 c1 a1 |...<..k...1.....|
00000060 72 33 6e 48 59 87 b5 8b 82 b3 1a b3 e3 d7 98 8c |r3nHY...........|
00000070 d8 a3 c0 04 f0 f5 c1 53 06 84 14 b7 ee 45 c0 de |.......S.....E..|
00000080 82 a2 |..|
00000082
Currently, the key is stored in a permission-restricted file in your home directory so that envbox can decrypt the files, but the plan is to move to a credential cache system like the one git uses, so that the key is only held in memory for a configurable time. This makes a better tradeoff between security and convenience. Update: Now envbox can use your OS’s native store, see here.
Summary
There are a few other things that envbox can do, such as accepting multi-line variables and differentiating the envbox name from the variable name, so that several of the same variable (e.g. two different GITHUB_TOKENs) can be tracked.
I’ve found it to be incredibly useful, allowing me to version and distribute my secret variables while keeping them secure.
Enjoy.
-
hub doesn’t actually require the environment variable, but logging in for every push and pull seems a bit inefficient. ↩︎