| Crates.io | secenv |
| lib.rs | secenv |
| version | 0.2.1 |
| created_at | 2025-09-01 01:24:59.390932+00 |
| updated_at | 2025-11-14 22:26:00.404204+00 |
| description | Secure environments. |
| homepage | https://github.com/cchexcode/secenv |
| repository | https://github.com/cchexcode/secenv |
| max_upload_size | |
| id | 1819018 |
| size | 128,796 |
Secure, profile-based environment variable management with HOCON configuration, PGP decryption, and optional GCP Secret Manager integration for retrieving PGP private keys.
gcloudgit clone https://github.com/cchexcode/secenv
cd secenv
cargo build --release
The binary will be at target/release/secenv.
secenv.conf (JSON or HOCON)version = "0.0.0" # Must be semver and compatible with the CLI version
profiles.default {
# Optional: Define temporary files that will be created before command execution
# and automatically cleaned up afterwards
files {
# Plain file example
# "./config.json".plain.literal = '{"key": "value"}'
# Secure file with PGP-encrypted content
# "./credentials.key".secure {
# secret.pgp.gpg.fingerprint = "1E1BAC706C352094D490D5393F5167F1F3002043"
# value.base64 = "<base64-encoded ASCII-armored PGP message>"
# }
}
env {
# Optional regex patterns of variables to keep when executing a command.
# If set, the child environment is cleared first, then only matching host vars are kept.
# If omitted, the full host environment is kept.
# keep = ["^PATH$", "^SHELL$", "^LC_.*"]
vars {
# Plain inline values
APP_NAME.plain.literal = "myapp"
# DB_HOST.plain.base64 = "bG9jYWxob3N0" # "localhost"
# Secure PGP-decrypted value using a GPG key from local keyring by fingerprint
SECRET_TOKEN.secure {
secret.pgp.gpg.fingerprint = "1E1BAC706C352094D490D5393F5167F1F3002043"
value.base64 = "<base64-encoded ASCII-armored PGP message>"
}
# Secure PGP-decrypted value using a private key stored in GCP Secret Manager
# secret.pgp.gcp.secret must be a fully qualified resource:
# projects/<project>/secrets/<name>[/versions/<version>]
# version defaults to "latest" if omitted.
SERVICE_TOKEN.secure {
secret.pgp.gcp.secret = "projects/123456789/secrets/pgp-private-key"
# secret.pgp.gcp.version = "latest" # optional
value.literal = """
-----BEGIN PGP MESSAGE-----
...
-----END PGP MESSAGE-----
"""
}
}
}
}
Notes:
secenv init to generate a JSON example file, or write your own in HOCON format.version field is validated against the CLI version. The config cannot be newer than the CLI, and major versions must match.secret.pgp.literal, secret.pgp.file, secret.pgp.gpg.fingerprint, secret.pgp.gcp.secret (+ optional .version).# Print key=value pairs for the default profile
secenv unlock
# Use a specific profile and config path
secenv unlock --config /path/to/secenv.conf --profile production
# Load into current shell (bash/zsh/fish)
eval "$(secenv unlock --profile production)"
To run a command with the variables set:
# Run a program inheriting host environment (default behavior)
secenv unlock --profile production -- env | sort
# With keep configured in the profile, only matching host vars are preserved
secenv unlock --profile production -- printenv | sort
# Execute a command (temporary files defined in the profile will be created and cleaned up)
secenv unlock --profile production -- make deploy
# Overwrite existing files if they already exist
secenv unlock --profile production --force -- make deploy
Output format when printing:
APP_NAME=myapp
SECRET_TOKEN=...
Note: When executing a command, any files defined in profiles.<profile>.files are created before the command runs and automatically deleted after the command completes. Use --force to overwrite existing files.
The temporary files feature allows you to create files with sensitive content that are automatically managed by secenv. This is useful for:
.kubeconfig, .aws/credentials, service account keys) that are needed by commands but should not persist on diskprofiles.<profile>.files section of the config--force is usedprofiles.production {
files {
# Temporary kubeconfig for kubectl commands
"./kubeconfig".secure {
secret.pgp.gcp.secret = "projects/myproject/secrets/pgp-key"
value.base64 = "<base64-encoded-pgp-message>"
}
# Temporary service account key
"./service-account.json".secure {
secret.pgp.gpg.fingerprint = "1E1BAC706C352094D490D5393F5167F1F3002043"
value.base64 = "<base64-encoded-pgp-message>"
}
}
env.vars {
KUBECONFIG.plain.literal = "./kubeconfig"
GOOGLE_APPLICATION_CREDENTIALS.plain.literal = "./service-account.json"
}
}
Then run:
secenv unlock --profile production -- kubectl get pods
# The kubeconfig and service account files are created, kubectl runs, then files are deleted
version = "<semver>"
profiles = {
<name> = {
files = { ... } # optional
env = {
keep = [<regex>], # optional
vars = { ... } # required
}
}
}
profiles.<profile>.files {
# Define temporary files that will be created before command execution
# and automatically cleaned up afterwards
# Plain file content
"/path/to/file".plain.literal = "file content"
"/path/to/file".plain.base64 = "<base64-encoded content>"
# Secure file content (PGP-decrypted)
"/path/to/secure.key".secure {
# Use any of the same PGP secret sources as environment variables
secret.pgp.file = "/path/to/private.key"
# or secret.pgp.literal, secret.pgp.gpg.fingerprint, secret.pgp.gcp.secret
value.literal = "-----BEGIN PGP MESSAGE-----..."
# or value.base64 = "<base64-encoded-ASCII-armored-message>"
}
}
profiles.<profile>.env.keep = ["^PATH$", "^LC_.*"] # optional
profiles.<profile>.env.vars { # required
# Plain values (inline only)
KEY.plain.literal = "value"
KEY.plain.base64 = "<base64-encoded string>"
# Secure values (PGP-decrypted)
KEY.secure {
# One of the following PGP private key sources:
# Inline (EncodedValue): choose one encoding
# secret.pgp.literal.literal = """
# -----BEGIN PGP PRIVATE KEY BLOCK-----
# ...
# -----END PGP PRIVATE KEY BLOCK-----
# """
# or
# secret.pgp.literal.base64 = "<base64-encoded ASCII-armored private key>"
# OR
# secret.pgp.file = "/path/to/private.key"
# OR
# secret.pgp.gpg.fingerprint = "<fingerprint>"
# OR
# secret.pgp.gcp.secret = "projects/<project>/secrets/<name>"
# secret.pgp.gcp.version = "latest" # optional
# Encrypted value to decrypt (ASCII-armored PGP message)
value.literal = "-----BEGIN PGP MESSAGE-----..."
# or
# value.base64 = "<base64-encoded-ASCII-armored-message>"
}
}
literal or base64secret.pgp.*)Important:
literal/base64.fingerprint.Global options:
-e, --experimental – enable experimental featuresCommands:
Unlock values, create temporary files, and optionally execute a command with the variables set.
secenv unlock [OPTIONS] [--] [COMMAND...]
Options:
-c, --config <path> Path to config (default: secenv.conf)
-p, --profile <name> Profile name (default: default)
-f, --force Overwrite existing files defined in the manifest
Behavior:
COMMAND, prints KEY=VALUE lines to stdout. If the profile defines temporary files, they are created and immediately cleaned up.COMMAND, executes it with variables set and temporary files created. Files are automatically cleaned up after the command completes.env.keep is set in the profile, the child environment is cleared first and only host variables matching any regex in keep are preserved; otherwise, the full host environment is kept.profiles.<profile>.files are created before command execution:
--force is specifiedRender the manual pages or markdown help.
secenv man --out <directory> --format <manpages|markdown>
Generate shell completion scripts.
secenv autocomplete --out <directory> --shell <bash|zsh|fish|elvish|powershell>
Initialize a new config file.
secenv init [--path <path>] [--force]
Notes:
--path (default: secenv.conf) in JSON format.version, profiles, and vars as shown in the examples.gcloud (gcloud auth login or service account with suitable permissions).projects/<project>/secrets/<name> (optional /versions/<version>; defaults to latest).profiles.<name> exists in the config.--force to overwrite or remove the existing file.gcloud authentication, project, permissions, and secret name.For verbose logs:
RUST_LOG=debug secenv unlock
cargo run -- unlock -- env
The password for all private keys for testing is test.
git clone https://github.com/cchexcode/secenv
cd secenv
cargo build
cargo test
MIT – see LICENSE.