gopass Mounts

Managing multiple secret stores and team sharing.

Understanding Mounts

Mounts are local configuration - they tell gopass where stores are located on THIS machine. They are NOT synced with git. Each machine needs its own mount configuration.

# Conceptual model
root (default store: ~/.local/share/gopass/stores/root)
├── local/                # Entries in root store
├── personal/             # Entries in root store
└── v3/ [MOUNT]           # Points to ~/.local/share/gopass/stores/v3
    ├── domains/          # Entries in v3 store
    └── personal/         # Entries in v3 store

KEY INSIGHT: gopass ls shows a unified tree, but entries live in different stores.

Basic Mount Operations

# List all mounts
gopass mounts

# Show mount details
gopass mounts
# Output:
# root  -> ~/.local/share/gopass/stores/root
# v3    -> ~/.local/share/gopass/stores/v3

# Add a mount (after store exists)
gopass mounts add v3 ~/.local/share/gopass/stores/v3

# Add mount with different path
gopass mounts add work ~/secrets/work-store

# Remove a mount
gopass mounts rm v3

# Remove mount (keeps the store, just unmounts)
gopass mounts rm work
# Store still exists at ~/secrets/work-store

GOTCHA: gopass mounts rm does NOT delete the store. It just removes the mount point.

New Machine Setup

When you set up gopass on a new machine, you must: 1. Clone the store repository 2. Mount it in gopass

# Step 1: Clone the store (if using git)
git clone git@github.com:username/gopass-v3.git ~/.local/share/gopass/stores/v3

# Step 2: Mount it
gopass mounts add v3 ~/.local/share/gopass/stores/v3

# Step 3: Verify
gopass ls v3/
gopass show v3/test/entry

# Alternative: Initialize new store (fresh)
gopass init --path ~/.local/share/gopass/stores/v3 GPGKEYID
gopass mounts add v3 ~/.local/share/gopass/stores/v3

TIP: Keep a setup script in your dotfiles that configures mounts.

Multi-Store Architecture

# Common setup: separate stores for different concerns
gopass mounts
# root     -> ~/.local/share/gopass/stores/root     # Default (legacy)
# v3       -> ~/.local/share/gopass/stores/v3       # Personal+infra
# work     -> ~/.local/share/gopass/stores/work     # Work secrets
# team     -> ~/.local/share/gopass/stores/team     # Shared team

# Why multiple stores?
# 1. Different recipients (who can decrypt)
# 2. Different sync locations (repos)
# 3. Different backup strategies
# 4. Different retention policies

# Create entries in specific store
gopass insert v3/domains/d000/server
gopass insert work/project/database

# Move between stores
gopass show work/old/entry | gopass insert -m v3/new/location
gopass rm work/old/entry
~/.local/share/gopass/
├── stores/
│   ├── root/              # Default store (usually keep minimal)
│   │   ├── .gpg-id        # Recipients for this store
│   │   ├── .git/
│   │   └── local/         # Machine-local entries
│   │
│   ├── v3/                # Main personal store
│   │   ├── .gpg-id
│   │   ├── .git/
│   │   ├── domains/
│   │   │   └── d000/
│   │   │       ├── infrastructure/
│   │   │       ├── services/
│   │   │       └── dev/
│   │   └── personal/
│   │
│   └── work/              # Work-only store
│       ├── .gpg-id        # Different recipients
│       ├── .git/
│       └── projects/
│
└── config                 # gopass config

Team Secrets (Shared Store)

# Team store with multiple recipients
# Each team member has their GPG key in .gpg-id

# 1. Initialize team store
gopass init --path ~/.local/share/gopass/stores/team KEY1 KEY2 KEY3

# 2. Each team member clones
git clone git@github.com:org/gopass-team.git ~/.local/share/gopass/stores/team

# 3. Each team member mounts
gopass mounts add team ~/.local/share/gopass/stores/team

# 4. Verify recipients
gopass recipients --store team
# Should show all team member keys

# 5. Add new team member
gopass recipients add NEWMEMBER_KEYID --store team
gopass sync --store team

# 6. Remove team member (IMPORTANT)
gopass recipients remove LEAVING_MEMBER_KEYID --store team
# This re-encrypts ALL entries, they can no longer decrypt
gopass sync --store team

SECURITY: When someone leaves, remove their key. Old git history still has entries encrypted to them, but new entries and re-encrypted entries are safe.

Sync and Git Operations

# Sync all stores
gopass sync

# Sync specific store
gopass sync --store v3

# Check git status
gopass git status
gopass git status --store v3

# Manual git operations
cd ~/.local/share/gopass/stores/v3
git log --oneline -10
git remote -v
git pull origin main
git push origin main

# Fix diverged history
cd ~/.local/share/gopass/stores/v3
git pull --rebase origin main
gopass sync

# Force push (DANGEROUS - overwrites remote)
gopass git push --force --store v3

TIP: Enable autosync to avoid manual sync:

gopass config core.autosync true

Clone vs Init

# CLONE: Existing store from remote
git clone git@github.com:user/gopass-v3.git ~/.local/share/gopass/stores/v3
gopass mounts add v3 ~/.local/share/gopass/stores/v3

# INIT: New store from scratch
gopass init --path ~/.local/share/gopass/stores/newstore GPGKEYID
gopass mounts add newstore ~/.local/share/gopass/stores/newstore

# After init, set up remote
cd ~/.local/share/gopass/stores/newstore
git remote add origin git@github.com:user/gopass-newstore.git
git push -u origin main

# Clone includes .gpg-id (recipients)
# You must have private key for one of the recipients to decrypt

Migration Between Stores

# Copy single entry
gopass show old-store/path/entry | gopass insert -m new-store/path/entry
gopass rm old-store/path/entry

# Copy subtree (bulk)
for entry in $(gopass ls -f old-store/category/ | grep '^old-store/category/'); do
    new_path=$(echo "$entry" | sed 's|old-store/|new-store/|')
    gopass show "$entry" | gopass insert -m "$new_path"
    echo "Migrated: $entry -> $new_path"
done

# After migration, verify and cleanup
gopass ls new-store/category/
gopass rm -r old-store/category/

# Change store path (move on filesystem)
mv ~/.local/share/gopass/stores/v2 ~/.local/share/gopass/stores/archive-v2
gopass mounts rm v2
gopass mounts add archive-v2 ~/.local/share/gopass/stores/archive-v2

Troubleshooting Mounts

# Mount not showing entries
gopass mounts                    # Check path is correct
ls ~/.local/share/gopass/stores/v3/  # Does it exist?
gopass recipients --store v3     # Can you decrypt?

# "Store not found"
gopass mounts add v3 ~/.local/share/gopass/stores/v3  # Re-add mount

# Wrong path in mount
gopass mounts rm v3
gopass mounts add v3 /correct/path/to/store

# Recipients mismatch
gpg --list-secret-keys           # Your keys
gopass recipients --store v3     # Store recipients
# You need private key for at least one recipient

# Store corrupted
cd ~/.local/share/gopass/stores/v3
gopass fsck --store v3
git status
git fsck

# Re-clone from remote (last resort)
mv ~/.local/share/gopass/stores/v3 ~/.local/share/gopass/stores/v3.bak
git clone git@github.com:user/gopass-v3.git ~/.local/share/gopass/stores/v3
gopass mounts rm v3
gopass mounts add v3 ~/.local/share/gopass/stores/v3

Setup Script Example

#!/bin/bash
# gopass-setup.sh - Run on new machine after GPG key is imported

STORES_DIR="$HOME/.local/share/gopass/stores"
mkdir -p "$STORES_DIR"

# Clone stores
echo "Cloning v3 store..."
git clone git@github.com:user/gopass-v3.git "$STORES_DIR/v3"

echo "Cloning work store..."
git clone git@github.com:org/gopass-work.git "$STORES_DIR/work"

# Mount stores
echo "Mounting stores..."
gopass mounts add v3 "$STORES_DIR/v3"
gopass mounts add work "$STORES_DIR/work"

# Verify
echo "Verifying..."
gopass mounts
gopass ls v3/ | head -5
gopass ls work/ | head -5

echo "Setup complete!"

Backup Considerations

# Each store is a git repo - remote IS the backup

# Additional local backup
tar czf gopass-backup-$(date +%Y%m%d).tar.gz ~/.local/share/gopass/stores/

# Backup config too
tar czf gopass-config-$(date +%Y%m%d).tar.gz ~/.config/gopass/

# What to backup for disaster recovery:
# 1. GPG keys (export with gpg --export-secret-keys)
# 2. Store remotes (git@github.com:...)
# 3. Mount configuration (recreate with script)

# Restore from git remote (primary method)
git clone git@github.com:user/gopass-v3.git ~/.local/share/gopass/stores/v3
gopass mounts add v3 ~/.local/share/gopass/stores/v3

# Restore from tarball (fallback)
tar xzf gopass-backup.tar.gz -C ~/.local/share/gopass/
gopass mounts add v3 ~/.local/share/gopass/stores/v3

CRITICAL: GPG private key is the most important thing to backup. Without it, encrypted entries are unrecoverable.