pass-ssh-unpack 0.5.0

A utility for unpacking proton's pass-cli ssh keys into usable ssh and rclone configurations.
pass-ssh-unpack-0.5.0 is not a library.

pass-ssh-unpack

[!IMPORTANT] This tool is still in the PROTOTYPE phase. Expect breaking changes. It is not recommended for use in production environments.

A utility for unpacking proton's pass-cli ssh keys into usable ssh and rclone configurations.

Features

  • Cross-platform: Works on Linux, macOS, and Windows
  • Automatic SSH config generation: Creates host entries with aliases
  • Machine-specific keys: Filter keys by hostname suffix (e.g., github/my-laptop)
  • Incremental updates: Only processes changed items by default
  • Rclone integration: Automatically creates SFTP remotes for each SSH host
  • Wildcard filtering: Filter vaults and items using glob patterns
  • Progress indicators: Visual feedback with spinners and progress bars
  • Encrypted rclone config: Supports encrypted rclone configs with password from Proton Pass

Requirements

Installation

From crates.io

cargo install pass-ssh-unpack

From source

Clone Repository

git clone https://github.com/Frosthaven/pass-ssh-unpack.git
cd pass-ssh-unpack
cargo build --release
# Binary will be at ./target/release/pass-ssh-unpack

Add to PATH

# Linux/macOS
sudo cp target/release/pass-ssh-unpack /usr/local/bin/

# Or symlink
ln -s "$(pwd)/target/release/pass-ssh-unpack" ~/.local/bin/pass-ssh-unpack

Usage

# Generates SSH key files, config, and rclone remotes from all vaults
pass-ssh-unpack

# ..from specific vault(s)
pass-ssh-unpack --vault Personal
pass-ssh-unpack --vault "Work*"    # Wildcard matching

# ..for specific items
pass-ssh-unpack --item "github/*"
pass-ssh-unpack --vault Personal --item "github/*"

# Full regeneration (clear and rebuild)
pass-ssh-unpack --full

# Only process SSH keys (skip rclone)
pass-ssh-unpack --ssh

# Only process rclone remotes (skip SSH)
pass-ssh-unpack --rclone

# Remove all managed SSH key files, config, and rclone remotes
pass-ssh-unpack --purge

# Quiet mode (suppress output)
pass-ssh-unpack --quiet

# Dry run (show what would be done)
pass-ssh-unpack --dry-run

CLI Options

CLI options override corresponding config file settings.

Option Short Description
--vault <PATTERN> -v Vault(s) to process (repeatable, supports wildcards)
--item <PATTERN> -i Item title pattern(s) (repeatable, supports wildcards)
--full -f Full regeneration (clear config first)
--dry-run Show what would be done without making changes
--quiet -q Suppress output
--ssh Only process SSH keys (skip rclone sync)
--rclone Only process rclone remotes (skip SSH extraction)
--purge Remove all managed SSH keys and rclone remotes
--config <PATH> -c Custom config file path
--output-dir <PATH> -o Override SSH output directory
--sync-public-key <MODE> Override public key sync mode (never/if-empty/always)
--rclone-password-path <PATH> Override rclone password path in Proton Pass
--always-encrypt Force rclone config encryption after operations
--help -h Show help
--version -V Show version

Configuration

On first run, a default config file is created at ~/.config/pass-ssh-unpack/config.toml:

# pass-ssh-unpack configuration file
# This file is auto-generated on first run. All fields are optional.

# Directory where SSH keys and config are written
# Supports ~ for home directory
# Default: ~/.ssh/proton-pass
ssh_output_dir = "~/.ssh/proton-pass"

# Default vault filter(s) - applied when no --vault flag is given
# Supports wildcards: "Personal", "Work*", etc.
# Default: [] (all vaults)
default_vaults = []

# Default item filter(s) - applied when no --item flag is given
# Supports wildcards: "github/*", "*-prod", etc.
# Default: [] (all items)
default_items = []

# When to sync generated public keys back to Proton Pass
# Options: "never", "if_empty" (default), "always"
#   never    - Never update public keys in Proton Pass
#   if_empty - Only update if the public key field is empty (default)
#   always   - Always overwrite the public key in Proton Pass
sync_public_key = "if_empty"

[rclone]
# Enable rclone SFTP remote sync
# Default: true
enabled = true

# Path in Proton Pass to rclone config password (if encrypted)
# This is optional if RCLONE_CONFIG_PASS is already set in your environment.
# If both are set, this value takes precedence.
# Leave empty to rely on environment variable or unencrypted config.
# Example: "pass://Personal/rclone/password"
# Default: ""
password_path = ""

# Always ensure rclone config is encrypted after operations
# If true and a password is available (via password_path or RCLONE_CONFIG_PASS),
# the rclone config will be re-encrypted even if it wasn't encrypted before.
# Default: false
always_encrypt = false

Proton Pass Item Structure

SSH key items in Proton Pass should have the following fields:

Field Required Description
Title Yes Item name. Use title/hostname format for machine-specific keys
Private Key Yes The private key
Host Yes The SSH host (IP or hostname)
Username No SSH username
Aliases No Comma-separated host aliases
Jump No Jump host for SSH config (ProxyJump directive)
SSH No Custom SSH binary/command for rclone (ssh option)
Server Command No SFTP server command for rclone (server_command option)

Jump Hosts and Custom SSH Commands

Jump is used for SSH config's ProxyJump directive - specify just the jump host:

  • Example: Jump = bastion.example.com
  • Generated SSH config: ProxyJump bastion.example.com
  • This field only affects SSH config, not rclone.

SSH is used for rclone's ssh option - specify the full SSH command:

  • Example: SSH = tsh ssh --proxy=example.com --user=username (for Teleport)
  • Example: SSH = ssh -J bastion.example.com (for jump host support in rclone)
  • Generated rclone config: ssh = tsh ssh --proxy=example.com --user=username
  • This field only affects rclone, not SSH config.

Server Command is used for rclone's server_command option - specify the SFTP server path:

  • Example: Server Command = /usr/lib/openssh/sftp-server
  • Generated rclone config: server_command = /usr/lib/openssh/sftp-server
  • This is useful when using custom SSH commands that don't support the SFTP subsystem.

Note: These fields are independent. Use Jump for standard SSH jump hosts, SSH when rclone needs a custom SSH binary or options, and Server Command when rclone needs to explicitly invoke the SFTP server.

Machine-Specific Keys

If an item title contains a /, the part after the last / is treated as a hostname filter. The key will only be extracted on machines with a matching hostname (case-insensitive).

Examples:

  • github/my-laptop - Only extracted on machine with hostname my-laptop
  • work-server - Extracted on all machines

macOS Hostname Detection

On macOS, the tool uses the LocalHostName (Bonjour name) rather than the dynamic DHCP hostname, which can change based on network configuration. This provides stable machine identification.

To check your LocalHostName:

scutil --get LocalHostName

To set it (if needed):

sudo scutil --set LocalHostName my-laptop

On Linux and Windows, the system hostname is used directly.

How It Works

  1. Authenticate: Checks that you're logged into Proton Pass CLI
  2. Extract keys: For each SSH key item:
    • Writes private key to ~/.ssh/proton-pass/<vault>/<item>
    • Generates public key using ssh-keygen
    • Saves public key back to Proton Pass if missing and sync-public-key is enabled
  3. Generate SSH config: Creates ~/.ssh/proton-pass/config (or at your configured ssh_output_dir) with host entries that you can include in your own ssh config file.
  4. Sync rclone remotes: Syncs SFTP remotes named after the first alias

SSH Config Integration

Add this line to your ~/.ssh/config:

Include ~/.ssh/proton-pass/config

Note: If you used a custom ssh_output_dir, include config from there.

License

MIT License - see LICENSE for details.