From ad8b8a419af84ddec7a56a15e9d5e9abadfa3c4d Mon Sep 17 00:00:00 2001 From: Mika Salminen Date: Thu, 2 Jan 2025 13:15:12 +0200 Subject: [PATCH 1/4] Add new environment variable PGCONNECT_ADDRESS to set the postgresql.connect_address Spilo by default uses IP for the property ```postgresql.connect_address```. This is a problem when Patroni REST API is configured in SSL with client authentication because hostname validation is performed or behind NAT. This PR solves the problem with the introduction of environment variable: PGCONNECT_ADDRESS. You can configure it with the external IP of the spilo or dns name of spilo and the replicas will use the address PGCONNECT_ADDRESS:PGPORT when connecting the primary. --- ENVIRONMENT.rst | 1 + postgres-appliance/scripts/configure_spilo.py | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/ENVIRONMENT.rst b/ENVIRONMENT.rst index ea2e3df81..072a7ed33 100644 --- a/ENVIRONMENT.rst +++ b/ENVIRONMENT.rst @@ -30,6 +30,7 @@ Environment Configuration Settings - **ALLOW_NOSSL**: set to allow clients to connect without SSL enabled. - **PGPORT**: port PostgreSQL listens to for client connections, 5432 by default - **PGVERSION**: Specifies the version of postgreSQL to reference in the bin_dir variable (/usr/lib/postgresql/PGVERSION/bin) if postgresql.bin_dir wasn't set in SPILO_CONFIGURATION +- **PGCONNECT_ADDRESS**: When you configure postgreSQL behind NAT or you set a hostname based SSL certificate for it you might need to advertise different connect address (for example external IP, hostname instead of IP) for the replicas. - **SCOPE**: cluster name, multiple Spilos belonging to the same cluster must have identical scope. - **SSL_CA_FILE**: path to the SSL CA certificate file inside the container (by default: '') - **SSL_CRL_FILE**: path to the SSL Certificate Revocation List file inside the container (by default: '') diff --git a/postgres-appliance/scripts/configure_spilo.py b/postgres-appliance/scripts/configure_spilo.py index b7a301202..f2d5bd95b 100755 --- a/postgres-appliance/scripts/configure_spilo.py +++ b/postgres-appliance/scripts/configure_spilo.py @@ -284,7 +284,7 @@ def deep_update(a, b): use_unix_socket_repl: true name: '{{instance_data.id}}' listen: '*:{{PGPORT}}' - connect_address: {{instance_data.ip}}:{{PGPORT}} + connect_address: {{PGCONNECT_ADDRESS}}:{{PGPORT}} data_dir: {{PGDATA}} parameters: archive_command: {{{postgresql.parameters.archive_command}}} @@ -696,6 +696,7 @@ def get_placeholders(provider): placeholders['instance_data'] = get_instance_metadata(provider) placeholders.setdefault('RESTAPI_CONNECT_ADDRESS', placeholders['instance_data']['ip']) + placeholders.setdefault('PGCONNECT_ADDRESS', placeholders['instance_data']['ip']) placeholders['BGMON_LISTEN_IP'] = get_listen_ip() From 997ebdcdd485d7de390cfb27d4e1f5ec24d9e09f Mon Sep 17 00:00:00 2001 From: Mika Salminen Date: Thu, 2 Jan 2025 20:18:57 +0200 Subject: [PATCH 2/4] Added fix to patroni_wait.sh to support SSL secured patroni. This is quickfix to get it working. --- postgres-appliance/scripts/patroni_wait.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/postgres-appliance/scripts/patroni_wait.sh b/postgres-appliance/scripts/patroni_wait.sh index 6edb95234..33ed43bb3 100755 --- a/postgres-appliance/scripts/patroni_wait.sh +++ b/postgres-appliance/scripts/patroni_wait.sh @@ -54,6 +54,7 @@ do *) echo "Unknown option: $1" exit 1 + ;; esac shift @@ -62,7 +63,13 @@ done if [ $# -gt 0 ]; then [ -n "$TIMEOUT" ] && CUTOFF=$(($(date +%s)+TIMEOUT)) - while [ "$(curl -so /dev/null -w '%{http_code}' "http://localhost:8008/$ROLE")" != "200" ]; do + if [ -z "$RESTAPI_CONNECT_ADDRESS" ]; then + ADDRESS="localhost" + else + ADDRESS="$RESTAPI_CONNECT_ADDRESS" + fi + + while [ "$(curl --cert $SSL_RESTAPI_CERTIFICATE_FILE --key $SSL_PRIVATE_KEY_FILE --cacert $SSL_RESTAPI_CA_FILE -so /dev/null -w '%{http_code}' "https://$ADDRESS:8008/$ROLE")" != "200" ]; do [ -n "$TIMEOUT" ] && [ $CUTOFF -le "$(date +%s)" ] && exit 2 sleep "$INTERVAL" done From fbe197cdebb5a6a2d12653c5cec58ed0d4ff038d Mon Sep 17 00:00:00 2001 From: Mika Salminen Date: Thu, 2 Jan 2025 20:21:15 +0200 Subject: [PATCH 3/4] Added simple build script --- postgres-appliance/build.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 postgres-appliance/build.sh diff --git a/postgres-appliance/build.sh b/postgres-appliance/build.sh new file mode 100644 index 000000000..5c97029ce --- /dev/null +++ b/postgres-appliance/build.sh @@ -0,0 +1,15 @@ +#/bin/bash +WITH_PERL=false # set to true if you want to install perl and plperl packages into image +PGVERSION="17" +DEMO=false # set to true to build the smallest possible image which will work only on Kubernetes +TIMESCALEDB_APACHE_ONLY=false # set to false to build timescaledb community version (Timescale License) +TIMESCALEDB_TOOLKIT=false # set to false to skip installing toolkit with timescaledb community edition. Only relevant when TIMESCALEDB_APACHE_ONLY=false +ADDITIONAL_LOCALES=fi_FI # additional UTF-8 locales to build into image (example: "de_DE pl_PL fr_FR") + +docker build -t ghcr.io/damischa1/spilo:X.X . \ + --build-arg WITH_PERL=false \ + --build-arg PGVERSION="17" \ + --build-arg DEMO=false \ + --build-arg TIMESCALEDB_APACHE_ONLY=false \ + --build-arg TIMESCALEDB_TOOLKIT=false \ + --build-arg ADDITIONAL_LOCALES=fi_FI \ No newline at end of file From 3310ff1e4592577465870b9e6b39c55bbeb18976 Mon Sep 17 00:00:00 2001 From: Mika Salminen Date: Thu, 2 Jan 2025 20:40:35 +0200 Subject: [PATCH 4/4] Added restapi verify client parameter --- postgres-appliance/scripts/configure_spilo.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/postgres-appliance/scripts/configure_spilo.py b/postgres-appliance/scripts/configure_spilo.py index f2d5bd95b..580ecb99e 100755 --- a/postgres-appliance/scripts/configure_spilo.py +++ b/postgres-appliance/scripts/configure_spilo.py @@ -278,6 +278,9 @@ def deep_update(a, b): {{#SSL_RESTAPI_PRIVATE_KEY_FILE}} keyfile: {{SSL_RESTAPI_PRIVATE_KEY_FILE}} {{/SSL_RESTAPI_PRIVATE_KEY_FILE}} + {{#SSL_RESTAPI_VERIFY_CLIENT}} + verify_client: {{SSL_RESTAPI_VERIFY_CLIENT}} + {{/SSL_RESTAPI_VERIFY_CLIENT}} postgresql: pgpass: /run/postgresql/pgpass use_unix_socket: true @@ -555,6 +558,7 @@ def get_placeholders(provider): placeholders.setdefault('SSL_RESTAPI_CA_FILE', '') placeholders.setdefault('SSL_RESTAPI_CERTIFICATE_FILE', '') placeholders.setdefault('SSL_RESTAPI_PRIVATE_KEY_FILE', '') + placeholders.setdefault('SSL_RESTAPI_VERIFY_CLIENT', '') placeholders.setdefault('WALE_BACKUP_THRESHOLD_MEGABYTES', 102400) placeholders.setdefault('WALE_BACKUP_THRESHOLD_PERCENTAGE', 30) placeholders.setdefault('INITDB_LOCALE', 'en_US')