Features
Secrets management
Securely manage sensitive configuration with encrypted secrets.
Overview
Odysseus provides encrypted secrets management using AES-256-GCM encryption. Secrets are stored in an encrypted file that can be safely committed to version control.
Quick start
1. Generate a master key
odysseus secrets generate-key
Output:
Generated master key:
a1b2c3d4e5f6789012345678901234567890123456789012345678901234abcd
Store this key securely. You will need it to encrypt/decrypt secrets.
Set it as ODYSSEUS_MASTER_KEY environment variable.
Store this key securely (password manager, CI secrets, etc.).
2. Create secrets file
Create a plain YAML file with your secrets:
# secrets.yml
DATABASE_URL: postgres://user:password@localhost/myapp
RAILS_MASTER_KEY: abc123def456ghi789
REDIS_URL: redis://localhost:6379
AWS_ACCESS_KEY_ID: AKIA...
AWS_SECRET_ACCESS_KEY: secret...
3. Encrypt the file
ODYSSEUS_MASTER_KEY=your-key odysseus secrets encrypt \
--input secrets.yml \
--file secrets.yml.enc
4. Clean up and commit
rm secrets.yml
git add secrets.yml.enc
git commit -m "Add encrypted secrets"
5. Configure deployment
Reference the encrypted file in your deploy.yml:
env:
secret:
- DATABASE_URL
- RAILS_MASTER_KEY
- REDIS_URL
secrets_file: secrets.yml.enc
Using secrets
Environment variable
Set the master key before running commands:
export ODYSSEUS_MASTER_KEY=your-key
odysseus deploy --image v1.0.0
Inline
Pass the key directly:
ODYSSEUS_MASTER_KEY=your-key odysseus deploy --image v1.0.0
CI/CD
Store the master key in your CI system's secrets:
# GitHub Actions
- run: odysseus deploy --image ${{ github.sha }}
env:
ODYSSEUS_MASTER_KEY: ${{ secrets.ODYSSEUS_MASTER_KEY }}
CLI commands
generate-key
Generate a new master key:
odysseus secrets generate-key
encrypt
Encrypt a plaintext file:
odysseus secrets encrypt --input secrets.yml --file secrets.yml.enc
Options:
--input FILE: Source plaintext file--file FILE: Output encrypted file
decrypt
Decrypt to view contents:
odysseus secrets decrypt --file secrets.yml.enc
Output is printed to stdout. To save to a file:
odysseus secrets decrypt --file secrets.yml.enc > secrets.yml
edit
Edit secrets in your default editor:
odysseus secrets edit --file secrets.yml.enc
This:
- Decrypts to a temporary file
- Opens in
$EDITOR - Re-encrypts when you save and close
Editor
Set your preferred editor with export EDITOR=vim or export EDITOR=code --wait.
Encryption details
Algorithm
Odysseus uses AES-256-GCM (Galois/Counter Mode):
- 256-bit key
- Authenticated encryption
- Unique IV for each encryption
Key format
The master key is a 64-character hex string (32 bytes).
File format
Encrypted files contain:
- IV (initialization vector)
- Auth tag (for verification)
- Encrypted data
All base64-encoded for safe storage.
Best practices
Key management
- Never commit the master key - Store it in a password manager or CI secrets
- Use different keys per environment - Separate keys for staging vs production
- Rotate keys periodically - Re-encrypt with new keys as needed
Secret organization
Keep secrets organized:
# secrets.yml
# Database
DATABASE_URL: postgres://...
DATABASE_POOL: "10"
# Cache
REDIS_URL: redis://...
# External services
STRIPE_SECRET_KEY: sk_live_...
SENDGRID_API_KEY: SG....
# Application
RAILS_MASTER_KEY: abc123...
SECRET_KEY_BASE: def456...
Multiple environments
Use separate files per environment:
# Production
odysseus secrets encrypt --input prod-secrets.yml --file secrets.prod.yml.enc
# Staging
odysseus secrets encrypt --input staging-secrets.yml --file secrets.staging.yml.enc
Reference in config:
# deploy.prod.yml
secrets_file: secrets.prod.yml.enc
# deploy.staging.yml
secrets_file: secrets.staging.yml.enc
Troubleshooting
"Master key not set"
Error: ODYSSEUS_MASTER_KEY environment variable not set
Set the key:
export ODYSSEUS_MASTER_KEY=your-key
"Invalid key"
Error: Failed to decrypt secrets file
Check that you're using the correct key for this file. Keys are specific to the encryption.
"Secret not found"
Warning: Secret 'MY_VAR' not found in secrets file
The variable listed in env.secret doesn't exist in your encrypted file. Add it:
odysseus secrets edit --file secrets.yml.enc
# Add MY_VAR: value
Fallback behavior
If a secret isn't found in the encrypted file, Odysseus falls back to the server's environment:
env:
secret:
- DATABASE_URL # From secrets file
- CUSTOM_VAR # Not in file, uses server env
This allows hybrid configurations where some secrets come from the encrypted file and others from the server environment.