v2.7.0 fac7705

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 Secrets in Environment Files

Reference pass secrets in your app's environment files:

# ~/.gordon/env/app_mydomain_com.env
DATABASE_URL=postgresql://user:${pass:myapp/db/password}@postgres:5432/app
API_KEY=${pass:myapp/api/key}
JWT_SECRET=${pass:myapp/jwt/secret}

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 Secrets in Environment Files
110
111Reference pass secrets in your app's environment files:
112
113```bash
114# ~/.gordon/env/app_mydomain_com.env
115DATABASE_URL=postgresql://user:${pass:myapp/db/password}@postgres:5432/app
116API_KEY=${pass:myapp/api/key}
117JWT_SECRET=${pass:myapp/jwt/secret}
118```
119
120## Organizing Secrets
121
122Recommended directory structure in pass:
123
124```
125~/.password-store/
126├── gordon/
127│   └── auth/
128│       ├── password_hash.gpg
129│       └── token_secret.gpg
130├── myapp/
131│   ├── db/
132│   │   └── password.gpg
133│   ├── api/
134│   │   └── key.gpg
135│   └── jwt/
136│       └── secret.gpg
137└── production/
138    └── stripe/
139        └── secret_key.gpg
140```
141
142## Team Workflows
143
144### Multiple GPG Keys
145
146Allow multiple team members to decrypt secrets:
147
148```bash
149# Initialize with multiple keys
150pass init KEY_ID_1 KEY_ID_2 KEY_ID_3
151
152# Or add keys later
153pass init --path=gordon KEY_ID_1 KEY_ID_2
154```
155
156### Git Integration
157
158Version control your encrypted secrets:
159
160```bash
161# Initialize git in pass store
162pass git init
163
164# Add remote
165pass git remote add origin git@github.com:yourorg/secrets.git
166
167# Commit and push
168pass git push -u origin main
169```
170
171### Pull Secrets on New Server
172
173```bash
174# Clone the pass store
175git clone git@github.com:yourorg/secrets.git ~/.password-store
176
177# Import team GPG keys
178gpg --import team-member.pub
179```
180
181## Automation (Passphrase-less Keys)
182
183For servers running Gordon automatically, use a GPG key without a passphrase:
184
185```bash
186# Generate key without passphrase
187gpg --batch --gen-key <<EOF
188Key-Type: EdDSA
189Key-Curve: ed25519
190Name-Real: Gordon Automation
191Name-Email: gordon@server.local
192Expire-Date: 0
193%no-protection
194%commit
195EOF
196```
197
198> **Security Note**: Protect access to the server itself when using passphrase-less keys.
199
200## Running in Containers
201
202See [Running Gordon in a Container](/wiki/guides/running-in-container.md#using-pass-secrets-backend) for container-specific setup.
203
204Quick summary:
205
206```bash
207docker run -d \
208  --name gordon \
209  -v $HOME/.gnupg:/home/gordon/.gnupg:ro \
210  -v $HOME/.password-store:/home/gordon/.password-store:ro \
211  gordon-with-pass
212```
213
214## Troubleshooting
215
216### "gpg: decryption failed: No secret key"
217
218Your GPG private key isn't available.
219
220```bash
221# List available secret keys
222gpg --list-secret-keys
223
224# If empty, import your key
225gpg --import your-private-key.asc
226```
227
228### "pass: command not found"
229
230Pass isn't installed.
231
232```bash
233# Ubuntu/Debian
234sudo apt install pass
235
236# macOS
237brew install pass
238```
239
240### "Error: password store is empty"
241
242Initialize pass first:
243
244```bash
245pass init YOUR_GPG_KEY_ID
246```
247
248### "gpg: public key decryption failed: Inappropriate ioctl for device"
249
250GPG needs a TTY for passphrase entry:
251
252```bash
253export GPG_TTY=$(tty)
254```
255
256Add to `~/.bashrc` for persistence.
257
258### "gpg-agent: no running gpg-agent"
259
260Start the GPG agent:
261
262```bash
263gpg-agent --daemon
264```
265
266### Permissions Issues
267
268Ensure correct permissions:
269
270```bash
271chmod 700 ~/.gnupg
272chmod 600 ~/.gnupg/*
273chmod 700 ~/.password-store
274```
275
276## Security Best Practices
277
2781. **Protect GPG keys**: Back up securely, use strong passphrases for interactive use
2792. **Limit access**: Use separate GPG keys per environment (dev, staging, prod)
2803. **Rotate secrets**: Periodically update passwords and tokens
2814. **Audit access**: Review who has GPG keys for each environment
2825. **Use Git**: Track changes to secrets with pass git integration
283
284## Related
285
286- [Secrets Configuration](/docs/config/secrets.md)
287- [Authentication](/docs/config/auth.md)
288- [Running in Containers](/wiki/guides/running-in-container.md)
289- [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