v2.4.0 79b3461

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/registry/password_hash

# Token secret (random 32+ chars for JWT signing)
pass generate gordon/registry/token_secret 32

Gordon Configuration

Enable Pass Backend

[secrets]
backend = "pass"

[registry_auth]
enabled = true
type = "token"
username = "admin"
password_hash = "gordon/registry/password_hash"
token_secret = "gordon/registry/token_secret"

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