Skip to main content

keenv

keenv puts secrets from a KeePass database into the environment of one command and nowhere else. The values never reach a file, an export, or the shell history: they exist between unlocking the database and execing the command, and the process that held them is replaced.

It is the tool the Oberon Systems keyring policy names for local secrets, and the way indech hands the Cloudflare R2 keys to OpenTofu.

Contents

Why

The usual ways of getting a secret into a process all leave it somewhere: export puts it in every child of the shell for the rest of the session, a .env full of plaintext puts it on disk, and eval $(something) puts it in the history file as well.

keenv reads the value out of the database at the moment it is needed, builds the environment for exactly one command, and replaces itself with that command. There is no keenv export and no keenv eval, on purpose.

Installation

pip install keenv

The database itself is read in process through pykeepass, so KeePassXC does not have to be installed.

Configuration

keenv reads two files, both optional. keenv.yaml names the database and maps environment variables onto entries:

vault: ~/Dropbox/oberon.kdbx
keyfile: ~/.keys/oberon.keyx

env:
  AWS_ACCESS_KEY_ID:
    entry: Oberon/R2/indech-state
    field: username
  AWS_SECRET_ACCESS_KEY:
    entry: Oberon/R2/indech-state
    field: password

.env is the same mapping in the shape people already write, where a value may be a keenv:// reference instead of a literal:

AWS_ACCESS_KEY_ID=keenv://Oberon/R2/indech-state/username
AWS_SECRET_ACCESS_KEY=keenv://Oberon/R2/indech-state/password
TF_LOG=INFO

A reference is keenv://<entry path>/<field>. The last segment is the field and everything before it is the path to the entry, so a field whose name contains a slash cannot be addressed. username, password, url, notes and title are matched case-insensitively; any other name is looked up as a custom attribute, with its spelling preserved.

Values that are not references pass through literally. A # only starts a comment at the beginning of a line, never in the middle of one, because a secret may contain it.

The layers apply in this order, each one overriding the last:

Layer Set by
keenv.yaml -c, default ./keenv.yaml
.env -e, default ./.env
the database path vault:, then KEENV_VAULT, then --vault
the key file path keyfile:, then KEENV_KEYFILE, then --keyfile

A file that is not there is an empty layer, not an error. Having nothing to resolve after both layers is an error.

keenv.yaml is validated against a pydantic model that rejects keys it does not know, so vualt: is reported as a mistake rather than quietly ignored.

Usage

Run a command with the resolved environment:

keenv run -- tofu -chdir=circuits/live/ramnode/compute plan

Check that every reference still points at something, without printing any value:

keenv check

Expected output:

AWS_ACCESS_KEY_ID            keenv://Oberon/R2/indech-state/UserName    20 chars
AWS_SECRET_ACCESS_KEY        keenv://Oberon/R2/indech-state/Password    40 chars

Point at another database and another mapping:

keenv run --vault ~/other.kdbx -e deploy.env -- ./deploy.sh

Exit codes are 0 on success, 1 for anything keenv can explain, 2 for a usage mistake, and 127 when the command does not exist. Otherwise the exit code is the command's own, because the command replaces keenv.

How it works

  1. Both layers are read and merged into one list of variables.
  2. If any of them is a keenv:// reference, the database is opened once. The master password is asked for on /dev/tty, never on stdin, so a password prompt can never swallow the first line of a pipe. A key file replaces the prompt.
  3. Every reference is resolved from that one open database.
  4. The resolved variables are laid over a copy of the current environment and handed to os.execvpe.

Step 4 is what keeps the secrets contained: execvpe replaces the process image, so nothing that held the values is still running once the command starts, and the shell that invoked keenv never saw them.

Development

make init
make test
make lint

make init creates .venv, installs the package in editable mode and wires up the pre-commit hooks. The test suite builds its own throwaway database in a temporary directory; no test opens a real vault.

Commits go through commitizen:

.venv/bin/cz commit

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

keenv-0.1.1.tar.gz (7.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

keenv-0.1.1-py3-none-any.whl (9.7 kB view details)

Uploaded Python 3

File details

Details for the file keenv-0.1.1.tar.gz.

File metadata

  • Download URL: keenv-0.1.1.tar.gz
  • Upload date:
  • Size: 7.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.15

File hashes

Hashes for keenv-0.1.1.tar.gz
Algorithm Hash digest
SHA256 06d2e626af3437024e76bdd73532e37d8b2baf376436e062d3402d00d0eb73f0
MD5 27a5f37a1b71e1fef9d13c9bc7a6bc85
BLAKE2b-256 dfec6595101750d0caee2e64cda7bbb3f3acde98fef93e51d97c0f0f8fde0cc8

See more details on using hashes here.

File details

Details for the file keenv-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: keenv-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 9.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.8.15

File hashes

Hashes for keenv-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 e801837d9f968b4cba8d5b16efac6cbd303c905529e97c3405a1001b1077b3e8
MD5 1f23cbfb2aaa3c27526bcadf52a37c23
BLAKE2b-256 5f7483ab99ac432146fed2d1e90dae7eeb636c521f094a26fa1e9f553753b356

See more details on using hashes here.

Release history Release notifications | RSS feed

0.3.1

2 files

0.2.1

2 files

0.2.0

2 files

0.1.2

2 files

This release

0.1.1 This release

2 files

0.1.0

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page