Encrypted environment variable management for teams and projects
Project description
๐ envault
Encrypted environment variable management for teams and projects
Stop leaking secrets in .env files. Encrypt them at rest, share securely, and inject at runtime.
AES-256-GCM Encryption + Multi-Environment Support + Zero Infrastructure
Why This Exists
Every team has the same problem: .env files with plaintext secrets committed to repos, shared over Slack, or lost when someone leaves. Cloud secrets managers like HashiCorp Vault or AWS Secrets Manager require infrastructure, setup, and ongoing maintenance. For most projects, that is overkill.
envault sits in the sweet spot -- AES-256-GCM encryption with scrypt key derivation, multi-environment support (dev/staging/prod in one file), and zero infrastructure. It is just a JSON file you can commit to your repo. The secrets inside are encrypted. Share the password or key out of band, and your whole team has access.
- Encrypted at rest -- AES-256-GCM with scrypt key derivation means secrets are safe even if the vault file is committed
- Multi-environment -- manage dev, staging, and prod secrets in a single file with environment inheritance
- Export anywhere -- dotenv, shell, Docker, JSON, YAML, Kubernetes Secrets with one command
- Zero infrastructure -- no server, no cloud service, no accounts, just a JSON file and a password
Stop sharing plaintext .env files. Start encrypting them.
Features
| Category | Feature | Description |
|---|---|---|
| Encryption | AES-256-GCM | Military-grade authenticated encryption |
| Encryption | scrypt Key Derivation | Password-based key derivation with configurable parameters |
| Encryption | Key-based Auth | Base64-encoded 256-bit keys for team sharing |
| Encryption | Password Rotation | Re-encrypt all secrets with a new password |
| Encryption | Key Rotation | Re-encrypt all secrets with a new key |
| Environments | Multi-Environment | dev, staging, prod in one vault file |
| Environments | Environment Inheritance | staging inherits from default, prod overrides |
| Environments | Environment Diffing | Compare variables across environments |
| Environments | Environment Copying | Clone entire environments |
| Variables | Set/Get/Delete | Full CRUD operations with metadata |
| Variables | Bulk Set | Set multiple variables at once |
| Variables | Rename | Rename variables without re-encryption |
| Variables | Search | Case-insensitive name search across environments |
| Variables | Tags | Categorize variables with multiple tags |
| Variables | Groups | Organize by prefix (DB_, API_, AWS_) |
| Variables | Interpolation | ${DB_USER}:${DB_PASS} template syntax with defaults |
| Variables | Validation | Enforce URL, email, port, pattern, length constraints |
| Variables | Expiry/TTL | Time-based variable expiration with warnings |
| Variables | History | Full change audit trail (set, delete, rename, rotate) |
| Export | dotenv | Standard .env file format |
| Export | Shell | export VAR=value statements |
| Export | Docker | Docker --env-file compatible |
| Export | JSON | Structured JSON output |
| Export | YAML | YAML-formatted output |
| Export | Kubernetes Secret | K8s Secret manifest with base64 encoding |
| Import | .env Files | Parse and import standard dotenv files |
| Import | JSON | Import from JSON files |
| Runtime | Process Injection | Run commands with injected environment variables |
| Security | Access Control | Role-based (admin/editor/viewer) with environment/variable restrictions |
| Security | Secret Detection | Detect weak secrets and default values |
| Security | gitignore Generation | Auto-generate gitignore entries for vault files |
| Security | Secure Display | Multiple masking styles for terminal output |
| Reliability | Atomic Saves | Temp file + rename to prevent corruption |
| Reliability | File Locking | Prevent concurrent modifications with stale lock detection |
| Reliability | Backup/Restore | Timestamped backups with verification |
| Reliability | Snapshots | Point-in-time state comparison |
| Reliability | Migration | Vault file version upgrade support |
| Configuration | .envaultrc | Project-level configuration file |
| Configuration | pyproject.toml | [tool.envault] section support |
| Configuration | .env.example | Smart placeholder generation (no secrets exposed) |
๐ Quick Start
# 1. Install envault
pip install -e .
# 2. Initialize a vault with password
envault init
# 3. Set your first secret
envault set DATABASE_URL "postgres://localhost/mydb" -e dev
Your secrets are now encrypted at rest in .envault.json.
๐ CLI Commands
envault init
Initialize a new encrypted vault.
# Password-based (interactive prompt)
envault init
# Key-based (prints key to save securely)
envault init --key
# Custom path
envault init --path secrets/vault.json
envault set
Set a variable in the vault.
# Basic set
envault set API_KEY "sk-secret-key"
# With environment, description, and tags
envault set DATABASE_URL "postgres://prod-host/db" \
-e prod \
-d "Production database" \
-t database -t critical
envault get
Get a decrypted variable value.
envault get API_KEY
envault get DATABASE_URL -e prod
envault list
List all variables (without values).
# List all environments
envault list
# List specific environment
envault list -e prod
envault delete
Delete a variable.
envault delete OLD_API_KEY -e dev
envault export
Export variables in various formats.
# Export as .env file
envault export -e dev -f dotenv -o .env
# Export as shell statements
eval "$(envault export -e dev -f shell)"
# Export as Kubernetes Secret
envault export -e prod -f k8s-secret -o k8s-secret.yaml
# Export as Docker env-file
envault export -e dev -f docker -o docker.env
# Export as JSON
envault export -e dev -f json
# Export as YAML
envault export -e dev -f yaml
envault import
Import variables from a file.
# Import from .env file
envault import .env -e dev
# Import into specific environment
envault import legacy-config.env -e staging
envault diff
Compare two environments.
# Compare environments
envault diff dev prod
# Show masked values
envault diff dev prod --values
envault run
Run a command with injected environment variables.
# Run application with dev secrets
envault run -e dev -- python app.py
# Run with prod secrets
envault run -e prod -- node server.js
envault keygen
Generate a new encryption key.
envault keygen
# Output: base64-encoded 256-bit key
๐๏ธ Architecture
envault/
โโโ cli.py # Click-based CLI with Rich output
โโโ vault.py # Core vault engine (Vault, VaultEntry, Environment)
โโโ crypto.py # AES-256-GCM encryption with scrypt key derivation
โโโ access.py # Role-based access control (admin/editor/viewer)
โโโ history.py # Variable change history tracking
โโโ inheritance.py # Environment inheritance with layered resolution
โโโ template.py # Variable interpolation (${VAR:-default} syntax)
โโโ validator.py # Variable validation rules (URL, email, port, etc.)
โโโ expiry.py # TTL-based variable expiration
โโโ groups.py # Variable groups by prefix
โโโ diff.py # Environment comparison
โโโ display.py # Secure terminal display with masking
โโโ exporter.py # Multi-format export (dotenv/shell/docker/json/yaml/k8s)
โโโ importer.py # Import from .env, JSON, shell
โโโ backup.py # Timestamped backup and restore
โโโ snapshot.py # Point-in-time vault state snapshots
โโโ lock.py # File-based vault locking
โโโ migration.py # Vault file version migration
โโโ security.py # Secret strength auditing and gitignore generation
โโโ example.py # .env.example generation with smart placeholders
โโโ config.py # Project config (.envaultrc, pyproject.toml)
Data Flow
โโโโโโโโโโโโโโโโ
โ CLI (Click) โ
โโโโโโโโฌโโโโโโโโ
โ
โโโโโโโโโโโโโโผโโโโโโโโโโโโโ
โผ โผ โผ
โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ
โ set โ โ get โ โ export โ
โ import โ โ list โ โ run โ
โโโโโโฌโโโโโโ โโโโโโฌโโโโโโ โโโโโโฌโโโโโโ
โ โ โ
โผ โผ โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Vault Engine โ
โ (encrypt/decrypt/store) โ
โโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโผโโโโโโโโโโโโ
โผ โผ โผ
โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ
โ Crypto โ โ History โ โ Access โ
โ AES-256 โ โ Audit โ โ Control โ
โ scrypt โ โ Log โ โ RBAC โ
โโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโ
โ .envault.jsonโ
โ (encrypted) โ
โโโโโโโโโโโโโโโโ
Encryption Details
Password Mode:
password โโโถ scrypt(N=16384, r=8, p=1) โโโถ 256-bit key โโโถ AES-256-GCM
+ 32-byte random salt + 12-byte random nonce
Key Mode:
base64 key โโโถ decode โโโถ 256-bit key โโโถ AES-256-GCM
+ 12-byte random nonce
Each variable is independently encrypted with its own nonce, so identical values produce different ciphertexts.
๐ก API Reference
Vault Operations
from envault.vault import Vault
from envault.crypto import generate_key
# Create with password
vault = Vault(path="secrets.json", password="my-password")
# Create with key
key = generate_key()
vault = Vault(path="secrets.json", key=key)
# Set variables
vault.set("DB_URL", "postgres://...", "prod", description="Main DB", tags=["database"])
vault.bulk_set({"API_KEY": "sk-...", "SECRET": "val"}, "dev")
# Get variables
value = vault.get("DB_URL", "prod")
all_vars = vault.get_all("prod")
# Search and filter
results = vault.search("DB", environment="prod")
db_vars = vault.filter_by_tag("database", "prod")
# Environment management
vault.copy_environment("dev", "staging")
envs = vault.list_environments()
# Rotation
vault.rotate_password("new-password")
vault.rotate_key(generate_key())
# Save and load
vault.save()
vault.load()
Environment Inheritance
from envault.inheritance import InheritanceConfig, resolve_variables
config = InheritanceConfig()
config.set_parent("staging", "default")
config.set_parent("prod", "staging")
# Resolves: default -> staging -> prod (later overrides earlier)
resolved = resolve_variables(vault, "prod", config)
Variable Interpolation
from envault.template import interpolate
variables = {"DB_USER": "admin", "DB_PASS": "secret", "DB_HOST": "localhost"}
result = interpolate("postgres://${DB_USER}:${DB_PASS}@${DB_HOST}/mydb", variables)
# => "postgres://admin:secret@localhost/mydb"
Access Control
from envault.access import AccessControl, AccessEntry, Role, Permission
ac = AccessControl()
ac.add_entry(AccessEntry(identity="dev-team", role=Role.EDITOR, environments=["dev", "staging"]))
ac.add_entry(AccessEntry(identity="ops-team", role=Role.ADMIN))
ac.check_permission("dev-team", Permission.WRITE, environment="dev") # OK
ac.check_permission("dev-team", Permission.WRITE, environment="prod") # Raises AccessDeniedError
Validation
from envault.validator import ValidationSchema, ValidationRule, RuleType
schema = ValidationSchema()
schema.add_rule(ValidationRule(variable="DATABASE_URL", rule_type=RuleType.URL))
schema.add_rule(ValidationRule(variable="PORT", rule_type=RuleType.PORT))
schema.add_rule(ValidationRule(variable="EMAIL", rule_type=RuleType.EMAIL))
errors = schema.validate({"DATABASE_URL": "not-a-url", "PORT": "99999"})
Export Formats
from envault.exporter import export_to_format, ExportFormat, inject_to_process
# Export as dotenv
content = export_to_format(variables, ExportFormat.DOTENV)
# Export as Kubernetes Secret
content = export_to_format(variables, ExportFormat.K8S_SECRET, name="app-secrets")
# Run subprocess with injected vars
exit_code = inject_to_process(variables, ["python", "app.py"])
๐ง How It Works
- Initialization --
envault initcreates a.envault.jsonfile encrypted with your password or key - Encryption -- Each variable value is independently encrypted using AES-256-GCM with a unique nonce
- Key Derivation -- Passwords are run through scrypt (N=16384, r=8, p=1) with a random 32-byte salt
- Storage -- The vault file is a JSON document with encrypted payloads (ciphertext + nonce + salt)
- Atomic Writes -- Saves write to a temp file first, then atomically rename to prevent corruption
- Multi-Environment -- Variables are organized by environment name, each independently accessible
- Inheritance -- Child environments inherit from parents;
prodcan overridestagingwhich inheritsdefault - Export -- Decrypted variables are formatted into the target format (dotenv, shell, docker, k8s, etc.)
- Injection --
envault rundecrypts variables and passes them as environment to a subprocess
โ Troubleshooting
"Decryption failed: incorrect password or corrupted data"
- Verify you are using the same password/key that was used to create the vault
- If using environment variables, check
ENVAULT_KEYorENVAULT_PASSWORDis set correctly
Vault File in Git
The .envault.json file is safe to commit -- all values are encrypted. But add it to .gitignore if you prefer:
echo ".envault.json" >> .gitignore
Team Sharing
# Option 1: Password (share out of band)
envault init # Enter password
# Share password via secure channel
# Option 2: Key (share the key)
envault init --key
# Output: base64-key-here
# Share key via secure channel, set ENVAULT_KEY env var
Migration Between Password and Key
Currently, you need to export and re-import:
envault export -e dev -f json -o backup.json
envault init --key --path new-vault.json
envault import backup.json -e dev --path new-vault.json
๐งช Testing
# Install dev dependencies
pip install -e ".[dev]"
# Run all 698 tests
pytest tests/ -v
# Run with coverage
pytest tests/ --cov=envault --cov-report=term-missing
# Run specific module tests
pytest tests/test_vault.py -v
pytest tests/test_crypto.py -v
pytest tests/test_access.py -v
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file jsleekr_envault-0.1.0.tar.gz.
File metadata
- Download URL: jsleekr_envault-0.1.0.tar.gz
- Upload date:
- Size: 78.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
66b743a51d37315c4db72ac14714ea67886c611372be528e3aeebdde010e2d5e
|
|
| MD5 |
13707812b92fd0f1c180c6ab0cddb596
|
|
| BLAKE2b-256 |
0751929f876b9c47c766e0bdad6ffdc6e8d2176e2ff1c78571abcf97bf2029b1
|
File details
Details for the file jsleekr_envault-0.1.0-py3-none-any.whl.
File metadata
- Download URL: jsleekr_envault-0.1.0-py3-none-any.whl
- Upload date:
- Size: 49.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
53a0d081cb5352de49aa0d158a07a110504f51ae84bd8d4c6dd1e854321ca268
|
|
| MD5 |
8cbbd6571d37f274c98c032dc1ac155c
|
|
| BLAKE2b-256 |
50121ca91109ae92f928fe1771129ffbde967dd4c1746a052bf0ed26f83f4389
|