Table of Contents Link to heading
- Installing pass and Generating a GPG Keypair
- Storing and Retrieving Passwords
- Bulk Export for Migration or Audit
- Synchronising the Password Store Across Devices with Git
- Common Failures and How to Resolve Them
- Conclusion
password-store (commonly invoked as pass) is the Unix-philosophy answer to credential management: passwords are stored as GPG-encrypted files, organised in a directory tree, with Git providing synchronisation and version history. There are no proprietary formats, no cloud lock-in, and no dependencies beyond tools that are standard in any Linux environment. The entire store is auditable, portable, and backed by well-understood cryptographic primitives.
This guide covers setup, day-to-day operations, cross-device synchronisation, and the failure modes worth knowing before they happen to you in production.
Installing pass and Generating a GPG Keypair Link to heading
sudo apt install pass
gpg --full-generate-key
Choose RSA 4096-bit with a defined expiry (2 years is a reasonable default). The passphrase protecting the private key is your last line of defence if the key file is ever exfiltrated — make it strong.
List your generated private keys:
gpg --list-secret-keys --keyid-format=long
Example output:
/home/user/.gnupg/pubring.kbx
------------------------------
sec rsa4096/1A2B3C4D5E6F7G8H 2025-03-15 [SC]
9X8Y7Z6W5V4U3T2S1R0P1A2B3C4D5E6F7G8H
uid [ultimate] Duc Mai <ducmai.network@gmail.com>
ssb rsa4096/2B3C4D5E6F7G8H9J 2025-03-15 [E]
Initialise your password store with the key fingerprint:
pass init 1A2B3C4D5E6F7G8H
Generate a GPG revocation certificate immediately and store it somewhere separate from the private key — ideally offline. If you lose access to the private key without a revocation cert, all passwords encrypted to that key become permanently inaccessible, and you cannot notify others that the key should no longer be trusted.
gpg --gen-revoke 1A2B3C4D5E6F7G8H > revoke.asc
Storing and Retrieving Passwords Link to heading
Add a Password Link to heading
pass insert banks/online-banking
pass prompts for the password twice (to confirm), then encrypts it to the configured GPG key and stores it at ~/.password-store/banks/online-banking.gpg. The directory structure is yours to define — use it to organise credentials by category, service, or environment.
Retrieve a Password Link to heading
Display to stdout:
pass banks/online-banking
Copy directly to clipboard (clears after 45 seconds by default):
pass -c banks/online-banking
-c) is preferable to stdout for interactive use — it avoids the password appearing in terminal history or being visible on screen. For automation or scripting contexts, stdout is appropriate since the output is being consumed programmatically rather than displayed.Remove a Password Link to heading
pass rm banks/online-banking
If Git integration is active, the deletion is committed automatically, giving you a record that the entry existed and when it was removed.
Bulk Export for Migration or Audit Link to heading
Bulk export is occasionally necessary for migration or audit purposes. The recommended approach is a script that decrypts entries to a secure temporary file rather than piping cleartext to disk or stdout directly.
Install and Run the Script Link to heading
curl -O https://raw.githubusercontent.com/duc-mt/dotfiles/refs/heads/master/bin/export_password_store
chmod +x export_password_store
./export_password_store
The script decrypts all entries in the store and writes them to a temporary file created by mktemp, providing a single cleartext snapshot you can reference or import into another system.
Understand mktemp in the Script
Link to heading
mktemp /tmp/example.XXXXXX
mktemp creates a uniquely named temporary file, returning a path like /tmp/example.a1b2c3. The six X characters are replaced with a random string, ensuring no two concurrent invocations produce the same filename. This prevents race conditions and predictable filename attacks.
If XXXXXX is omitted, mktemp may fail or fall back to platform-specific behaviour. Always include the suffix template. See the Linux manual page for full details.
Synchronising the Password Store Across Devices with Git Link to heading
Git integration turns pass into a multi-device credential store. Every pass insert, pass edit, and pass rm operation is automatically committed, giving you a full history of when credentials were added, changed, or removed.
Initialise a Git Repository Link to heading
Create a bare repository on your server or use a private remote:
git init --bare "$HOME/.password-store"
Wire the local store to Git and push:
pass git init
pass git branch -M master
pass git remote add origin https://github.com/duc-mt/password-store
pass git push origin master
.gpg files pushed to the remote are ciphertext — they’re safe to store in a private Git repository. Anyone who obtains the repository without your GPG private key gets encrypted blobs they cannot decrypt. That said, the filenames and directory structure are stored in plaintext, which reveals the categories and services you have credentials for. Keep the repository private.Set Up a Password Store on a New Machine Link to heading
# 1. Import your GPG keys
gpg --import pubkey.asc
gpg --allow-secret-key-import --import privkey.asc
# 2. Clone the repository
git clone https://github.com/duc-mt/password-store "$HOME/.password-store"
# 3. Trust your imported keys
gpg --edit-key 1A2B3C4D5E6F7G8H
Inside the gpg --edit-key session, use trust and select 5 (ultimate trust) for your own key. Without this step, every pass invocation will warn about an untrusted key.
Synchronise going forward:
pass git push
pass git pull
Common Failures and How to Resolve Them Link to heading
GPG “No Secret Key” Error Link to heading
gpg: decryption failed: No secret key
This error means GPG cannot find a private key capable of decrypting the target file. Verify that the correct key is imported:
gpg --list-secret-keys --keyid-format=long
If the key is listed but trust level is unknown or undefined, set it to ultimate as described above. If the key is not listed at all, re-import from your backup.
~/.password-store/.gpg-id). A mismatch here means the store was initialised with a different key than the one currently imported.Git Sync Issues Link to heading
If pass git push or pass git pull fail, diagnose the remote configuration first:
git remote -v
git status
Authentication failures on push/pull typically indicate an expired token, missing SSH key, or changed remote URL. Ensure your SSH agent has the correct key loaded or that your HTTPS credential helper is configured for the repository host.
Conclusion Link to heading
password-store with GPG and Git is a robust, auditable, and portable credential management system that requires no proprietary software, no cloud subscription, and no trust in a third-party service. The security model is transparent: credentials are protected by the strength of your GPG key and its passphrase, and the backup and synchronisation path is Git over HTTPS or SSH.
The operational discipline required — maintaining GPG key backups, generating revocation certificates, managing Git remotes — is real, but it’s the same discipline required for any serious use of asymmetric cryptography. Get those fundamentals right, and pass is a credential store you can rely on across machines, across years, and across jobs.