Skip to content

Comments

Enable .pgpass support for SSH tunnel connections#1546

Open
DiegoDAF wants to merge 1 commit intodbcli:mainfrom
DiegoDAF:feature/pgpass-ssh-tunnel
Open

Enable .pgpass support for SSH tunnel connections#1546
DiegoDAF wants to merge 1 commit intodbcli:mainfrom
DiegoDAF:feature/pgpass-ssh-tunnel

Conversation

@DiegoDAF
Copy link

@DiegoDAF DiegoDAF commented Dec 5, 2025

Summary

This PR enables PostgreSQL's .pgpass file to work seamlessly with SSH tunnel connections. Previously, when using --ssh-tunnel, the .pgpass file was not consulted because pgcli was connecting to 127.0.0.1 instead of the original database hostname.

Problem

When using SSH tunnels, the connection flow was:

  1. User specifies: --ssh-tunnel user@bastion --host production.db.com
  2. SSH tunnel created: 127.0.0.1:random_portproduction.db.com:5432
  3. pgcli connects to: 127.0.0.1:random_port
  4. .pgpass lookup fails (looking for 127.0.0.1 instead of production.db.com)

Solution

Use PostgreSQL's host/hostaddr parameter separation:

  • host: Original database hostname (for .pgpass lookup and SSL verification)
  • hostaddr: Actual connection endpoint 127.0.0.1 (SSH tunnel local port)

Changes

Core Functionality

  • Modified connect() to preserve original host and use hostaddr for tunnel
  • Updated connect_uri() to pass DSN parameter for proper .pgpass handling
  • Modified pgexecute.py to preserve hostaddr when using DSN connections

SSH Tunnel Enhancements

  • Added ssh_config_file: Use ~/.ssh/config for host settings
  • Added allow_agent: Enable SSH agent for authentication
  • Set compression: False: Better performance for database connections

Benefits

.pgpass file now works with SSH tunnels
✅ No manual password entry needed
✅ Standard PostgreSQL authentication flow
✅ SSL certificate verification uses correct hostname
✅ Maintains all existing functionality

Example Usage

# Setup .pgpass file
echo "production.db.example.com:5432:mydb:dbuser:secret_password" >> ~/.pgpass
chmod 600 ~/.pgpass

# Connect via SSH tunnel - password read from .pgpass automatically!
pgcli --ssh-tunnel user@bastion.example.com -h production.db.example.com -d mydb -U dbuser

Technical Details

PostgreSQL supports both host and hostaddr parameters:

  • When both are specified, host is used for authentication (.pgpass, Kerberos, SSL CN)
  • hostaddr is used for the actual TCP connection
  • This is perfect for SSH tunnels where we need different values for each

Compatibility

  • Fully backward compatible
  • No changes to non-SSH tunnel connections
  • Existing SSH tunnel connections continue to work
  • New functionality is transparent to users

Made with ❤️ and 🤖 Claude Code

@DiegoDAF DiegoDAF marked this pull request as ready for review December 9, 2025 13:21
Copy link
Contributor

@j-bennet j-bennet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs test coverage before it can go in.

Preserve original hostname for .pgpass lookup using PostgreSQL's
host/hostaddr parameters: host keeps the original DB hostname (for
.pgpass and SSL), hostaddr gets 127.0.0.1 (the tunnel endpoint).

Changes:
- main.py: Use hostaddr instead of replacing host with 127.0.0.1
- main.py: Pass dsn in connect_uri() for proper .pgpass handling
- pgexecute.py: Simplify DSN filtering to keep dsn, password, hostaddr
- tests: Add 4 new tests, update existing to verify host preservation

Made with ❤️ and 🤖 Claude
@DiegoDAF DiegoDAF force-pushed the feature/pgpass-ssh-tunnel branch from a67e7d8 to a050131 Compare February 20, 2026 15:24
@DiegoDAF
Copy link
Author

Addressed the feedback:

  • Simplified preserved_params: Replaced with a direct dict comprehension filtering for dsn, password, and hostaddr — no intermediary variable needed.
  • Added test coverage: 4 new tests covering host preservation with SSH tunnels, DSN+hostaddr behavior, no-tunnel baseline, and connect_uri dsn passing.
  • Rebased on latest main (a0c2ee4).

@j-bennet
Copy link
Contributor

Looks like there are test failures, take a look @DiegoDAF.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants