Skip to main content
chezmoi includes support for KeePass using the Passhole CLI (ph) to expose data as template functions.

Overview

Passhole (ph) is a command-line interface for KeePass databases. Unlike KeePassXC CLI, Passhole provides a more streamlined interface for accessing KeePass databases from the terminal.

Setup

Install Passhole

pip install passhole

Initialize Database

If you don’t have a KeePass database:
ph init /path/to/database.kdbx
Or use an existing KeePass database:
ph set-database /path/to/database.kdbx

Template Function

passhole

Retrieve a specific field from a KeePass entry:
{{ passhole "path/to/entry" "field" }}
Common field names:
  • password
  • username
  • url
  • notes
  • Custom field names

Configuration

Basic Configuration

~/.config/chezmoi/chezmoi.toml
[passhole]
    command = "ph"

With Password Prompt

~/.config/chezmoi/chezmoi.toml
[passhole]
    prompt = true
When prompt = true, chezmoi will prompt for your database password once and cache it for the session.

Custom Arguments

~/.config/chezmoi/chezmoi.toml
[passhole]
    args = ["--database", "/path/to/database.kdbx"]

Usage Examples

Basic Password Retrieval

~/.config/api-keys.env.tmpl
GITHUB_TOKEN={{ passhole "Personal/GitHub" "password" }}

Git Configuration

~/.gitconfig.tmpl
[user]
    name = {{ passhole "Personal/Git" "username" }}
    email = {{ passhole "Personal/Git" "email" }}
    signingkey = {{ passhole "Personal/Git" "gpg_key" }}

Database Credentials

~/.config/db/config.yml.tmpl
production:
  host: {{ passhole "Work/Database/Production" "url" }}
  port: 5432
  username: {{ passhole "Work/Database/Production" "username" }}
  password: {{ passhole "Work/Database/Production" "password" }}
  database: {{ passhole "Work/Database/Production" "database_name" }}

AWS Credentials

~/.aws/credentials.tmpl
[default]
aws_access_key_id = {{ passhole "Cloud/AWS" "access_key_id" }}
aws_secret_access_key = {{ passhole "Cloud/AWS" "secret_access_key" }}
region = {{ passhole "Cloud/AWS" "region" }}

Multiple API Keys

~/.config/api-keys.env.tmpl
# GitHub
GITHUB_TOKEN={{ passhole "API/GitHub" "password" }}

# GitLab
GITLAB_TOKEN={{ passhole "API/GitLab" "password" }}

# OpenAI
OPENAI_API_KEY={{ passhole "API/OpenAI" "api_key" }}

# Stripe
STRIPE_SECRET_KEY={{ passhole "API/Stripe" "secret_key" }}
STRIPE_PUBLISHABLE_KEY={{ passhole "API/Stripe" "publishable_key" }}

NPM Configuration

~/.npmrc.tmpl
//registry.npmjs.org/:_authToken={{ passhole "Development/NPM" "password" }}
email={{ passhole "Development/NPM" "email" }}

SSH Configuration

~/.ssh/config.tmpl
Host github.com
    User {{ passhole "SSH/GitHub" "username" }}
    IdentityFile ~/.ssh/id_ed25519

Host gitlab.com
    User {{ passhole "SSH/GitLab" "username" }}
    IdentityFile ~/.ssh/id_rsa

Host work-server
    HostName {{ passhole "SSH/WorkServer" "url" }}
    User {{ passhole "SSH/WorkServer" "username" }}
    IdentityFile ~/.ssh/work_id_rsa

Docker Registry

~/.docker/config.json.tmpl
{
  "auths": {
    "https://index.docker.io/v1/": {
      "auth": "{{ printf "%s:%s" (passhole "Docker/Hub" "username") (passhole "Docker/Hub" "password") | b64enc }}"
    }
  }
}

Managing KeePass Database with Passhole

Adding Entries

# Add a new entry
ph add "Personal/GitHub"
# Enter username, password, url, etc.

# Add entry with specific fields
ph add "API/Service" --username user --password pass --url https://example.com

Listing Entries

# List all entries
ph list

# List entries in a group
ph list "Personal"

Viewing Entries

# Show entry details
ph show "Personal/GitHub"

# Show specific field
ph show "Personal/GitHub" --field password

Editing Entries

ph edit "Personal/GitHub"

Deleting Entries

ph delete "Personal/GitHub"

Entry Organization

Organize entries in groups (folders):
Root/
├── Personal/
│   ├── Email/
│   │   └── Gmail
│   ├── GitHub
│   └── Social/
│       ├── Twitter
│       └── LinkedIn
├── Work/
│   ├── AWS
│   ├── GitHub
│   └── Database/
│       ├── Production
│       └── Staging
└── API/
    ├── GitHub
    ├── OpenAI
    └── Stripe
Access with:
{{ passhole "Personal/GitHub" "password" }}
{{ passhole "Work/Database/Production" "password" }}
{{ passhole "API/OpenAI" "api_key" }}

Custom Fields

Passhole supports custom fields beyond the standard username/password:
# Add entry with custom fields
ph add "API/Service"
# When prompted, add custom fields like:
# - api_key
# - endpoint
# - region
Access custom fields:
api_key: {{ passhole "API/Service" "api_key" }}
endpoint: {{ passhole "API/Service" "endpoint" }}
region: {{ passhole "API/Service" "region" }}

Complete Examples

Multi-Service Configuration

~/.config/services.yml.tmpl
github:
  username: {{ passhole "Personal/GitHub" "username" }}
  token: {{ passhole "Personal/GitHub" "password" }}
  email: {{ passhole "Personal/GitHub" "email" }}

aws:
  access_key_id: {{ passhole "Cloud/AWS" "access_key_id" }}
  secret_access_key: {{ passhole "Cloud/AWS" "secret_access_key" }}
  region: {{ passhole "Cloud/AWS" "region" }}

database:
  host: {{ passhole "Work/Database" "url" }}
  port: 5432
  username: {{ passhole "Work/Database" "username" }}
  password: {{ passhole "Work/Database" "password" }}
  database: production

redis:
  host: localhost
  port: 6379
  password: {{ passhole "Work/Redis" "password" }}

Application Environment

~/.config/app/.env.tmpl
# Application
APP_NAME=myapp
APP_ENV=production
APP_KEY={{ passhole "App/Laravel" "app_key" }}

# Database
DB_HOST={{ passhole "App/Database" "url" }}
DB_PORT=5432
DB_DATABASE={{ passhole "App/Database" "database" }}
DB_USERNAME={{ passhole "App/Database" "username" }}
DB_PASSWORD={{ passhole "App/Database" "password" }}

# Cache
REDIS_HOST=localhost
REDIS_PASSWORD={{ passhole "App/Redis" "password" }}
REDIS_PORT=6379

# Mail
MAIL_HOST={{ passhole "App/Mail" "host" }}
MAIL_PORT={{ passhole "App/Mail" "port" }}
MAIL_USERNAME={{ passhole "App/Mail" "username" }}
MAIL_PASSWORD={{ passhole "App/Mail" "password" }}

# AWS
AWS_ACCESS_KEY_ID={{ passhole "App/AWS" "access_key_id" }}
AWS_SECRET_ACCESS_KEY={{ passhole "App/AWS" "secret_access_key" }}
AWS_REGION={{ passhole "App/AWS" "region" }}

Troubleshooting

Database Locked

If using prompt = true, chezmoi will prompt for your password once per session. If prompt = false, ensure your database is unlocked or use a key file.

Entry Not Found

List all entries to find the correct path:
ph list
ph show "path/to/entry"

Command Not Found

Ensure Passhole is installed:
which ph
ph --version

Testing Templates

Test template functions:
chezmoi execute-template '{{ passhole "Personal/GitHub" "password" }}'

Field Not Found

View all fields for an entry:
ph show "path/to/entry"

Best Practices

  1. Use groups: Organize entries in logical groups (Personal, Work, API)
  2. Consistent paths: Use a clear naming convention for entry paths
  3. Custom fields: Use custom fields for structured data
  4. Backup database: Keep encrypted backups of your KeePass database
  5. Strong master password: Use a strong password for your database
  6. Use prompt mode: Enable prompt = true for better security
  7. Test access: Verify entries are accessible before templating
  8. Sync carefully: If syncing database, ensure it’s encrypted

See Also

Build docs developers (and LLMs) love