From b9565eaf6bbecda4c2ecda65f212f5a1265f799b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcos=20M=C3=A9ndez?= Date: Sun, 27 Sep 2026 06:51:36 +0000 Subject: [PATCH] Listen on both loopback addresses, and name them The layer shipped a database an appliance built on it could not reach over IPv6, which is the address family this project builds for. conf.d/main asserted Debian's default, listen_addresses = 'localhost', on the grounds that it is the loopback of both families. It is not. Debian's /etc/hosts maps ::1 to ip6-localhost and ip6-loopback and never to localhost, so getaddrinfo("localhost") answers 127.0.0.1 alone and the cluster binds the IPv4 loopback only. Measured on a container booted from the published layer: # ss -lntH 'sport = :5432' LISTEN 0 200 127.0.0.1:5432 0.0.0.0:* with ::1 up on lo and pg_hba.conf already carrying its scram-sha-256 line for ::1/128, ready for a connection that could never arrive. That is what failed firstboot.d/36pgsqlverify on the gate, and the hook was right: 35pgsqlpass had set the password over the unix socket and the database was still unreachable at the address this layer says it serves. The fix is two literal addresses, '::1,127.0.0.1', the same pair the MariaDB layer writes into its bind-address. A literal address cannot resolve into something else, which is the point: the previous line was not wrong about what it wanted, it was wrong about what a name meant on this machine. What it binds is now proved on the booted machine by the boot test rather than assumed by a grep of the setting here, which is the lesson of the defect: asserting the configuration is not asserting the behaviour. Measured on the build host, on a container booted from the published chain with the line in place: # ss -lntH 'sport = :5432' LISTEN 0 200 127.0.0.1:5432 0.0.0.0:* LISTEN 0 200 [::1]:5432 [::]:* $ psql --username=postgres --host=::1 --port=5432 --no-password \ --command='SELECT 1, current_user, inet_server_addr()' 1|postgres|::1 with the declared password in PGPASSWORD, and with the wrong one FATAL: password authentication failed for user "postgres" The layer ships this, so the changelog gains an entry and the layer needs a rebuild before its gate can go green. --- README.rst | 12 ++++++++---- changelog | 10 ++++++++++ conf.d/main | 30 ++++++++++++++++++++++++------ 3 files changed, 42 insertions(+), 10 deletions(-) diff --git a/README.rst b/README.rst index 069a558..4c23b7f 100644 --- a/README.rst +++ b/README.rst @@ -54,10 +54,14 @@ Upstream's ``conf.d/main`` sets ``listen_addresses = '*'`` and appends ``host all all 0.0.0.0/0 md5`` to ``pg_hba.conf``, so the appliance accepts password authentication for every database from anywhere. On an IPv6 first, publicly routable appliance (brief section 5.3) that is not a default this -project can inherit quietly. This layer keeps Debian's -``listen_addresses = 'localhost'``, which is the loopback of both families, -and asserts at build time that neither of upstream's two changes is -present. An appliance that really has remote clients opens the port, says +project can inherit quietly. This layer listens on +``'::1,127.0.0.1'``, the loopback of both families and nothing else, and +asserts at build time that neither of upstream's two changes is present. +Both addresses are written out rather than left to Debian's default of +``'localhost'``: that default binds the IPv4 loopback alone, because +Debian's ``/etc/hosts`` maps ``::1`` to ``ip6-localhost`` and never to +``localhost``, which is a defect this layer shipped once and its own boot +test caught. An appliance that really has remote clients opens the port, says who may connect and terminates TLS. That is a decision an appliance makes, not one a database layer makes for everything built on it. diff --git a/changelog b/changelog index 500786b..5ca7b24 100644 --- a/changelog +++ b/changelog @@ -1,3 +1,13 @@ +turnkey-postgresql-19.0 (2) turnkey; urgency=low + + * Listen on both loopback addresses, named literally: + listen_addresses = '::1,127.0.0.1'. Debian's default, 'localhost', + binds the IPv4 loopback alone, because Debian's /etc/hosts maps ::1 to + ip6-localhost and never to localhost, so an appliance built on this + layer and reaching its database over IPv6 found nothing listening. + + -- Keel Linux maintainers Sun, 27 Sep 2026 07:30:00 +0000 + turnkey-postgresql-19.0 (1) turnkey; urgency=low * Initial release of the PostgreSQL database layer for Keel, compatible diff --git a/conf.d/main b/conf.d/main index b304ae3..5908c2a 100755 --- a/conf.d/main +++ b/conf.d/main @@ -41,12 +41,30 @@ EOF systemctl stop postgresql -# The cluster listens on the loopback of both families and nowhere else. -# Debian's default, listen_addresses = 'localhost', is exactly that, so it -# is asserted rather than changed: upstream's postgresql appliance replaces -# it with '*' and appends a pg_hba line accepting password authentication -# from 0.0.0.0/0, and this layer must not inherit that by accident. -grep -qE "^#?listen_addresses = 'localhost'" "$CONF_DIR/postgresql.conf" +# The cluster listens on the loopback of both families and nowhere else, +# and both are named as literal addresses. +# +# Debian's default is listen_addresses = 'localhost', and that was taken +# for "the loopback of both families" when this layer was written. It is +# not. Debian's /etc/hosts maps ::1 to ip6-localhost and ip6-loopback and +# never to localhost, so getaddrinfo("localhost") answers 127.0.0.1 alone +# and the cluster binds the IPv4 loopback only. Measured on the booted +# layer: "LISTEN 127.0.0.1:5432" and nothing on [::1]:5432, with ::1 up on +# lo and pg_hba.conf already holding its scram-sha-256 line for ::1/128. +# An appliance built on this layer and reaching its database over IPv6, +# which is the default this project builds for (brief section 10), found +# nothing listening. +# +# Two literal addresses cannot resolve into something else, which is the +# whole point of writing them out; what they bind to is then proved on the +# booted machine by the boot test rather than assumed here. +sed -i "s|^#\?listen_addresses = .*|listen_addresses = '::1,127.0.0.1'\t\t# set by conf.d/main of keel-postgresql: see the comment there|" \ + "$CONF_DIR/postgresql.conf" +grep -qE "^listen_addresses = '::1,127\.0\.0\.1'" "$CONF_DIR/postgresql.conf" + +# Upstream's postgresql appliance replaces listen_addresses with '*' and +# appends a pg_hba line accepting password authentication from 0.0.0.0/0. +# This layer must not inherit either by accident. ! grep -qE "^listen_addresses = '\*'" "$CONF_DIR/postgresql.conf" ! grep -qE '^host\s+all\s+all\s+0\.0\.0\.0/0' "$CONF_DIR/pg_hba.conf"