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:

  1. Decrypts to a temporary file
  2. Opens in $EDITOR
  3. 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

  1. Never commit the master key - Store it in a password manager or CI secrets
  2. Use different keys per environment - Separate keys for staging vs production
  3. 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.

Previous
Zero-downtime deploys