Using Pass for Secrets
Set up the Unix password manager (pass) as Gordon's secrets backend for secure credential storage.
What You'll Learn
- Installing and initializing pass
- Storing Gordon secrets securely
- Configuring Gordon to use pass
- Team workflows with shared GPG keys
- Troubleshooting common issues
Prerequisites
- Linux or macOS system
- GPG installed
- Basic understanding of GPG keys
Why Pass?
Pass is a simple, Unix-philosophy password manager that:
- Stores secrets as GPG-encrypted files
- Integrates with Git for version control
- Works with standard Unix tools
- Supports multiple GPG keys for team access
Installation
Ubuntu/Debian
sudo apt install pass gnupg
macOS
brew install pass gnupg
Arch Linux
sudo pacman -S pass gnupg
Initial Setup
1. Generate a GPG Key (if needed)
# Generate a new GPG key
gpg --gen-key
# Follow prompts:
# - Real name: Gordon Server
# - Email: [email protected]
# - Passphrase: (use a strong passphrase or leave empty for automation)
List your keys to find the key ID:
gpg --list-keys
Output:
pub ed25519 2024-01-15 [SC]
ABC123DEF456... <-- This is your key ID
uid [ultimate] Gordon Server <[email protected]>
2. Initialize Pass Store
pass init ABC123DEF456... # Use your GPG key ID
This creates ~/.password-store/.
3. Create Gordon Secrets
# Registry password hash (bcrypt)
# Generate with: htpasswd -nbB admin yourpassword | cut -d: -f2
pass insert gordon/auth/password_hash
# Token secret (random 32+ chars for JWT signing)
pass generate gordon/auth/token_secret 32
Gordon Configuration
Enable Pass Backend
[auth]
enabled = true
secrets_backend = "pass"
token_secret = "gordon/auth/token_secret"
# Optional: enable password auth for interactive login
# username = "admin"
# password_hash = "gordon/auth/password_hash"
Using Route Secrets
With the pass backend, per-domain secrets are stored in pass, not .env files.
# Store secrets for a domain
gordon secrets set app.mydomain.com DATABASE_URL "postgresql://user:pass@postgres:5432/app"
gordon secrets set app.mydomain.com API_KEY "your-api-key"
Gordon migrates existing .env files on startup and renames them to .env.migrated.
Organizing Secrets
Recommended directory structure in pass:
~/.password-store/
├── gordon/
│ └── auth/
│ ├── password_hash.gpg
│ └── token_secret.gpg
├── myapp/
│ ├── db/
│ │ └── password.gpg
│ ├── api/
│ │ └── key.gpg
│ └── jwt/
│ └── secret.gpg
└── production/
└── stripe/
└── secret_key.gpg
Team Workflows
Multiple GPG Keys
Allow multiple team members to decrypt secrets:
# Initialize with multiple keys
pass init KEY_ID_1 KEY_ID_2 KEY_ID_3
# Or add keys later
pass init --path=gordon KEY_ID_1 KEY_ID_2
Git Integration
Version control your encrypted secrets:
# Initialize git in pass store
pass git init
# Add remote
pass git remote add origin [email protected]:yourorg/secrets.git
# Commit and push
pass git push -u origin main
Pull Secrets on New Server
# Clone the pass store
git clone [email protected]:yourorg/secrets.git ~/.password-store
# Import team GPG keys
gpg --import team-member.pub
Automation (Passphrase-less Keys)
For servers running Gordon automatically, use a GPG key without a passphrase:
# Generate key without passphrase
gpg --batch --gen-key <<EOF
Key-Type: EdDSA
Key-Curve: ed25519
Name-Real: Gordon Automation
Name-Email: [email protected]
Expire-Date: 0
%no-protection
%commit
EOF
Security Note: Protect access to the server itself when using passphrase-less keys.
Running in Containers
See Running Gordon in a Container for container-specific setup.
Quick summary:
docker run -d \
--name gordon \
-v $HOME/.gnupg:/home/gordon/.gnupg:ro \
-v $HOME/.password-store:/home/gordon/.password-store:ro \
gordon-with-pass
Troubleshooting
"gpg: decryption failed: No secret key"
Your GPG private key isn't available.
# List available secret keys
gpg --list-secret-keys
# If empty, import your key
gpg --import your-private-key.asc
"pass: command not found"
Pass isn't installed.
# Ubuntu/Debian
sudo apt install pass
# macOS
brew install pass
"Error: password store is empty"
Initialize pass first:
pass init YOUR_GPG_KEY_ID
"gpg: public key decryption failed: Inappropriate ioctl for device"
GPG needs a TTY for passphrase entry:
export GPG_TTY=$(tty)
Add to ~/.bashrc for persistence.
"gpg-agent: no running gpg-agent"
Start the GPG agent:
gpg-agent --daemon
Permissions Issues
Ensure correct permissions:
chmod 700 ~/.gnupg
chmod 600 ~/.gnupg/*
chmod 700 ~/.password-store
Security Best Practices
- Protect GPG keys: Back up securely, use strong passphrases for interactive use
- Limit access: Use separate GPG keys per environment (dev, staging, prod)
- Rotate secrets: Periodically update passwords and tokens
- Audit access: Review who has GPG keys for each environment
- Use Git: Track changes to secrets with pass git integration