Encrypted Environment Loader
A secure Python package for managing encrypted environment variables. Load sensitive configuration from encrypted .env
files using Fernet encryption, with convenient keyring integration for local development.
Features
- Secure encryption using Fernet (AES 128 in CBC mode with HMAC-SHA256)
- Keyring integration for secure local key storage (macOS Keychain, Windows Credential Manager, Linux Secret Service)
- Profile support for multiple environments (dev, prod, test, etc.)
- CLI tools for file management and subprocess execution
- Python API with context managers and decorators
- Shell integration for fish, bash, and zsh
- Safe editing with backup and validation
- CI/CD friendly with quiet modes and secret masking
- Modern Python with type hints and proper packaging
Installation
pip install encrypted-env-loader
Quick Start
1. Initialize a new encrypted environment file
encrypted-env init
export ENCRYPTED_ENV_KEY='gAAAAABh...'
2. Edit your environment variables
encrypted-env edit
3. Run commands with encrypted environment
encrypted-env run -- python app.py
encrypted-env run -- ./deploy.sh
Or use shell integration
eval (encrypted-env load)
eval $(encrypted-env load)
Keyring Integration (New in v0.2.0)
For local development, store encryption keys securely in your system keyring instead of environment variables:
1. Store key in keyring
encrypted-env keyring set-key
encrypted-env keyring set-key --profile dev
encrypted-env keyring set-key --profile prod
2. Use encrypted environment with keyring
encrypted-env run --profile dev -- python app.py
encrypted-env load --profile dev
encrypted-env edit --profile dev
3. Production/CI usage
encrypted-env run --profile prod --no-keyring -- ./deploy.sh
export ENCRYPTED_ENV_KEY="your-key-here"
encrypted-env load --profile prod --no-keyring
4. Manage keyring keys
encrypted-env keyring list-keys
encrypted-env keyring get-key --profile dev
encrypted-env keyring delete-key --profile dev
Key Benefits:
- 🔐 Secure: Keys stored in OS-native keyring (never in plaintext)
- 🚀 Convenient: No need to manage environment variables locally
- 🔄 Flexible: Fallback to environment variables for production/CI
- 📋 Profile-aware: Separate keys per environment automatically
Security Features
CI/CD Safe Operations
All commands support --quiet
mode for CI environments and have secure defaults:
KEY=$(encrypted-env generate-key --quiet)
encrypted-env show --names-only
encrypted-env validate --quiet
Secret Masking
By default, commands mask sensitive values:
encrypted-env show
encrypted-env show --show-values
Examples and Testing
Run the comprehensive demo to see all features:
./examples/demo.sh
./examples/demo.sh --ci
./examples/basic_usage.sh
CLI Reference
Core Operations
run
- Execute commands with encrypted environment
encrypted-env run [--file FILE] [--profile PROFILE] [--no-keyring] -- <command>
encrypted-env run -- python app.py
encrypted-env run --profile prod -- ./deploy.sh
encrypted-env run --file .env.custom.encrypted -- npm start
encrypted-env run --profile dev --no-keyring -- python app.py
load
- Generate shell commands to load environment
encrypted-env load [--file FILE] [--profile PROFILE] [--shell SHELL] [--quiet] [--no-keyring]
eval (encrypted-env load)
eval (encrypted-env load --profile dev)
eval (encrypted-env load --profile prod --no-keyring)
eval $(encrypted-env load)
eval $(encrypted-env load --profile prod)
clear
- Generate shell commands to clear environment
encrypted-env clear [--file FILE] [--profile PROFILE] [--shell SHELL] [--quiet] [--no-keyring]
eval (encrypted-env clear)
eval $(encrypted-env clear)
File Management
init
- Create new encrypted environment file
encrypted-env init [--file FILE] [--profile PROFILE] [--key-file KEYFILE] [--quiet]
encrypted-env init
encrypted-env init --profile dev
encrypted-env init --key-file .env.key
encrypted-env init --quiet
encrypt
- Encrypt existing .env file
encrypted-env encrypt <source> [--output OUTPUT] [--profile PROFILE] [--quiet]
encrypted-env encrypt .env
encrypted-env encrypt .env.dev --profile dev
encrypted-env encrypt .env --output custom.encrypted
decrypt
- Decrypt to filesystem
encrypted-env decrypt [--file FILE] [--output OUTPUT] [--profile PROFILE] [--quiet]
encrypted-env decrypt
encrypted-env decrypt --profile dev
encrypted-env decrypt --output .env.backup
edit
- Safely edit encrypted files
encrypted-env edit [--file FILE] [--profile PROFILE] [--quiet]
encrypted-env edit --profile prod
Key Management
generate-key
- Generate new encryption key
encrypted-env generate-key [--quiet]
encrypted-env generate-key
encrypted-env generate-key --quiet
rekey
- Change encryption key
encrypted-env rekey [--file FILE] [--profile PROFILE] [--old-key-env VAR] [--new-key-env VAR] [--quiet]
ENCRYPTED_ENV_KEY="old_key" NEW_KEY="new_key" encrypted-env rekey --new-key-env NEW_KEY
encrypted-env rekey --quiet
Keyring Management (New in v0.2.0)
keyring set-key
- Store encryption key in system keyring
encrypted-env keyring set-key [--profile PROFILE] [--key KEY] [--quiet]
encrypted-env keyring set-key
encrypted-env keyring set-key --profile dev
encrypted-env keyring set-key --key "ABC123"
encrypted-env keyring set-key --quiet
keyring get-key
- Retrieve encryption key from keyring
encrypted-env keyring get-key [--profile PROFILE] [--quiet]
encrypted-env keyring get-key
encrypted-env keyring get-key --profile dev
encrypted-env keyring get-key --quiet
keyring delete-key
- Remove encryption key from keyring
encrypted-env keyring delete-key [--profile PROFILE] [--quiet]
encrypted-env keyring delete-key
encrypted-env keyring delete-key --profile dev
encrypted-env keyring delete-key --quiet
keyring list-keys
- List all profiles with stored keys
encrypted-env keyring list-keys [--quiet]
encrypted-env keyring list-keys --quiet
Keyring Key Storage:
- Service name: Git repository name (e.g.,
encrypted-env-loader
)
- Username format:
{profile}-key
(e.g., dev-key
, default-key
)
- Automatic detection: Git repo name used for consistent keyring service naming
Utilities
status
- Show file information and variables
encrypted-env status [--file FILE] [--profile PROFILE] [--no-keyring]
validate
- Check if file can be decrypted
encrypted-env validate [--file FILE] [--profile PROFILE] [--quiet] [--no-keyring]
show
- Display variables (with security options)
encrypted-env show [--file FILE] [--profile PROFILE] [--names-only] [--show-values] [--no-keyring]
encrypted-env show
encrypted-env show --names-only
encrypted-env show --show-values
Python API
Basic Usage
from encrypted_env_loader import load_encrypted_env
env_vars = load_encrypted_env()
env_vars = load_encrypted_env(
key="base64-encoded-key",
file_path=".env.prod.encrypted",
profile="prod",
change_os_env=True,
use_keyring=True
)
env_vars = load_encrypted_env(
profile="prod",
use_keyring=False
)
Context Manager
from encrypted_env_loader import encrypted_env_context
import os
with encrypted_env_context(profile="dev"):
database_url = os.getenv("DATABASE_URL")
secret_key = os.getenv("SECRET_KEY")
with encrypted_env_context(profile="prod", use_keyring=False):
pass
Decorator
from encrypted_env_loader import with_encrypted_env
import os
@with_encrypted_env(profile="prod")
def deploy_application():
api_key = os.getenv("API_KEY")
database_url = os.getenv("DATABASE_URL")
@with_encrypted_env(profile="prod", use_keyring=False)
def ci_deploy():
pass
deploy_application()
Keyring Functions (New in v0.2.0)
from encrypted_env_loader import (
get_key_from_keyring,
set_key_in_keyring,
delete_key_from_keyring,
list_keyring_profiles,
get_git_repo_name
)
repo_name = get_git_repo_name()
success = set_key_in_keyring("my-secret-key", profile="dev")
key = get_key_from_keyring(profile="dev")
profiles = list_keyring_profiles()
success = delete_key_from_keyring(profile="dev")
Utility Functions
from encrypted_env_loader import (
generate_key,
encrypt_env_file,
decrypt_env_file,
validate_encrypted_file
)
key = generate_key()
encrypt_env_file(".env", ".env.encrypted", key)
encrypt_env_file(".env", ".env.encrypted", profile="dev")
encrypt_env_file(".env", ".env.encrypted", profile="dev", use_keyring=False)
env_vars = decrypt_env_file(".env.encrypted", key=key)
env_vars = decrypt_env_file(".env.encrypted", profile="dev")
env_vars = decrypt_env_file(".env.encrypted", profile="dev", use_keyring=False)
is_valid = validate_encrypted_file(".env.encrypted", key=key)
is_valid = validate_encrypted_file(".env.encrypted", profile="dev")
is_valid = validate_encrypted_file(".env.encrypted", profile="dev", use_keyring=False)
Profiles
Profiles allow managing multiple environment configurations:
.env.encrypted
.env.dev.encrypted
.env.prod.encrypted
.env.test.encrypted
encrypted-env init --profile dev
encrypted-env run --profile prod -- python app.py
encrypted-env edit --profile test
Shell Integration
Fish Shell
# Load environment
eval (encrypted-env load --profile dev)
# Clear environment
eval (encrypted-env clear --profile dev)
# One-liner with auto-clear
encrypted-env run --profile dev -- python app.py
Bash/Zsh
eval $(encrypted-env load --profile dev)
eval $(encrypted-env clear --profile dev)
eval $(encrypted-env load)
for i in {1..100}; do
curl -H "Authorization: $SECRET_TOKEN" api.example.com/data/$i
done
eval $(encrypted-env clear)
CI/CD Integration
GitHub Actions Example
- name: Setup encrypted environment
run: |
# Generate or retrieve key securely
echo "${{ secrets.ENCRYPTED_ENV_KEY }}" > .env.key
export ENCRYPTED_ENV_KEY=$(cat .env.key)
encrypted-env validate --quiet
encrypted-env run -- pytest
Security Best Practices
encrypted-env show --names-only
encrypted-env validate --quiet
encrypted-env generate-key --quiet
encrypted-env show --show-values
encrypted-env status
Security Considerations
- Key Storage: Never commit encryption keys to version control
- Key Rotation: Regularly rotate encryption keys using
rekey
command
- File Permissions: Ensure encrypted files have appropriate permissions
- Backup Strategy: Keep secure backups of both encrypted files and keys
- Environment Isolation: Use profiles to separate dev/staging/prod secrets
- CI/CD Safety: Use
--quiet
and --names-only
flags in automated environments
Error Handling
The package provides specific exception types:
from encrypted_env_loader import EncryptedEnvError, DecryptionError, KeyError
try:
load_encrypted_env()
except KeyError:
print("Encryption key missing or invalid")
except DecryptionError:
print("File cannot be decrypted - wrong key or corrupted data")
except EncryptedEnvError:
print("General error with encrypted environment operations")
Development
Setup
git clone https://github.com/igutekunst/encrypted-env-loader
cd encrypted-env-loader
pip install -e ".[dev]"
Testing
pytest
./examples/demo.sh
./examples/demo.sh --ci
pytest --cov=encrypted_env_loader
Code Quality
black src tests
isort src tests
flake8 src tests
mypy src
License
MIT License - see LICENSE file.
Contributing
- Fork the repository
- Create a feature branch
- Add tests for new functionality
- Ensure all tests pass
- Submit a pull request
Changelog
0.2.0
- Keyring integration for secure local key storage
- Automatic git repo detection for keyring service naming
- Key resolution priority: explicit key → keyring → environment variable
- New CLI command group:
keyring
with set-key
, get-key
, delete-key
, list-keys
- Enhanced commands: All file operations support
--no-keyring
flag
- Improved status reporting: Shows key source (keyring vs environment variable)
- Python API extensions: All functions support
use_keyring
parameter
- Production/CI compatibility: Graceful fallback to environment variables
0.1.0
- Initial release
- Basic encryption/decryption functionality
- CLI with all core commands
- Python API with context managers and decorators
- Profile support
- Shell integration
- CI/CD safety features with quiet modes and secret masking