Secure Password Management in WSL: Building an Integrated Backup Environment with Pass and GPG
Introduction
Password management is an eternal challenge for developers. Especially in WSL (Windows Subsystem for Linux) environments, how to backup credentials managed on the Linux side becomes a critical issue.
This article explains how to build a system that combines the command-line password manager "Pass" with GPG encryption to automatically backup to the Windows side.
Goals
- Security: Strong security through GPG encryption
- Convenience: Quick access from the command line
- Automation: Automatic backup via Git integration
- Recoverability: Reliable restoration from Windows-side backups
- Unified Management: Managing passwords and GPG keys in a single repository
Understanding Pass and GPG
What is Pass?
Pass, short for "password store," is a simple password management tool for Unix/Linux. Developed by Jason A. Donenfeld in 2012, it has the following features:
- Text file-based: Each password is stored as an individual file
- Combination of standard tools: Utilizes GPG, Git, tree commands, etc.
- Extensibility: Easily customizable with shell scripts
What is GPG (GNU Privacy Guard)?
GPG is encryption software based on the OpenPGP standard:
- Public key cryptography: Uses public and private key pairs
- Digital signatures: Ensures data integrity and authentication
- Web of Trust: Decentralized trust model
Role Division between Pass and GPG
┌─────────────────────────────────────────┐
│ Pass (Management Layer) │
│ - Directory structure management │
│ - Git integration │
│ - Command-line interface │
└────────────────┬────────────────────────┘
│ Encryption/Decryption requests
↓
┌─────────────────────────────────────────┐
│ GPG (Encryption Layer) │
│ - Actual encryption/decryption process │
│ - Key management │
│ - Security guarantee │
└─────────────────────────────────────────┘
Detailed Interaction
Password Storage Flow ```bash pass insert github.com/personal
↓ Pass receives input
↓ Requests GPG to encrypt
↓ GPG encrypts with public key
↓ Pass saves as .gpg file
```
Password Retrieval Flow ```bash pass show github.com/personal
↓ Pass reads .gpg file
↓ Requests GPG to decrypt
↓ GPG decrypts with private key (passphrase required)
↓ Pass displays plaintext
```
Why Choose Pass?
Pass Features
- Unix philosophy: Each password as an individual GPG-encrypted file
- Git integration: Built-in version control
- Simple: No unnecessary features, robust
- Standard: Available in many Linux distributions
Comparison with Other Options
- KeePass: GUI-based and feature-rich, but limited CLI operations
- Bitwarden: Cloud sync is convenient, but not locally self-contained
- 1Password: Paid and feature-rich, but overkill
System Architecture
Architecture Diagram
Windows Host
│
├─ C:\gpg-keys-backup\
│ └─ wsl-personal-pass.git/ (Bare Repository)
│ ├─ GPG key backups
│ └─ Encrypted passwords
│
└─ WSL Ubuntu
└─ ~/secure/pass-with-gpg/
├─ .git/ (Auto-push configured)
├─ gpg-keys/
│ ├─ pass-secret-key.asc
│ ├─ pass-public-key.asc
│ └─ key-info.txt
└─ password-store/
└─ *.gpg (Encrypted passwords)
Data Flow
1. pass insert/generate ↓ 2. GPG encryption ↓ 3. Git auto-commit ↓ 4. Git Hooks (post-commit) ↓ 5. Auto-push to Windows repository
Prerequisites
Environment Requirements
Complete Setup Procedure
Setting Environment Variables
First, set the following variables according to your environment:
# Windows-side backup directory (change according to your environment) export BACKUP_DIR="/mnt/c/gpg-keys-backup" export REPO_NAME="wsl-personal-pass.git" # WSL-side working directory export WORK_DIR="$HOME/secure/pass-with-gpg" # GPG key settings (name and email for Pass) export GPG_NAME="Pass Manager" export GPG_EMAIL="pass@localhost"
1. Installing Required Tools
# System update sudo apt update # Install required tools sudo apt install -y gnupg pass git tree # Verify installation gpg --version pass --version git --version
2. Creating Windows-side Git Repository
Execute in Windows Command Prompt or PowerShell:
# Create backup directory mkdir C:\gpg-keys-backup cd C:\gpg-keys-backup # Initialize Git repository git init --bare wsl-personal-pass.git
Or, execute from WSL:
# Create Windows-side directory from WSL mkdir -p "$BACKUP_DIR" cd "$BACKUP_DIR" # Initialize Git repository git init --bare "$REPO_NAME"
3. Creating GPG Key (Pass-specific)
# Generate GPG key
gpg --batch --generate-key <<EOF
Key-Type: RSA
Key-Length: 4096
Subkey-Type: RSA
Subkey-Length: 4096
Name-Real: $GPG_NAME
Name-Email: $GPG_EMAIL
Expire-Date: 2y
%no-protection
%commit
EOF
# Automatically retrieve generated key ID
export PASS_GPG_ID=$(gpg --list-secret-keys --keyid-format LONG | grep -A1 "^sec" | grep "$GPG_EMAIL" -B1 | head -1 | awk '{print $2}' | cut -d'/' -f2)
# Verify
echo "Generated GPG Key ID: $PASS_GPG_ID"
gpg --list-secret-keys --keyid-format LONG
4. Building Integrated Repository
# Create working directory mkdir -p "$WORK_DIR" cd "$WORK_DIR" # Initialize as Git repository git init git remote add origin "$BACKUP_DIR/$REPO_NAME" # Create directory structure mkdir -p gpg-keys mkdir -p password-store # Export GPG keys cd gpg-keys gpg --armor --export-secret-keys "$PASS_GPG_ID" > pass-secret-key.asc gpg --armor --export "$PASS_GPG_ID" > pass-public-key.asc gpg --list-keys --fingerprint "$PASS_GPG_ID" > key-info.txt cd .. # Create README cat << EOF > README.md # WSL Personal Pass Repository This repository contains: - \`gpg-keys/\`: GPG keys for Pass - \`password-store/\`: Passwords managed by Pass ## Configuration - GPG Key ID: $PASS_GPG_ID - Created: $(date +%Y-%m-%d) EOF # Initial commit git add . git commit -m "Initial setup: GPG keys for Pass" git branch -M master git push -u origin master
5. Initializing Pass
cd "$WORK_DIR" # Use password-store directory as Pass store export PASSWORD_STORE_DIR="$WORK_DIR/password-store" # Initialize Pass pass init "$PASS_GPG_ID" # Create symbolic link (for access from usual location) ln -sf "$WORK_DIR/password-store" ~/.password-store
6. Setting Up Auto-commit & Push
# Create post-commit hook
# Note: This hook is in the .git directory and not under Git control
# Must be recreated during restoration
cat << 'EOF' > "$WORK_DIR/.git/hooks/post-commit"
#!/bin/bash
echo "Auto-pushing to backup repository..."
git push origin master
EOF
chmod +x "$WORK_DIR/.git/hooks/post-commit"
# Script to detect Pass changes and auto-commit
cat << 'SCRIPT' > "$WORK_DIR/auto-commit.sh"
#!/bin/bash
cd "$(dirname "$0")"
if [ -n "$(git status --porcelain)" ]; then
git add .
git commit -m "Auto-commit: $(date +%Y-%m-%d\ %H:%M:%S)"
fi
SCRIPT
chmod +x "$WORK_DIR/auto-commit.sh"
7. Adding bashrc Configuration
# Add configuration to ~/.bashrc
cat << 'BASHRC' >> ~/.bashrc
# Pass configuration
export PASS_GPG_ID="$(gpg --list-secret-keys --keyid-format LONG | grep -A1 "^sec" | grep "pass@localhost" -B1 | head -1 | awk '{print $2}' | cut -d'/' -f2)"
export PASSWORD_STORE_DIR="$HOME/secure/pass-with-gpg/password-store"
# Auto-commit after Pass operations
pass() {
command pass "$@"
local exit_code=$?
if [ $exit_code -eq 0 ]; then
case "$1" in
init|insert|add|generate|rm|remove|mv|cp|copy|edit)
(cd "$HOME/secure/pass-with-gpg" && ./auto-commit.sh)
;;
esac
fi
return $exit_code
}
# Backup GPG keys on update
backup-gpg-keys() {
local work_dir="$HOME/secure/pass-with-gpg"
cd "$work_dir/gpg-keys" || return 1
local gpg_id="$PASS_GPG_ID"
gpg --armor --export-secret-keys "$gpg_id" > pass-secret-key.asc
gpg --armor --export "$gpg_id" > pass-public-key.asc
gpg --list-keys --fingerprint "$gpg_id" > key-info.txt
cd "$work_dir"
if [ -n "$(git status --porcelain)" ]; then
git add .
git commit -m "GPG key update: $(date +%Y-%m-%d\ %H:%M:%S)"
fi
}
# Utility aliases
alias pass-status='cd "$HOME/secure/pass-with-gpg" && git status -s && echo "=== Recent commits ===" && git log --oneline -5'
alias pass-tree='tree -a "$HOME/secure/pass-with-gpg" -I ".git"'
alias pass-sync='cd "$HOME/secure/pass-with-gpg" && git pull && git push'
BASHRC
# Apply configuration
source ~/.bashrc
8. Creating Restoration Documentation
# Create restoration documentation
cat << 'RESTORE' > "$WORK_DIR/RESTORE.md"
# Restoration Procedure
## 1. Clone Repository
\`\`\`bash
git clone /mnt/c/gpg-keys-backup/wsl-personal-pass.git ~/secure/pass-with-gpg
ln -sf ~/secure/pass-with-gpg/password-store ~/.password-store
\`\`\`
## 2. Restore GPG Keys
\`\`\`bash
cd ~/secure/pass-with-gpg/gpg-keys
gpg --import pass-secret-key.asc
gpg --import pass-public-key.asc
# Get imported key ID
export IMPORTED_KEY_ID=\$(gpg --list-secret-keys --keyid-format LONG | grep -A1 "^sec" | tail -1 | awk '{print \$1}' | cut -d'/' -f2)
# Set trust level
gpg --edit-key \$IMPORTED_KEY_ID trust quit
# Select 5 for ultimate trust
\`\`\`
## 3. Configure Environment
Add the Pass configuration above to ~/.bashrc and run source ~/.bashrc
## 4. Verify Operation
\`\`\`bash
pass list
\`\`\`
RESTORE
# Commit
cd "$WORK_DIR"
git add RESTORE.md
git commit -m "Add restore documentation"
git push
9. Security Settings
# Set directory permissions chmod 700 "$WORK_DIR" chmod 700 "$WORK_DIR/gpg-keys" chmod 600 "$WORK_DIR/gpg-keys/"* chmod 700 "$WORK_DIR/.git/hooks/post-commit" chmod 700 "$WORK_DIR/auto-commit.sh"
10. Verification and Testing
# Verify GPG key echo "=== GPG Key Info ===" gpg --list-secret-keys --keyid-format LONG # Create initial test entry echo "=== Creating test entry ===" pass generate test/initial-setup 16 # Check status echo "=== Repository status ===" pass-status # Display tree structure echo "=== Directory structure ===" pass-tree # Test sync echo "=== Testing sync ===" pass-sync
Usage
Basic Operations
# Add password pass insert github.com/personal # Generate password (32 characters) pass generate aws/prod/api-key 32 # Show password pass show github.com/personal # Copy password to clipboard (auto-clear after 45 seconds) pass -c github.com/personal # List passwords pass list # Search passwords pass find github
Management Commands
# Check backup status pass-status # Display directory structure pass-tree # Manual sync pass-sync # After updating GPG key backup-gpg-keys
Troubleshooting
Common Issues and Solutions
GPG Errors
# Reset GPG agent gpgconf --kill gpg-agent gpgconf --launch gpg-agent
Git Push Errors
# Verify and fix remote cd "$WORK_DIR" git remote -v git remote set-url origin "$BACKUP_DIR/$REPO_NAME"
Pass Not Working
# Check environment variables
echo $PASS_GPG_ID
echo $PASSWORD_STORE_DIR
# Manually reset
export PASS_GPG_ID=$(gpg --list-secret-keys --keyid-format LONG | grep -A1 "^sec" | tail -1 | awk '{print $1}' | cut -d'/' -f2)
source ~/.bashrc
Security Best Practices
1. GPG Key Protection
- Regularly change GPG key passphrase
- Always backup after key updates with
backup-gpg-keys - Use dedicated keys for Pass, don't mix with other purposes
2. Access Restrictions
- Restrict access to Windows-side backup directory
- Maintain WSL working directory permissions at 700
- Always set private key file permissions to 600
3. Operational Considerations
- Perform restoration tests quarterly
- Regularly check backup status with
pass-status - Delete passwords when no longer needed
4. Passphrase Policy
- Recommend 20+ characters for GPG key passphrase
- Use combinations of non-dictionary words
- Include numbers and symbols
Summary
This setup achieves the following:
- ✅ Secure password management in WSL environment
- ✅ Automatic backup to Windows side
- ✅ Change tracking via Git history
- ✅ Reliable disaster recovery procedures
- ✅ Fast command-line access
Credential management is an unavoidable challenge in WSL development environments. By combining Pass and GPG, you can build an environment that balances security and convenience.