secenv
Secure Environment Variable Management with PGP Encryption
secenv is a command-line tool for managing environment variables with PGP encryption support. It allows you to store sensitive configuration values encrypted in YAML files and decrypt them on-demand using your system's GPG keys.
Features
- 🔐 PGP Encryption: Encrypt sensitive values using OpenPGP/GPG
- 📁 Profile-Based Configuration: Organize variables into different profiles (dev, staging, prod, etc.)
- 🔑 System GPG Integration: Uses your existing GPG keys and agent
- 🛡️ Password Protection: Supports password-protected PGP keys with secure prompting
- 📄 Multiple Value Types: Literal values, environment variables, files, and encrypted values
- ⚡ Fast & Lightweight: Written in Rust for performance and safety
Installation
From Source
The binary will be available at target/release/secenv.
Quick Start
1. Create a Configuration File
Create a secenv.yaml file with your environment variables:
# Define reusable anchors
.defaultkey: "PGP-KEY-FINGERPRINT"
profiles:
dev:
propagate: true
vars:
# Literal value
APP_NAME: "myapp"
# Environment variable reference
HOME_DIR: "HOME"
# File content
CONFIG_JSON_CONTENT: "/etc/myapp/config.json"
# PGP encrypted value
DATABASE_PASSWORD:
key: *defaultkey
value: |
-----BEGIN PGP MESSAGE-----
...
-----END PGP MESSAGE-----
production:
propagate: false
vars:
APP_NAME: "myapp"
DATABASE_PASSWORD:
key: "PROD_KEY_FINGERPRINT"
value: |
-----BEGIN PGP MESSAGE-----
...
-----END PGP MESSAGE-----
2. Encrypt Values
To create encrypted values, use GPG to encrypt your secrets:
# Encrypt a value for a specific key
|
# Or encrypt for a specific key fingerprint
|
Copy the resulting PGP message (including the -----BEGIN PGP MESSAGE----- and -----END PGP MESSAGE----- lines) into your YAML file.
3. Unlock Variables
# Unlock variables from the default profile
# Unlock variables from a specific profile
# Use a different config file
Output format:
APP_NAME=MyApp
DATABASE_PASSWORD=my-secret-password
HOME_DIR=/Users/username
Configuration Format
Profile Structure
profiles:
<profile-name>:
propagate: <boolean> # Whether to propagate to child processes
vars:
<variable-name>: <value-provider>
Value Providers
Literal Values
APP_NAME: "MyApplication"
Environment Variables
HOME_DIR: "HOME"
USER_NAME: "USER"
File Contents
CONFIG_DATA: "/etc/myapp/config.json"
CERTIFICATE: "/etc/ssl/certs/app.crt"
PGP Encrypted Values
SECRET_KEY:
key: "9CD9D9187E17BE27E2F838B7BA59BCD337CEEA1D" # PGP key fingerprint
value: |
-----BEGIN PGP MESSAGE-----
hQIMA/nYRg4ylYK0AQ/+K25a1jwIORvRnutLSR4vBuWA1mC8GHDrWRW3k7btX8DD
...
-----END PGP MESSAGE-----
YAML Anchors and References
Use YAML anchors to avoid repeating key fingerprints:
.defaultkey: "9CD9D9187E17BE27E2F838B7BA59BCD337CEEA1D"
.prodkey: "ABCD1234567890ABCD1234567890ABCD12345678"
profiles:
default:
vars:
SECRET1:
key: *defaultkey
value: "..."
SECRET2:
key: *defaultkey
value: "..."
production:
vars:
SECRET1:
key: *prodkey
value: "..."
Usage
Commands
unlock
Decrypt and display environment variables from a profile.
man
Generate manual pages.
|
autocomplete
Generate shell completion scripts.
||||
Integration Examples
Shell Integration
# Load variables into current shell
# Export to a file
Docker Integration
# In your Dockerfile
COPY secenv.yaml /app/
RUN secenv unlock --profile production > /app/.env
CI/CD Integration
# GitHub Actions example
- name: Load secrets
run: |
secenv unlock --profile ci > $GITHUB_ENV
Security Considerations
PGP Key Management
- Key Storage: Store your PGP private keys securely using your system's keychain or GPG agent
- Key Rotation: Regularly rotate encryption keys and re-encrypt values
- Access Control: Use different PGP keys for different environments (dev, staging, prod)
Best Practices
- Never commit unencrypted secrets to version control
- Use different keys per environment to limit blast radius
- Regularly audit who has access to decryption keys
- Use strong passphrases for PGP keys
- Enable GPG agent for convenient key management
- Backup your keys securely
Password-Protected Keys
When using password-protected PGP keys, secenv will:
- Attempt decryption without a password first
- If that fails, prompt securely for the password
- Allow up to 3 retry attempts
- Integrate with GPG agent for cached passwords
GPG Setup
Generate a New Key
# Generate a new GPG key
# List your keys
# Export public key (for sharing)
Import Existing Keys
# Import a private key
# Import a public key
# Trust a key
# In GPG prompt: trust -> 5 -> y -> quit
Troubleshooting
Common Issues
"GPG decryption failed"
- Ensure the correct PGP key is installed:
gpg --list-secret-keys - Verify the key fingerprint matches the one in your config
- Check if the key requires a password and GPG agent is running
"Profile not found"
- Verify the profile name exists in your config file
- Check YAML syntax with
yamllint secenv.yaml
"Failed to read config"
- Ensure the config file exists and is readable
- Verify YAML syntax is correct
- Check file permissions
Debug Mode
For verbose output, set the RUST_LOG environment variable:
RUST_LOG=debug
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
Development Setup
Running Tests
# Run all tests
# Run with output
# Run specific test
License
This project is licensed under the MIT License - see the LICENSE file for details.
Changelog
v0.0.0 (Current)
- Initial implementation
- PGP encryption support
- Profile-based configuration
- Multiple value providers (literal, environment, file, pgp)
- GPG integration with password support
- Shell completion and manual generation