Skip to content

channable/vaultenv

Repository files navigation

vaultenv

Build Status

Run processes with secrets from HashiCorp Vault. It:

  1. Reads a list of required secrets
  2. Fetches them from Vault
  3. Calls exec with the secrets in the process environment

There is nothing else going on.

vaultenv supports the Vault KV API. It supports both version 1 and version 2. This support is automatic; but you do need a token which has read access on the /sys/mounts endpoint.

Comparison to alternatives

The only alternative to this tool that we are aware of is envconsul, also by HashiCorp. Unlike envconsul, vaultenv does not:

  • daemonize
  • spawn any child processes
  • manage the lifecycle of the process it provides the secrets for

All of the above should not be done by a secret fetching tool. This should be left to a service manager, like systemd.

vaultenv calls a syscall from the exec family after fetching secrets for you. This means that vaultenv replaces its own process with whatever you want. After your service has started, vaultenv is not running anymore.

This approach does mean that we cannot automatically restart services if secrets in Vault have changed.

Terminology

A brief summary of Vault terminology:

A Vault secret consists of multiple key/value pairs, which are stored under a path in a backend.

Let's use the Vault CLI to write a secret to see all the concepts in action:

$ vault write secret/production/third-party api-key=fecb0f6e97c5b37b3a814107682cf68416f072a8
              ^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
             backend          path            key                   value

Note: this will fail without a running Vault instance. Use vault server -dev to get one up and running locally.

Tutorial

Before we can start, build vaultenv locally or download a binary.

The following program depends on the secret that we stored in Vault in the previous section:

#!/bin/bash

# Fail when referencing an unbound variable
set -u

# Mentally substitute the call to echo with something like:
# curl -H "Content-Type: application/json" -H "X-API-Key: ${PRODUCTION_THIRD_PARTY_API_KEY}" -X POST -d '{"my": "payload"}' https://example.com/
echo "${PRODUCTION_THIRD_PARTY_API_KEY}"

This program will fail without PRODUCTION_THIRD_PARTY_API_KEY in its environment:

$ ./tutorial.sh
./tutorial.sh: line 8: PRODUCTION_THIRD_PARTY_API_KEY: unbound variable

We can use vaultenv to fetch the required secret before running tutorial.sh. Create a file tutorial.secrets with the following content:

production/third-party#api-key

And run vaultenv like so:

$ vaultenv --token <YOUR_VAULT_TOKEN_HERE> --no-connect-tls --secrets-file ./tutorial.secrets ./tutorial.sh
fecb0f6e97c5b37b3a814107682cf68416f072a8

This instructs vaultenv to fetch secret/production/third-party and load the contents of api-key under PRODUCTION_THIRD_PARTY_API_KEY in the environment of tutorial.sh.

Usage

vaultenv 0.16.0 - run programs with secrets from HashiCorp Vault

Usage: vaultenv [--version] [--host HOST] [--port PORT] [--addr ADDR]
                [--token TOKEN | --github-token TOKEN | --kubernetes-role ROLE]
                [--secrets-file FILENAME] [CMD] [ARGS...]
                [--no-connect-tls | --connect-tls]
                [--no-validate-certs | --validate-certs]
                [--no-inherit-env | --inherit-env]
                [--inherit-env-blacklist COMMA_SEPARATED_NAMES]