root/private/: vault-touchid-gate-0.2.0 metadata and description

Simple index

Touch ID gate for rbw/bw (Bitwarden CLI) — remote client for SSH hosts

author Tobias Hochgürtel
author_email Tobias Hochgürtel <tobias.hochguertel@googlemail.com>
classifiers
  • Development Status :: 4 - Beta
  • Environment :: Console
  • Intended Audience :: Developers
  • Programming Language :: Python :: 3.11
  • Programming Language :: Python :: 3.12
  • Programming Language :: Python :: 3.13
  • Topic :: Security
description_content_type text/markdown
keywords bitwarden,rbw,touchid,ssh,vault,security
license_expression MIT
requires_dist
  • ruamel-yaml>=0.18
requires_python >=3.11

Because this project isn't in the mirror_whitelist, no releases from root/pypi are included.

File Tox results History
vault_touchid_gate-0.2.0-py3-none-any.whl
Size
10 KB
Type
Python Wheel
Python
3
vault_touchid_gate-0.2.0.tar.gz
Size
8 KB
Type
Source

vault-touchid-gate

Gate rbw and bw (Bitwarden CLI) behind macOS Touch ID — locally and over SSH. No sudo, no env-var juggling, auto-unlock from Keychain.

Why

The official bw CLI requires you to manually lock/unlock and pass session keys via environment variables. rbw solves this with a background agent (like ssh-agent), but still requires typing your master password to unlock.

This project adds a Touch ID gate on top of rbw/bw so that:

Architecture

Local (on the Mac)

vault rbw get "GitHub"
  │
  ├─→ touchid-gate (Swift / LocalAuthentication)
  │     🔑 Touch ID requested — waiting for fingerprint...
  │     ✓ Touch ID approved
  │
  ├─→ (if vault locked) retrieve master password from Keychain
  │                     → expect feeds it to `rbw unlock`
  │
  └─→ exec rbw get "GitHub"

Remote (over SSH, including jump hosts)

[Remote server]                    [MacBook]
vault rbw get "GitHub"
  │
  ├─→ vault-agent-client
  │     connects to localhost:8423
  │         │
  │     SSH reverse tunnel ────────→ vault-agent (daemon, 127.0.0.1:8423)
  │                                      │
  │                                 touchid-gate (Touch ID prompt on Mac)
  │                                      │ approved
  │                                 rbw get "GitHub"
  │                                      │
  │     ←──── JSON response ─────────────┘
  │
  └─→ prints stdout/stderr, exits with code

The SSH reverse tunnel chains through jump hosts automatically:

MacBook ──SSH──→ srv-fedora ──SSH──→ vps9
  │                 │                  │
  vault-agent       tunnel             tunnel
  (127.0.0.1:8423)  (localhost:8423)   (localhost:8423)
                     → Mac:8423         → srv-fedora:8423 → Mac:8423
Component Description
touchid-gate.swift Swift program using LocalAuthentication to trigger Touch ID. Compiled to a fast binary. Biometrics only (no password fallback).
vault Bash wrapper. Detects local vs remote mode. Local: Touch ID gate + Keychain auto-unlock. Remote: connects to vault-agent via tunnel.
vault-setup One-time setup. Stores Bitwarden master password in macOS Keychain.
vault-agent Python daemon (Mac). Listens on 127.0.0.1:8423. For each request: Touch ID → run rbw/bw → return result as JSON.
vault-agent-client Python client (remote). Connects to localhost:8423 via SSH tunnel, sends request, prints result.

Requirements

Mac (local mode)

Remote servers (remote mode)

Installation

On the Mac

git clone <repo-url>
cd vault-touchid-gate
./install.sh

This compiles touchid-gate.swift and installs all scripts to ~/.local/bin/.

On remote servers

# Clone the repo on the remote server
git clone <repo-url>
cd vault-touchid-gate
./install.sh --remote

This installs only vault and vault-agent-client (no Swift, no touchid-gate needed).

Configuration

1. Configure rbw (on the Mac)

rbw config set base_url "https://your-bitwarden-server.com"
rbw config set email "you@example.com"
rbw config set pinentry "pinentry-tty"
rbw config set lock_timeout 300   # auto-lock after 5 min (default: 3600)

2. Register the device (official Bitwarden server only)

rbw register

Self-hosted servers may not require this.

3. Store your master password in Keychain

vault-setup

4. Start the vault-agent daemon (on the Mac)

# Foreground (for testing):
vault-agent

# Background:
vault-agent &

# Or auto-start on login via launchd:
mkdir -p ~/Library/LaunchAgents
# Edit launchd/com.hochguertel.vault-agent.plist to use your home path
cp launchd/com.hochguertel.vault-agent.plist ~/Library/LaunchAgents/
launchctl load ~/Library/LaunchAgents/com.hochguertel.vault-agent.plist

5. Test locally

vault rbw list

Remote SSH Access

SSH config setup

Add RemoteForward to your ~/.ssh/config on the Mac:

# Direct connection to a server
Host srv-fedora
    HostName srv-fedora.example.com
    User youruser
    RemoteForward 8423 127.0.0.1:8423
    ExitOnForwardFailure yes

# Jump host: Mac → srv-fedora → vps9
Host vps9
    HostName vps9.internal
    User youruser
    ProxyJump srv-fedora
    RemoteForward 8423 127.0.0.1:8423
    ExitOnForwardFailure yes

With ProxyJump, the reverse tunnel chains automatically through the jump host. ExitOnForwardFailure yes ensures the SSH connection fails if the tunnel can't be set up (rather than silently continuing without vault access).

Manual chaining (without ProxyJump)

If you SSH manually through hops (Mac → srv-fedora → vps9), add RemoteForward at each hop:

# On Mac:
ssh -R 8423:127.0.0.1:8423 srv-fedora

# On srv-fedora:
ssh -R 8423:127.0.0.1:8423 vps9

This chains the tunnel: vps9:8423 → srv-fedora:8423 → Mac:8423.

Remote installation (Python package)

The remote components (vault + vault-agent-client) are published to the private devpi registry as the vault-touchid-gate package. Install them on a remote host with:

uv tool install --extra-index-url https://pypi.registry.hochguertel.work/root/private/+simple/ vault-touchid-gate

No clone, no build, no mise.toml on the host — just Python 3.12+. The package depends on ruamel.yaml (resolved from PyPI; devpi serves only the package itself, so always install with --extra-index-url as above). The vault entry point is remote-mode only: if it detects touchid-gate (a Mac), it refuses to run so it can never shadow the local-mode bash wrapper from install.sh.

Update an existing install:

uv tool upgrade --extra-index-url https://pypi.registry.hochguertel.work/root/private/+simple/ vault-touchid-gate

Test from a remote server

# On the remote server (after SSHing in with the tunnel):
vault rbw list

Touch ID fires on your Mac. You approve. The result appears on the remote.

How it works

  1. vault-agent daemon runs on your Mac, listening on 127.0.0.1:8423
  2. You SSH to a remote server with RemoteForward 8423 127.0.0.1:8423
  3. On the remote, localhost:8423 is tunneled back to your Mac's 8423
  4. vault on the remote detects it's not on a Mac (no touchid-gate) → uses vault-agent-client
  5. vault-agent-client connects to localhost:8423 → tunnel → vault-agent on Mac
  6. vault-agent triggers Touch ID on your Mac
  7. You approve → vault-agent runs rbw/bw → returns result as JSON
  8. vault-agent-client prints the result on the remote

Environment variables (remote)

Variable Default Description
VAULT_AGENT_HOST 127.0.0.1 Host to connect to (use with non-standard tunnel setups)
VAULT_AGENT_PORT 8423 Port to connect to
VAULT_AGENT_TIMEOUT 120 Timeout in seconds (waiting for Touch ID)

Usage

# List all entries (local or remote — same command)
vault rbw list

# Get a password
vault rbw get "GitHub"

# Get all fields (username, password, notes, custom fields)
vault rbw get --full "GitHub"

# Get a TOTP code
vault rbw code "GitHub"

# Sync from server
vault rbw sync

# Add an entry (password first line, notes after — no editor, works
# identically locally and from remote hosts, Touch ID gated):
printf '%s\n' 'hunter2' 'note line' | vault rbw add "My Entry" user --uri https://example.com

# Use the official bw CLI (also gated behind Touch ID)
vault bw sync

# Manually lock the vault (on the Mac)
rbw lock

# Start/stop the daemon (on the Mac)
vault-agent &           # start
pkill -f vault-agent    # stop

Security Model

What this does

What this does NOT do

Removing the master password from Keychain

security delete-generic-password -s "rbw-master-password" -a "$(id -un)"

Files

vault-touchid-gate/
├── bin/
│   ├── touchid-gate.swift     # Swift source — LocalAuthentication Touch ID gate
│   ├── vault                  # Bash wrapper — detects local/remote, gates access
│   ├── vault-setup            # One-time setup — stores master password in Keychain
│   ├── vault-agent            # Python daemon (Mac) — Touch ID + rbw over TCP
│   └── vault-agent-client     # Python client (remote) — connects to agent via tunnel
├── launchd/
│   └── com.hochguertel.vault-agent.plist  # macOS auto-start for the daemon
├── docs/
│   └── ARCHITECTURE.md        # Design decisions and trust model
├── install.sh                 # Installation script (auto-detects Mac vs remote)
├── LICENSE                    # MIT
└── README.md

License

MIT