Re: POC: Carefully exposing information without authentication

From: Greg Sabino Mullane <htamfids(at)gmail(dot)com>
To: Andres Freund <andres(at)anarazel(dot)de>
Cc: Antonin Houska <ah(at)cybertec(dot)at>, Tom Lane <tgl(at)sss(dot)pgh(dot)pa(dot)us>, "pgsql-hackers(at)lists(dot)postgresql(dot)org" <pgsql-hackers(at)lists(dot)postgresql(dot)org>
Subject: Re: POC: Carefully exposing information without authentication
Date: 2026-09-15 17:57:04
Message-ID: CAKAnmmJBhwNK-vBgRJ0EgBVe_2dLomKOGtt=OLFbkA1Kd1eFjA@mail.gmail.com
Views: Whole Thread | Raw Message | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

New, rebased version with an expanded commit message, and a small sleep in
the tests to try an overcome an issue with the WIN32 CI tests. Here's the
new message:

Allow specific information to be output directly by Postgres

Add a new GUC 'expose_information' that lets a small, fixed set of
facts about the current server (recovery/role status, system identifier,
and version) be queried over a plain HTTP request (GET or HEAD) on
the same port PostgreSQL already listens on - without requiring
authentication. This lets external tools have a way to quickly obtain
information without requiring an account or ability to speak the protocol.

expose_information takes a comma-separated list of options:

role - whether the server is currently a primary or a replica
version - the server's server_version_num
sysid - the system identifier

The GUC defaults to an empty string, so nothing is returned until
explicitly enabled. It can be changed with a reload.

When enabled, we check immediately after we fork by using
MSG_PEEK to scan the first few bytes the client has sent.
The socket is set non-blocking, and then restored to its
original state. If the bytes match a small selection of
strings, we handle it then and there: GET /replica, GET /primary,
HEAD /replica, HEAD /primary, GET /version, and GET /sysid.
Exact matches only: GET /versionx will not work.
A minimal HTTP/1.1 response is sent back, the connection is
closed, and the backend exits immediately. The outgoing message
has a timeout to prevent the client from keeping the connection
open.

The HEAD /replica and HEAD /primary are meant to be drop in
replacements for the Patroni REST API items. They return an
HTTP code (200 for true, 503 for false), with no content. This
allows for a lightweight health check, without requiring
creation of an account and other overhead.

The GET /version was designed to replace the common practice of
monitoring systems that send a bad login message to the server, and
use the debugging information about what line in our source code triggered
the error as a very rough indication as to what version the Postgres
server is running. Rather than all those workaround, they can simply
ask the server with a quick HTTP request.

If the bytes we examine do not match anything, they are left untouched
in the kernel socket buffer and control falls back to the normal
startup packet / authentication flow, so all connections are
unaffected even if expose_information is set.

A new TAP test, t/016_expose_information.pl, checks the output
of calls to the TCP socket for all the known endpoints, including
for servers in primary or replica mode. Also verify that normal
libpq connections still work.

Attachment Content-Type Size
0008-Allow-specific-information-to-be-output-directly-by-Postgres.patch application/octet-stream 25.5 KB

In response to

Browse pgsql-hackers by date

  From Date Subject
Next Message Andrey Borodin 2026-09-15 18:13:26 Re: Return pg_control from pg_backup_stop().
Previous Message Burd, Greg 2026-09-15 17:22:24 Re: use a non-locking initial test in TAS_SPIN on AArch64