Re: libpq: decouple the .pgpass lookup port from the connection port

From: Diego <mrstephenamell(at)gmail(dot)com>
To: Christoph Berg <myon(at)debian(dot)org>
Cc: pgsql-hackers(at)lists(dot)postgresql(dot)org
Subject: Re: libpq: decouple the .pgpass lookup port from the connection port
Date: 2026-07-13 17:02:03
Message-ID: 396c2054-1351-4146-a15e-d1298c62f5e6@gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hello Christoph, and thanks for your time and the pushback.

> If you are giving the correct remote name to libpq, the rule won't
> match several different hosts.
[...]
> Don't use a wildcard, put :54321 in.

You are right, and I should concede this clearly: with host set to the
real server name (for the .pgpass key and TLS) and hostaddr pointing at
the tunnel, the lookup key becomes realname:54321, which is specific and
safe, no cross-host over-match. So my "the wildcard is not enough"
argument was aiming at the wrong target: the answer is not a wildcard,
it is host/hostaddr plus the connection port in .pgpass. For a tunnel
you open by hand, with a fixed local port, there is nothing missing and
no new parameter is warranted. I withdraw that part of the motivation.

What that solution still requires is that the .pgpass entry encode the
*local* port. That is fine when the local port is fixed and known in
advance. It breaks when the local port is dynamic:

- ssh -L 127.0.0.1:0:server:5432 (kernel picks the port)
- connection proxies that bind an ephemeral local port per session:
  cloud-sql-proxy, the AlloyDB auth proxy, AWS SSM port forwarding,
  Teleport's "tsh proxy db", and similar
- GUI/CLI clients that manage the tunnel themselves and allocate the
  local port at runtime (this is the case where I first hit it, in a
  libpq-based client, probably most of the pg-ecosystem-apps)

In all of these the local port is not known when .pgpass is written, and
it changes between sessions, so "put :54321 in" is not available. The
real server port, on the other hand, is fixed. So the only thing you
need is to key the .pgpass lookup on the real server port while
connecting to whatever local port the tool handed you. Everything else
(host, database, user, TLS) is already handled by host/hostaddr.

Which brings me to what I think is the more interesting question, and
where your host/hostaddr point actually leads. Rather than "yet another
password-file parameter", the symmetric framing is:

portaddr : port  ::  hostaddr : host

That is: let "port" be the logical port used for the .pgpass lookup (the
real server port), and add "portaddr" as the numeric port actually
connected to, exactly as hostaddr is to host. When portaddr is unset,
libpq connects to port as it does today, so it is fully backward
compatible; a tunnel with a dynamic local port is then just

host=db.example.com hostaddr=127.0.0.1 port=5432 portaddr=54321

with the natural .pgpass entry db.example.com:5432:... -- the same entry
that already works for a direct connection. No password-file-specific
concept at all; it just completes the host/hostaddr model for the port.

The cost is that it re-purposes the primary meaning of "port" (from "the
port connected to" to "the logical port"), the way hostaddr once did to
host. My current patch instead keeps "port" as the connection port and
adds a lookup-only override (spelled passfileport in v1). Both are
backward compatible; the difference is naming and which parameter holds
the real vs. local value.

does completing the model as port/portaddr seem preferable to a lookup-only
passfileport, or is re-purposing "port" a non-starter and the asymmetry
with host/hostaddr intentional? I would rather settle the shape before
rewriting the patch either way.

> Is this proposal just a giant buildup for a "PG passport" joke? :)

jajjajja, nono, was to test if someone reads me,but I will happily drop
the passport spelling; portaddr keeps things boring on purpose. :)

Thanks again,
Diego

On 2026-07-08 14:15, Christoph Berg wrote:
> Re: Diego
>> Why the port wildcard is not enough
>> -----------------------------------
>>
>> One can write the entry with a wildcard port:
>>
>>     db.example.com:*:appdb:alice:secret
>> and it does match the tunnel. But the wildcard over-matches: a single
>> local forwarding port (say 54321, or even a fixed local port reused for
>> several tunnels at different times) ends up matching every server reached
>> through that port,
> If you are giving the correct remote name to libpq, the rule won't
> match several different hosts. If you don't care about that part, you
> don't need anything extra and could just match on localhost:54321 (or
> localhost:*).
>
>> so the same password line can be applied to different
>> servers. That is precisely the kind of "password sent to the wrong
>> server" situation the 2018 host fix was trying to avoid. The wildcard
>> trades safety for convenience; it is not a substitute for matching the
>> real server port.
> Don't use a wildcard, put :54321 in.
>
> TBH I don't see why yet more connection parameters are required when
> the problem is already solved by setting the hostname/hostaddr
> correctly. (The part that remains when doing that can be avoided by
> not reusing ports I think. You should do that anyway for general
> sanity.)
>
>>     - pgpassport / passfileport (it only affects the password file)
> Is this proposal just a giant buildup for a "PG passport" joke? :)
>
> Christoph

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Jeff Davis 2026-07-13 17:09:34 Re: Small patch to improve safety of utf8_to_unicode().
Previous Message Bohyun Lee 2026-07-13 16:36:49 Re: [PATCH] pg_upgrade: add --initdb option to create the new cluster automatically