@chroma-x/vaultenv
v2.2.3
Published
Access secrets managed by HashiCorp Vault as environment variables and substitute them into sub commands.
Readme
vaultenv
Access secrets managed by HashiCorp Vault as environment variables and substitute them into sub commands.
vaultenv is a Node.js CLI that fetches secrets from a Vault KV secret path and either injects them as environment variables into a child process (run) or displays them (show). It supports multiple named configurations per project, username/password, Active Directory and AppRole authentication, and a consistency check across configurations (e.g. to compare staging vs. production secrets).
Inspired by dotenvx and Doppler — the same "inject secrets as env vars and run your command" workflow, but with HashiCorp Vault as the single source of truth and no additional secrets platform required.
Features
- Env substitution – Run any command as a sub process with secrets from Vault injected as environment variables
- Multiple configs per project – Manage several Vault configurations (e.g.
dev,staging,prod) side by side in one project via a.vaultenv.jsonfile - Multiple auth methods – Username/password or Active Directory login, AppRole login, or a directly provided client token
- Token store – Client tokens are persisted per project and config in
~/.vaultenv, so you only log in once - Consistency check – Verify that the secret keys of one or more configs match those of a reference config
- Signal forwarding – Signals (
SIGINT,SIGTERM,SIGHUP, …) are forwarded to the sub process; its exit code is propagated - Interactive prompts – Any missing option (method, config, username, password, …) is asked for interactively
Installation
npm install --save-dev @chroma-x/vaultenv
# or globally
npm install --global @chroma-x/vaultenv
# or run without installing
npx @chroma-x/vaultenv --helpRequires Node.js >= 20.
Quick start
# 1. Configure the Vault connection for your project
vaultenv config --url https://vault.example.com --path my-project/env
# 2. Log in to Vault
vaultenv login
# 3. Run your command with the secrets injected as env vars
vaultenv run -- npm startConfiguration
Configuration is stored per project in a .vaultenv.json file in the current working directory. Each entry maps a config name to a Vault base URL and secret path:
{
"default": {
"baseUrl": "https://vault.example.com",
"secretPath": "my-project/dev"
},
"prod": {
"baseUrl": "https://vault.example.com",
"secretPath": "my-project/prod"
}
}If more than one config exists and no --config option is given, the CLI prompts you to select one.
Note:
.vaultenv.jsoncontains no secrets and is safe to commit. Client tokens are stored outside the repository in~/.vaultenv/.
Commands
vaultenv config
Define a Vault config with base URL, secret path and an optional name.
| Option | Description |
| --- | --- |
| -u, --url <value> | The base URL the Vault API is accessible at |
| -p, --path <value> | The path the secrets are located at |
| -n, --name [value] | Optional name to deal with multiple configs in one project (default: default) |
vaultenv remove-config
Remove a Vault config from the project. Also removes the stored token for that config.
| Option | Description |
| --- | --- |
| -n, --name [value] | Optional name identifying the config to be removed |
vaultenv login
Log in to Vault via username/password or Active Directory and store the client token.
| Option | Description |
| --- | --- |
| -m, --method <value> | The Vault auth method (one of userpass, activedir) |
| -u, --username <value> | The Vault username |
| -p, --password <value> | The Vault password |
| -c, --config [value] | Optional config name |
If --method is omitted, the CLI prompts you to select one.
vaultenv multi-login
Log in to Vault for multiple configs at once with the same credentials.
| Option | Description |
| --- | --- |
| -m, --method <value> | The Vault auth method (one of userpass, activedir) |
| -u, --username <value> | The Vault username |
| -p, --password <value> | The Vault password |
| -c, --configs [value...] | Optional config names |
vaultenv logout
Remove the stored client token(s).
| Option | Description |
| --- | --- |
| -c, --config [value] | Optional config name |
| -a, --all | Logout from all configs in the project |
vaultenv run
Run a command as a sub process with the env substituted from the Vault secrets. The command to run must be separated with --.
vaultenv run --config=prod -- node server.js| Option | Description |
| --- | --- |
| -t, --token <value> | Optional client token used instead of a previous login |
| --appRole <value> | Optional role for AppRole login |
| --appRoleId <value> | Optional role id for AppRole login |
| --appRoleSecretId <value> | Optional secret id for AppRole login |
| -c, --config [value] | Optional config name |
The sub process inherits the current environment plus the Vault secrets, receives forwarded signals, and its exit code becomes the exit code of vaultenv.
vaultenv show
Show the env derived from the Vault secrets for the current config. Secret values are masked unless --unmask is set.
| Option | Description |
| --- | --- |
| -t, --token <value> | Optional client token used instead of a previous login |
| --appRole <value> | Optional role for AppRole login |
| --appRoleId <value> | Optional role id for AppRole login |
| --appRoleSecretId <value> | Optional secret id for AppRole login |
| -c, --config [value] | Optional config name |
| -u, --unmask | Show secret values in plain text |
vaultenv check-consistency
Check whether the secret keys of one or multiple configs match those of a reference config. Prints a comparison table and exits with code 1 if keys are missing.
vaultenv check-consistency --referenceConfig=prod --comparisonConfigs staging dev| Option | Description |
| --- | --- |
| -t, --token <value> | Optional client token used instead of a previous login |
| --appRole <value> | Optional role for AppRole login |
| --appRoleId <value> | Optional role id for AppRole login |
| --appRoleSecretId <value> | Optional secret id for AppRole login |
| -r, --referenceConfig [value] | Optional config name used as the reference |
| -c, --comparisonConfigs [value...] | Optional config names to undergo the check |
Global options
| Option | Description |
| --- | --- |
| --v | Log level info |
| --vv | Log level debug |
| -V, --version | Print the version |
| -h, --help | Print help |
Authentication
Secrets-fetching commands (run, show, check-consistency) resolve the client token in this order:
- Explicit token – provided via
--token - AppRole – if
--appRole,--appRoleIdand--appRoleSecretIdare all given, an AppRole login is performed (useful for CI/CD) - Token store – the token stored by a previous
vaultenv loginorvaultenv multi-loginfor the current project and config
Interactive logins (login), multi-login) support the userpass (username/password) and activedir (Active Directory/LDAP) auth methods via --method; if omitted, the CLI prompts you to select one.
CI/CD usage
For non-interactive environments, use AppRole or a pre-issued token:
vaultenv run \
--appRole my-role \
--appRoleId "$VAULT_ROLE_ID" \
--appRoleSecretId "$VAULT_SECRET_ID" \
-- npm run deployToken store
Tokens are stored in ~/.vaultenv/, keyed by the project working directory and config name (e.g. Users_me_projects_my-app--default). They never end up in the project directory. Use vaultenv logout (or logout --all) to remove them.
Development
# Install dependencies
npm install
# Type check
npm run typecheck
# Lint
npm run lint
# Build (esbuild bundle to dist/main.js)
npm run build
# Build and run the CLI locally
npm run dev -- <command>The CLI is bundled with esbuild into a single dist/main.js; runtime dependencies remain external and are installed from npm.
Built on commander, @inquirer/prompts, execa and chalk.
Releasing
prepack runs type checking, linting and the build automatically before packing or publishing, so a release is a single command:
npm run publish:patch # or publish:minor / publish:majorThis bumps the version, creates a git tag and publishes to npm. Push the tag afterwards with git push --follow-tags.
Contributing
Contributions are welcome. Please open an issue to discuss substantial changes first, and make sure linting (eslint) and type checks pass before submitting a pull request.
