v2.30.0-pre6 511705f

secrets-pass.md RawHistoryFolder

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: gordon@yourdomain.com
# - 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 <gordon@yourdomain.com>

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 git@github.com:yourorg/secrets.git

# Commit and push
pass git push -u origin main

Pull Secrets on New Server

# Clone the pass store
git clone git@github.com: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: gordon@server.local
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

  1. Protect GPG keys: Back up securely, use strong passphrases for interactive use
  2. Limit access: Use separate GPG keys per environment (dev, staging, prod)
  3. Rotate secrets: Periodically update passwords and tokens
  4. Audit access: Review who has GPG keys for each environment
  5. Use Git: Track changes to secrets with pass git integration
source
1# Using Pass for Secrets
2
3Set up the Unix password manager (`pass`) as Gordon's secrets backend for secure credential storage.
4
5## What You'll Learn
6
7- Installing and initializing pass
8- Storing Gordon secrets securely
9- Configuring Gordon to use pass
10- Team workflows with shared GPG keys
11- Troubleshooting common issues
12
13## Prerequisites
14
15- Linux or macOS system
16- GPG installed
17- Basic understanding of GPG keys
18
19## Why Pass?
20
21Pass is a simple, Unix-philosophy password manager that:
22
23- Stores secrets as GPG-encrypted files
24- Integrates with Git for version control
25- Works with standard Unix tools
26- Supports multiple GPG keys for team access
27
28## Installation
29
30### Ubuntu/Debian
31
32```bash
33sudo apt install pass gnupg
34```
35
36### macOS
37
38```bash
39brew install pass gnupg
40```
41
42### Arch Linux
43
44```bash
45sudo pacman -S pass gnupg
46```
47
48## Initial Setup
49
50### 1. Generate a GPG Key (if needed)
51
52```bash
53# Generate a new GPG key
54gpg --gen-key
55
56# Follow prompts:
57# - Real name: Gordon Server
58# - Email: gordon@yourdomain.com
59# - Passphrase: (use a strong passphrase or leave empty for automation)
60```
61
62List your keys to find the key ID:
63
64```bash
65gpg --list-keys
66```
67
68Output:
69
70```
71pub   ed25519 2024-01-15 [SC]
72      ABC123DEF456...  <-- This is your key ID
73uid           [ultimate] Gordon Server <gordon@yourdomain.com>
74```
75
76### 2. Initialize Pass Store
77
78```bash
79pass init ABC123DEF456...  # Use your GPG key ID
80```
81
82This creates `~/.password-store/`.
83
84### 3. Create Gordon Secrets
85
86```bash
87# Registry password hash (bcrypt)
88# Generate with: htpasswd -nbB admin yourpassword | cut -d: -f2
89pass insert gordon/auth/password_hash
90
91# Token secret (random 32+ chars for JWT signing)
92pass generate gordon/auth/token_secret 32
93```
94
95## Gordon Configuration
96
97### Enable Pass Backend
98
99```toml
100[auth]
101enabled = true
102secrets_backend = "pass"
103token_secret = "gordon/auth/token_secret"
104# Optional: enable password auth for interactive login
105# username = "admin"
106# password_hash = "gordon/auth/password_hash"
107```
108
109### Using Route Secrets
110
111With the pass backend, per-domain secrets are stored in pass, not `.env` files.
112
113```bash
114# Store secrets for a domain
115gordon secrets set app.mydomain.com DATABASE_URL "postgresql://user:pass@postgres:5432/app"
116gordon secrets set app.mydomain.com API_KEY "your-api-key"
117```
118
119Gordon migrates existing `.env` files on startup and renames them to `.env.migrated`.
120
121## Organizing Secrets
122
123Recommended directory structure in pass:
124
125```
126~/.password-store/
127├── gordon/
128│   └── auth/
129│       ├── password_hash.gpg
130│       └── token_secret.gpg
131├── myapp/
132│   ├── db/
133│   │   └── password.gpg
134│   ├── api/
135│   │   └── key.gpg
136│   └── jwt/
137│       └── secret.gpg
138└── production/
139    └── stripe/
140        └── secret_key.gpg
141```
142
143## Team Workflows
144
145### Multiple GPG Keys
146
147Allow multiple team members to decrypt secrets:
148
149```bash
150# Initialize with multiple keys
151pass init KEY_ID_1 KEY_ID_2 KEY_ID_3
152
153# Or add keys later
154pass init --path=gordon KEY_ID_1 KEY_ID_2
155```
156
157### Git Integration
158
159Version control your encrypted secrets:
160
161```bash
162# Initialize git in pass store
163pass git init
164
165# Add remote
166pass git remote add origin git@github.com:yourorg/secrets.git
167
168# Commit and push
169pass git push -u origin main
170```
171
172### Pull Secrets on New Server
173
174```bash
175# Clone the pass store
176git clone git@github.com:yourorg/secrets.git ~/.password-store
177
178# Import team GPG keys
179gpg --import team-member.pub
180```
181
182## Automation (Passphrase-less Keys)
183
184For servers running Gordon automatically, use a GPG key without a passphrase:
185
186```bash
187# Generate key without passphrase
188gpg --batch --gen-key <<EOF
189Key-Type: EdDSA
190Key-Curve: ed25519
191Name-Real: Gordon Automation
192Name-Email: gordon@server.local
193Expire-Date: 0
194%no-protection
195%commit
196EOF
197```
198
199> **Security Note**: Protect access to the server itself when using passphrase-less keys.
200
201## Running in Containers
202
203See [Running Gordon in a Container](/wiki/guides/running-in-container.md#using-pass-secrets-backend) for container-specific setup.
204
205Quick summary:
206
207```bash
208docker run -d \
209  --name gordon \
210  -v $HOME/.gnupg:/home/gordon/.gnupg:ro \
211  -v $HOME/.password-store:/home/gordon/.password-store:ro \
212  gordon-with-pass
213```
214
215## Troubleshooting
216
217### "gpg: decryption failed: No secret key"
218
219Your GPG private key isn't available.
220
221```bash
222# List available secret keys
223gpg --list-secret-keys
224
225# If empty, import your key
226gpg --import your-private-key.asc
227```
228
229### "pass: command not found"
230
231Pass isn't installed.
232
233```bash
234# Ubuntu/Debian
235sudo apt install pass
236
237# macOS
238brew install pass
239```
240
241### "Error: password store is empty"
242
243Initialize pass first:
244
245```bash
246pass init YOUR_GPG_KEY_ID
247```
248
249### "gpg: public key decryption failed: Inappropriate ioctl for device"
250
251GPG needs a TTY for passphrase entry:
252
253```bash
254export GPG_TTY=$(tty)
255```
256
257Add to `~/.bashrc` for persistence.
258
259### "gpg-agent: no running gpg-agent"
260
261Start the GPG agent:
262
263```bash
264gpg-agent --daemon
265```
266
267### Permissions Issues
268
269Ensure correct permissions:
270
271```bash
272chmod 700 ~/.gnupg
273chmod 600 ~/.gnupg/*
274chmod 700 ~/.password-store
275```
276
277## Security Best Practices
278
2791. **Protect GPG keys**: Back up securely, use strong passphrases for interactive use
2802. **Limit access**: Use separate GPG keys per environment (dev, staging, prod)
2813. **Rotate secrets**: Periodically update passwords and tokens
2824. **Audit access**: Review who has GPG keys for each environment
2835. **Use Git**: Track changes to secrets with pass git integration
284
285## Related
286
287- [Secrets Configuration](/docs/config/secrets.md)
288- [Authentication](/docs/config/auth.md)
289- [Running in Containers](/wiki/guides/running-in-container.md)
290- [Using SOPS for Secrets](./secrets-sops.md)

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close