Safe Environment Variable Loader
Project description
EnvGuard
Secure environment variable management for Python applications.
EnvGuard provides a robust, type-safe way to handle environment variables with built-in security features including encryption, tamper detection, override protection, and secret manager integration.
Features
- Type Safety: Automatic type validation and conversion
- Override Protection: Prevents silent overrides of system environment variables
- Built-in Encryption: Encrypt sensitive
.envfiles with Fernet (AES-128) - Tamper Detection: SHA-256 hash verification to detect file modifications
- Secret Masking: Automatically masks sensitive keys in status reports
- Scoped Access: Restrict variable access to specific code sections
- Environment Locking: Prevent running wrong environment configurations
- Multi-Environment Support: Load environment-specific files (
.env.production,.env.development) - Variable Interpolation: Reference variables with
${VAR}syntax - Template Validation: Validate against template files with optional defaults
- Secret Manager Integration: AWS Secrets Manager and HashiCorp Vault support
- Pydantic Integration: Seamless integration with Pydantic models
- Zero External Dependencies: Core functionality works without Pydantic
Installation
pip install envguard
Optional dependencies:
# For Pydantic support
pip install envguard[pydantic]
# For AWS Secrets Manager
pip install envguard[aws]
# For HashiCorp Vault
pip install envguard[vault]
# For all secret managers
pip install envguard[secrets]
Quick Start
Basic Usage
from envguard import load
# Load environment variables from .env file
env = load(path=".env", schema={
"DATABASE_URL": str,
"API_KEY": str,
"DEBUG": bool,
"PORT": int
})
print(env.DATABASE_URL)
print(env.PORT)
Class-Based Configuration (Recommended)
from envguard import BaseSettings, guard
class Config(BaseSettings):
database_host: str
database_port: int
api_key: str
debug: bool = False
max_connections: int = 100
# Load and validate configuration
config = guard(Config, verbose=False)
# Use your configuration
print(config.database_host)
print(config.database_port)
Without Pydantic (Lightweight)
from envguard import BaseConfig
class Config(BaseConfig):
DATABASE_URL: str
API_KEY: str
DEBUG: bool
PORT: int
config = Config.load()
print(config.DATABASE_URL)
Core Features
Multi-Environment File Support
Load environment-specific files automatically based on your deployment environment:
from envguard import load
# Automatically loads .env.production if it exists
# Falls back to .env if not found
env = load(
path=".env",
environment="production",
fallback=".env",
schema={"API_KEY": str, "DATABASE_URL": str}
)
# File structure:
# .env (base/default)
# .env.production (production overrides)
# .env.development (development overrides)
# .env.staging (staging overrides)
Use case: Different configurations for development, staging, and production without code changes.
Variable Interpolation
Reference other variables within your environment files:
from envguard import load
# .env file:
# BASE_URL=https://api.example.com
# API_URL=${BASE_URL}/v1
# VERSION=2.0
# FULL_URL=${API_URL}?version=${VERSION}
env = load(path=".env")
print(env.FULL_URL) # https://api.example.com/v1?version=2.0
Supported syntax:
${VAR}- Reference another variable${VAR:-default}- Use default value if variable not found- Variables are resolved from: file variables → system environment → default
Example with defaults:
# .env
DATABASE_HOST=${DB_HOST:-localhost}
DATABASE_PORT=${DB_PORT:-5432}
DATABASE_URL=postgresql://${DATABASE_HOST}:${DATABASE_PORT}/mydb
Use case: Build complex URLs and connection strings from simpler components.
Environment Variable Templates
Use template files to document and validate required variables:
from envguard import load
# .env.template file:
# DATABASE_URL=postgresql://localhost/dbname
# API_KEY=your-api-key-here
# DEBUG=false
# .env file (your actual values)
# DATABASE_URL=postgresql://prod/db
# API_KEY=secret-key-123
# Validate against template
env = load(path=".env", template=".env.template")
# Raises error if variables from template are missing
# Or use template defaults for missing variables
env = load(
path=".env",
template=".env.template",
use_template_defaults=True
)
Benefits:
- Document required variables for your team
- Validate configuration completeness
- Provide sensible defaults for development
- Onboard new developers faster
Encrypted Environment Files
Encrypt your .env file for secure storage in version control:
# Encrypt .env file
envguard encrypt .env
# The key will be displayed - save it securely!
# Set it as an environment variable:
export SAFEENV_KEY="your-encryption-key-here"
Load encrypted files in your application:
from envguard import load
# Automatically decrypts using SAFEENV_KEY environment variable
env = load(path=".env.enc", encrypted=True, schema={"API_KEY": str})
# Works with multi-environment support too
env = load(
path=".env",
environment="production",
encrypted=True,
schema={"API_KEY": str}
)
# Loads .env.production.enc
Use case: Store encrypted secrets in Git repositories safely.
Secret Manager Integration
Load secrets directly from cloud secret managers without storing them in files.
AWS Secrets Manager
from envguard import load_with_secrets
# Load from AWS Secrets Manager
env = load_with_secrets(
provider="aws",
secret_name="prod/database",
region="us-east-1",
schema={"DATABASE_URL": str, "API_KEY": str}
)
print(env.DATABASE_URL)
Installation:
pip install envguard[aws]
# or
pip install boto3
AWS Credentials: Uses standard AWS credential chain (environment variables, IAM roles, etc.)
HashiCorp Vault
from envguard import load_with_secrets
# Load from HashiCorp Vault
env = load_with_secrets(
provider="vault",
secret_path="secret/data/app",
vault_url="https://vault.example.com",
vault_token="your-token",
schema={"DATABASE_URL": str, "API_KEY": str}
)
Installation:
pip install envguard[vault]
# or
pip install hvac
Environment Variables:
VAULT_ADDR- Vault server URL (alternative tovault_url)VAULT_TOKEN- Vault authentication token (alternative tovault_token)AWS_DEFAULT_REGION- AWS region (alternative toregionparameter)
Use case: Production deployments where secrets are managed centrally.
Scoped Access Control
Restrict access to sensitive variables to specific code sections:
from envguard import load
env = load(path=".env", scoped=True, schema={"SECRET_KEY": str})
# This will raise AccessError
# secret = env.SECRET_KEY
# Access only within scope
with env.scope():
secret = env.SECRET_KEY
# Use secret here
process_secret(secret)
# Outside scope, access is denied again
Use case: Prevent accidental exposure of sensitive variables in logs or error messages.
Environment Locking
Prevent accidental use of wrong environment configuration:
from envguard import load
env = load(path=".env", schema={"APP_ENV": str})
env.lock("production") # Raises error if APP_ENV != "production"
Use case: Ensure production code never runs with development configuration.
Tamper Detection
Verify file integrity to detect unauthorized modifications:
from envguard import load
env = load(path=".env", schema={"API_KEY": str})
# Later, verify file hasn't been modified
env.verify() # Raises TamperError if file was changed
Use case: Security audits and compliance requirements.
Status Report
View security status and configuration summary:
from envguard import guard, BaseSettings
class Config(BaseSettings):
api_key: str
database_url: str
config = guard(Config, verbose=True)
# Prints security report with masked secrets:
# EnvGuard Security Report
# ----------------------------------------
# Source: .env
# Items Protected: 2
# - api_key: ********
# - database_url: postgresql://...
# Tamper Protection: Active
# ----------------------------------------
Command Line Interface
Encrypt a File
# Generate new key and encrypt
envguard encrypt .env
# Use existing key
envguard encrypt .env --key YOUR_KEY
# Keep original file
envguard encrypt .env --keep
Decrypt a File
# Decrypt using environment variable
export SAFEENV_KEY="your-key"
envguard decrypt .env.enc
# Or provide key directly
envguard decrypt .env.enc --key YOUR_KEY
Complete Examples
Production-Ready Configuration
from envguard import BaseSettings, guard
import os
class ProductionConfig(BaseSettings):
database_url: str
redis_url: str
api_key: str
secret_key: str
debug: bool = False
log_level: str = "INFO"
# Load based on environment
env_name = os.getenv("APP_ENV", "development")
config = guard(
ProductionConfig,
_environment=env_name,
_template=".env.template",
verbose=False
)
# Lock to production if in production
if env_name == "production":
config._env_guard.lock("production")
Using Secret Managers in Production
from envguard import load_with_secrets
# Production: Use AWS Secrets Manager
if os.getenv("ENVIRONMENT") == "production":
env = load_with_secrets(
provider="aws",
secret_name="prod/app-secrets",
region="us-east-1",
schema={
"DATABASE_URL": str,
"REDIS_URL": str,
"API_KEY": str,
}
)
else:
# Development: Use local .env file
from envguard import load
env = load(path=".env", schema={
"DATABASE_URL": str,
"REDIS_URL": str,
"API_KEY": str,
})
Complex Variable Interpolation
from envguard import load
# .env file:
# PROTOCOL=https
# DOMAIN=api.example.com
# VERSION=v1
# BASE_URL=${PROTOCOL}://${DOMAIN}
# API_URL=${BASE_URL}/${VERSION}
# TIMEOUT=30
# FULL_URL=${API_URL}?timeout=${TIMEOUT}
env = load(path=".env")
print(env.FULL_URL)
# https://api.example.com/v1?timeout=30
Custom Validators
from envguard import load
def validate_url(value: str) -> str:
if not value.startswith(("http://", "https://")):
raise ValueError("Invalid URL format")
return value
def validate_port(value: str) -> int:
port = int(value)
if not (1024 <= port <= 65535):
raise ValueError("Port must be between 1024 and 65535")
return port
env = load(
path=".env",
schema={
"API_URL": validate_url,
"PORT": validate_port,
"TIMEOUT": int,
}
)
API Reference
load(path, schema, encrypted, scoped, environment, fallback, template, use_template_defaults)
Load environment variables from a file.
Parameters:
path(str): Path to environment file (default:.env)schema(dict | type): Validation schema or classencrypted(bool): Whether file is encrypted (default:False)scoped(bool): Enable scoped access (default:False)environment(str, optional): Environment name for multi-environment support. Loadspath.environment(e.g.,.env.production)fallback(str, optional): Fallback path if environment file not found. Defaults topathif not specifiedtemplate(str, optional): Path to template file for validationuse_template_defaults(bool): Use template values as defaults (default:False)
Returns: Env object
load_with_secrets(provider, schema, secret_name, secret_path, region, vault_url, vault_token, scoped)
Load environment variables from a secret manager.
Parameters:
provider(str): Secret manager provider ("aws" or "vault")schema(dict | type, optional): Validation schema or classsecret_name(str, optional): AWS Secrets Manager secret namesecret_path(str, optional): Vault secret pathregion(str, optional): AWS regionvault_url(str, optional): Vault server URLvault_token(str, optional): Vault authentication tokenscoped(bool): Enable scoped access (default:False)
Returns: Env object
guard(schema, verbose, **kwargs)
Primary entry point for creating secured environment.
Parameters:
schema: Optional schema or class for validationverbose(bool): Print security status report (default:True)**kwargs: Arguments passed toload()(path, encrypted, scoped, environment, fallback, template, use_template_defaults)
Returns: Env object or Pydantic model instance
BaseSettings
Pydantic-based settings class with automatic environment loading.
BaseConfig
Lightweight base class without Pydantic dependency.
Error Handling
from envguard import (
load,
SafeEnvError,
MissingEnvError,
ValidationError,
AccessError,
TamperError,
EnvironmentLockError,
)
try:
env = load(path=".env", schema={"API_KEY": str})
except MissingEnvError as e:
print(f"Required variable missing: {e}")
except ValidationError as e:
print(f"Validation failed: {e}")
except TamperError as e:
print(f"File tampering detected: {e}")
except SafeEnvError as e:
print(f"Configuration error: {e}")
Comparison
| Feature | python-dotenv | pydantic-settings | EnvGuard |
|---|---|---|---|
| Type Safety | No | Yes | Yes |
| Override Protection | No | No | Yes |
| Built-in Encryption | No | No | Yes |
| Tamper Detection | No | No | Yes |
| Secret Masking | No | No | Yes |
| Scoped Access | No | No | Yes |
| Environment Locking | No | No | Yes |
| Multi-Environment Files | No | No | Yes |
| Variable Interpolation | No | No | Yes |
| Template Validation | No | No | Yes |
| Secret Manager Integration | No | No | Yes |
| Zero Dependencies | Yes | No | Yes* |
*Core functionality works without Pydantic
Security Best Practices
- Never commit plain text
.envfiles - Use encryption or secret managers - Store encryption keys securely - Use secret management systems or environment variables
- Enable scoped access - For highly sensitive variables
- Use environment locking - In production deployments
- Verify file integrity - Periodically check for tampering
- Use templates - Document required variables and validate configurations
- Use secret managers in production - Avoid storing secrets in files
- Mask secrets in logs - EnvGuard does this automatically in status reports
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT License - see LICENSE file for details.
EnvGuard - Bulletproof environment management for professional Python applications.
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 envgd-0.1.2.tar.gz.
File metadata
- Download URL: envgd-0.1.2.tar.gz
- Upload date:
- Size: 128.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d8245e2cefdf40c50f835abb9cd4bb4f61d9270e88405f0da7db135659369408
|
|
| MD5 |
7f79a7fcc04f23f1358a381d6ea493d7
|
|
| BLAKE2b-256 |
aa9820da2ba07c52cf8947686598bb0e3b812caba9db94455f27c72cada0f4cf
|
File details
Details for the file envgd-0.1.2-py3-none-any.whl.
File metadata
- Download URL: envgd-0.1.2-py3-none-any.whl
- Upload date:
- Size: 19.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b258e85de8b0e2250cf7d882295efd93b9ad38b714fce94a10a70ccb13bab3eb
|
|
| MD5 |
03fe3aad6f54d5f465d920ffdf8d8db7
|
|
| BLAKE2b-256 |
7774d8eac0f622435c371137125138847927e8e81436a193c872ae8d65965521
|