kvenv
is a simple command-line utility written in Rust that allows running arbitrary command with
a custom environment that is loaded from Azure KeyVault, GCP Secret Manager, AWS Secrets Manager or
Hashicorp Vault.
The main usage is in CI/CD pipelines - if your tool of choice does not support convenient,
per-project secrets (or the functionality does not support multitenancy) management, you might store
the secrets in KV and then subsequently load it using the kvenv
tool, without exposing secret
store credentials to the processes.
The app has three base commands:
cache
- download an environment and store it in temporary file,run-with
- run the command with environment made withcache
command, andrun-in
- run the command with freshly downloaded environment.
cache
and run-with
allow you to download the environment once, and use it for subsequent calls.
This can be used to optimize the number of network calls, sacrificing secrecy (because you store the
secret on-disk and, if not properly guarded, can be read by anyone).
run-in
can be used to run a command without storing anything to the disk. It downloads the
environment and keeps it only in memory.
The environment downloaded from the secret storage is then joined with OS environment and pass it as the process environment to the executed command.
run-in
can be used to start a command in an environment downloaded from the Cloud secret storage.
kvenv run-in [OPTIONS] <--secret-name <SECRET_NAME>|--secret-prefix <SECRET_PREFIX>> <--aws|--azure|--google|--vault> <COMMAND>
Example:
$ kvenv run-in \
--azure
--azure-tenant-id 00000000-0000-0000-0000-0000000000000\
--azure-client-id 00000000-0000-0000-0000-0000000000000\
--azure-client-secret appsecret \
--azure-keyvault-name example-keyvault \
--secret-name test \
-- env
DISPLAY=:0
LANG=en_US.UTF-8
PATH=/home/user
...
KEY_FROM_KV=Test
cache
+ run-with
pair can be used to first cache the environment and then run the commands with
that environment multiple times without accessing the storage at all.
Cache the environment
$ kvenv cache \
--azure
--azure-tenant-id 00000000-0000-0000-0000-0000000000000\
--azure-client-id 00000000-0000-0000-0000-0000000000000\
--azure-client-secret appsecret \
--azure-keyvault-name example-keyvault \
--secret-name test \
-- env
/tmp/kvenv-xxxxx.json
Run a command with the environment
$ kvenv run-with --env-file /tmp/kvenv-xxxxx.json -- env
DISPLAY=:0
LANG=en_US.UTF-8
PATH=/home/user
...
KEY_FROM_KV=Test
Remove the cached file
$ rm /tmp/kvenv-xxxxx.json
The cache
command supports --snapshot-env
option that will store the kvenv
process environment
to the cached file and use it for subsequent runs instead of fresh process env.
Every command that downloads environment (cache
and run-in
) takes one of the supported clouds:
Use AWS Secret Manager. It expects
--aws-region
- AWS region.
It uses rusoto
crate underneath and supports any AWS credentials. You can also specify
credentials directly using:
--aws-access-key-id
(orAWS_ACCESS_KEY_ID
environment variable), and--aws-secret-access-key
(orAWS_SECRET_ACCESS_KEY
environment variable).
Uses Azure KeyVault. It expects:
--azure-keyvault-name
- the name of KeyVault, or--azure-keyvault-url
- the full URL to KeyVault.
If name is provided, it constructs the KV url using https://{name}.vault.azure.net
.
The app uses azure-sdk-for-rust
, thus supports all the Azure authentication methods. You can
also specify credentials directly:
--azure-tenant-id
(orAZURE_TENATN_ID
),--azure-client-id
(orAZURE_CLIENT_ID
), and--azure-client-secret
(orAZURE_CLIENT_SECRET
).
Uses Google Secret Manager. It expects:
--google-project
- the GCP project name.
The app uses google-apis-rs
, thus supports all the methods yup2-oauth supports. You can
also specify credentials directly:
--google-credentials-file
(orGOOGLE_APPLICATION_CREDENTIALS
), or--google-credentials-json
(orGOOGLE_APPLICATION_CREDENTIALS_JSON
).
The first one expects path to the credentials JSON file, the second one expects the contents of the file.
Uses Hashicorp Vault.
It expects:
--vault-address
- The address of the vault.
It does plain HTTPS requests, thus it expects:
--vault-token
(orVAULT_TOKEN
), and--vault-cacert
(orVAULT_CACERT
).
There are two possible modes of secret storage:
- Environment stored as JSON in a single secret, or
- Secrets being environment variables.
This option is best if you want to store whole environment in a single place, or you want to store multiple different environments in a single secret store and match it to the running program (e.g. per project/tenant configuration). It expects a single key-value pair in the underlying storage, where value is a JSON object with properties being non-complex values (so no arrays and no objects).
Example JSON environment:
{
"Variable_A": false,
"Variable_B": "Value",
"Variable_C": 10
}
To get the environment as JSON, use the --secret-name
option.
If you prefer storing a single environment variable as a single secret in the storage, you can use prefixed mode. It finds all variables that start with a given prefix and interprets them as environment variables. The prefix will be stripped from secret name before using it as environment variable.
To get the environment as a list of prefixed secrets, use the --secret-prefix
option.
Since AKV secrets cannot have _
in the name, all -
will be replaced with _
(to follow the
convention used by ASP.NET Core).
Since Vault stores a list of values for a single secret, kvenv
adheres to that - it does not try
to force additional JSON encoding, it will get all pairs for a given secret directly.
When in prefixed mode, it gets all pairs for all the secrets that match the prefix and concatenate them.
kvenv
, supports masking environment variables, i.e. hiding them from the destination process. This
can be achieved by using the --mask
option, like so:
$ kvenv run-in ... --mask HOME --mask ANOTHER -- env
# There will be no `HOME` nor `ANOTHER` in the output
or
$ kvenv cache ... --mask HOME --mask ANOTHER
# There will be no `HOME` nor `ANOTHER` in the output cached file
Subsequent runs with the cached env file won't be able to see any of the mentioned variables.
- Masking
- JSON-based env keys
- ASP.NET Core-compatible key format
-
run-with
with direct env credentials (a.k.arun-in
) - Better documentation
- Integration tests
- GCP Secret Manager support
- AWS Secrets Manager support
- Hashicorp Vault support
The cmdline is Clap-based, so you have convenient help out of the box:
$ kvenv help
A simple command-line utility that allows running arbitrary commands within a custom environment thatis loaded from Azure KeyVault, GCP Secret Manager, AWS Secrets Manager or Hashicorp Vault.
Usage: kvenv <COMMAND>
Commands:
cache
Caches the environment variables from KeyVault into local file
run-with
Runs the command with the specified argument using cached environment
run-in
Runs the command with the specified argument using freshly downloaded environment
help
Print this message or the help of the given subcommand(s)
Options:
-h, --help
Print help
-V, --version
Print version