public inbox for [email protected]  
help / color / mirror / Atom feed
From: Bob Ross <[email protected]>
To: Tatsuo Ishii <[email protected]>
Cc: [email protected]
Subject: Re: Rotate SSL certificates on reload (SIGHUP) without restart
Date: Fri, 17 Apr 2026 11:50:48 +0200
Message-ID: <CAHtZvrcgCbM8=xTdxhdm_qOnQ4=ttAJpB_amTdG8r4NzcukYAQ@mail.gmail.com> (raw)
In-Reply-To: <[email protected]>
References: <CAHtZvrdhAbVSh2yhSwk0qeHmnL+Sr0LPvjrA+2inKF6WNh7azw@mail.gmail.com>
	<[email protected]>
	<CAHtZvreKzO3fwfWZfmSPKjc0qN4P5bsvGMLhCir6gSK8pOFnXQ@mail.gmail.com>
	<[email protected]>

Hi Tatsuo,

I've fixed the test failure. The issue was that the original test used the
static self-signed server.crt as the CA bundle. When ssl_ca_cert is set,
pgpool verifies the backend certificate against it, and the self-signed
cert failed that check. The fix generates a dedicated server CA in the test
and issues a backend cert signed by it, so pgpool can always verify the
backend while ca1/ca2 are independently swapped to test client-cert trust
rotation.

The test now passes:





*CA cert swap: CA1-signed client cert accepted before reload – ok.CA cert
swap: CA1-signed client cert rejected after reload to CA2 – ok.testing
042.ssl_reload...ok.out of 1 ok:1 failed:0 timeout:0*

pgpool.log showing client cert accepted before reload:




*2026-04-17 09:23:31.449: child pid 81378: DEBUG:  got the SSL
certificate2026-04-17 09:23:31.449: child pid 81378: DETAIL:  Protocol
Major: 3 Minor: 0 database: test user: ssltest2026-04-17 09:23:31.450:
child pid 81378: DETAIL:  client->server SSL response: S2026-04-17
09:23:31.455: child pid 81378: DETAIL:  auth kind:0*

SSL certificate reload completed:

*2026-04-17 09:23:31.471: main pid 81347: LOG:  reload SSL certificates.*

pgpool.log showing client cert rejected after reload:



*2026-04-17 09:23:32.485: psql pid 81385: DETAIL:  SSLRequest from
client2026-04-17 09:23:32.493: psql pid 81385: LOG:  pool_ssl:
"SSL_accept": "certificate verify failed"2026-04-17 09:23:32.493: psql pid
81385: ERROR:  failed while reading startup packet*

No changes to the core patch.
The updated v4 is attached.

Regards,
Bob

On Fri, Apr 17, 2026 at 12:37 AM Tatsuo Ishii <[email protected]> wrote:

> Hi Bob,
>
> Thank you for the new patch. This time it failed with different
> pgpool.log.
> src/test/regression/log/042.ssl_reload was same.
>
> 2026-04-17 07:30:46.893: child pid 1475041: DEBUG:  attempting to
> negotiate a secure connection
> 2026-04-17 07:30:46.893: child pid 1475041: DETAIL:  sending
> client->server SSL request
> 2026-04-17 07:30:46.893: child pid 1475041: DEBUG:  pool_flush_it: flush
> size: 8
> 2026-04-17 07:30:46.894: child pid 1475041: DEBUG:  pool_read: read 1
> bytes from backend 0
> 2026-04-17 07:30:46.894: child pid 1475041: DEBUG:  attempting to
> negotiate a secure connection
> 2026-04-17 07:30:46.894: child pid 1475041: DETAIL:  client->server SSL
> response: S
> 2026-04-17 07:30:46.899: child pid 1475041: LOG:  pool_ssl: "SSL_connect":
> "certificate verify failed"
> 2026-04-17 07:30:46.899: child pid 1475041: DEBUG:  pool_flush_it: flush
> size: 58
> 2026-04-17 07:30:46.899: child pid 1475041: DEBUG:  pool_read: read 360
> bytes from backend 0
> 2026-04-17 07:30:46.900: child pid 1475041: ERROR:  backend authentication
> failed
> 2026-04-17 07:30:46.900: child pid 1475041: DETAIL:  backend response with
> kind ' ' when expecting 'R'
> 2026-04-17 07:30:46.900: child pid 1475041: DEBUG:  pool_write: to
> frontend: kind:E po:0
> 2026-04-17 07:30:46.900: child pid 1475041: DEBUG:  pool_write: to
> frontend: length:4 po:1
> 2026-04-17 07:30:46.900: child pid 1475041: DEBUG:  pool_write: to
> frontend: length:115 po:5
> 2026-04-17 07:30:46.900: child pid 1475041: DEBUG:  pool_flush_it: flush
> size: 120
>
> > Hi Tatsuo,
> >
> > Thank you for the report and the log, that was very helpful.
> >
> > The bug was in the test, not in the core patch. Test 4 in 042.ssl_reload
> > set PGSSLROOTCERT="$CADIR/ca1.crt" on both psql invocations. The intent
> was
> > to use ca1.crt for server-side client-certificate verification, but
> > PGSSLROOTCERT actually controls client-side server certificate
> > verification, and ca1.crt is a freshly generated CA that never signed
> > pgpool's server.crt. Because libpq upgrades sslmode=require to verify-ca
> > behavior when a root CA file is provided, psql immediately sent
> unknown_ca
> > back to pgpool and aborted the handshake before server-side client-cert
> > verification ever ran.
> >
> > Fix: both lines now use PGSSLROOTCERT="etc/$SSL_CRT". Since server.crt is
> > self-signed it acts as its own root, so psql accepts pgpool's server
> cert,
> > the handshake completes, and the test exercises what it was always meant
> to
> > test: whether pgpool enforces the new ssl_ca_cert after reload.
> >
> > No changes to the core patch.
> >
> > Please find v3 attached. Please let me know if it fixes the test issue.
> >
> > Best regards,
> > Bob
> >
> > On Thu, Apr 16, 2026 at 12:31 PM Tatsuo Ishii <[email protected]>
> wrote:
> >
> >> Hi Bob,
> >>
> >> Thank you for the patch!
> >>
> >> Unfortunately after applying the patch, the test failed. From
> >> src/test/regression/log/042.ssl_reload:
> >>
> >> ===== ssl_ca_cert swap (client cert auth reload) =====
> >> waiting for server to start....1462289 2026-04-16 19:25:49.490 JST LOG:
> >> redirecting log output to logging collector process
> >> 1462289 2026-04-16 19:25:49.490 JST HINT:  Future log output will appear
> >> in directory "log".
> >>  done
> >> server started
> >> CA cert swap: CA1-signed client cert rejected before reload –
> unexpected.
> >>
> >> From pgpool.log:
> >>
> >> 2026-04-16 19:26:10.150: child pid 1462331: DETAIL:  Protocol Major:
> 1234
> >> Minor: 5679 database:  user:
> >> 2026-04-16 19:26:10.150: child pid 1462331: DEBUG:  selecting backend
> >> connection
> >> 2026-04-16 19:26:10.150: child pid 1462331: DETAIL:  SSLRequest from
> client
> >> 2026-04-16 19:26:10.150: child pid 1462331: DEBUG:  pool_write: to
> >> frontend: kind:S po:0
> >> 2026-04-16 19:26:10.150: child pid 1462331: DEBUG:  pool_flush_it: flush
> >> size: 1
> >> 2026-04-16 19:26:10.167: child pid 1462331: LOG:  pool_ssl:
> "SSL_accept":
> >> "tlsv1 alert unknown ca"
> >> 2026-04-16 19:26:10.167: child pid 1462331: DEBUG:  unable to read data
> >> from frontend
> >> 2026-04-16 19:26:10.167: child pid 1462331: DETAIL:  socket read failed
> >> with error "Connection reset by peer"
> >>
> >> Please let me know if you need more info.
> >>
> >> Regards,
> >> --
> >> Tatsuo Ishii
> >> SRA OSS K.K.
> >> English: http://www.sraoss.co.jp/index_en/
> >> Japanese:http://www.sraoss.co.jp
> >>
> >> > Hi Tatsuo,
> >> >
> >> > Please see attached v2. It adds regression coverage for SSL cert
> reload
> >> > with client certificate authentication; there are no functional code
> >> > changes.
> >> >
> >> > Best regards,
> >> > Bob
> >> >
> >> >
> >> > On Tue, Apr 14, 2026 at 10:02 AM Tatsuo Ishii <[email protected]>
> >> wrote:
> >> >
> >> >> Hi Bob,
> >> >>
> >> >> > Hi Tatsuo,
> >> >> >
> >> >> > Please let me know if you need any assistance with updating your
> test
> >> >> > cases. I am be happy to help.
> >> >> >
> >> >> > Thanks,
> >> >> > Bob
> >> >>
> >> >> Sorry for late. I was busy with personal affairs and some other
> >> >> projects.
> >> >>
> >> >> > On Thu, Apr 2, 2026 at 9:57 PM Bob Ross <[email protected]>
> >> >> wrote:
> >> >> >
> >> >> >> Hi Tatsuo,
> >> >> >>
> >> >> >> Thanks for putting together the regression tests.
> >> >> >>
> >> >> >> Thoughts on your questions:
> >> >> >> - CA Certificates - Yes, adding a cert auth test is highly
> >> recommended.
> >> >> We
> >> >> >> could test this by generating two different dummy CA certificates.
> >> Start
> >> >> >> pgpool trusting CA #1, swap the config to CA #2, reload and
> verify if
> >> >> >> client connection correctly gets rejected.
> >> >>
> >> >> If you could extend the test file I posted so that it performs a cert
> >> >> auth test, that would be helpful.
> >> >>
> >> >> >> - DH parameters - perhaps we can test this by providing a
> >> non-existent
> >> >> >> file path and then use grep to check pgpool.log for specific
> warning
> >> >> >> message (per pool_ssl.c it’s “DH: could not load DH parameters”)
> when
> >> >> >> pgpool tries to load the file.
> >> >>
> >> >> I think it will not work.
> >> >>
> >> >> ===================================================================
> >> >> static bool
> >> >> initialize_dh(SSL_CTX *context)
> >> >> {
> >> >>         DH                 *dh = NULL;
> >> >>
> >> >>         SSL_CTX_set_options(context, SSL_OP_SINGLE_DH_USE);
> >> >>
> >> >>         if (pool_config->ssl_dh_params_file[0])
> >> >>                 dh = load_dh_file(pool_config->ssl_dh_params_file);
> >> >>         if (!dh)
> >> >>                 dh = load_dh_buffer(FILE_DH2048,
> sizeof(FILE_DH2048));
> >> >>         if (!dh)
> >> >>         {
> >> >>                 ereport(WARNING,
> >> >>                                 (errmsg("DH: could not load DH
> >> >> parameters")));
> >> >>                 return false;
> >> >>         }
> >> >> :
> >> >> :
> >> >> ===================================================================
> >> >>
> >> >> The ereport message is printed when the built-in DH parameter file is
> >> >> broken. But as long as the source file is fine, it would never
> happen.
> >> >>
> >> >> Maybe we should fix the code above so that it emits ereport when it
> >> >> fails to load the DH parameter file specified by ssl_dh_params_file?
> >> >>
> >> >> Regards,
> >> >> --
> >> >> Tatsuo Ishii
> >> >> SRA OSS K.K.
> >> >> English: http://www.sraoss.co.jp/index_en/
> >> >> Japanese:http://www.sraoss.co.jp
> >> >>
> >>
>


Attachments:

  [application/octet-stream] v4-0001-Feature-reload-SSL-certificates-on-SIGHUP-without.patch (28.4K, 3-v4-0001-Feature-reload-SSL-certificates-on-SIGHUP-without.patch)
  download | inline diff:
From c97fc6e9d4acb3f5071e473db3b34577f2498d59 Mon Sep 17 00:00:00 2001
From: Bob Ross <[email protected]>
Date: Thu, 17 Apr 2026 00:00:00 +0000
Subject: [PATCH v4] Feature: reload SSL certificates on SIGHUP without restart
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Allow Pgpool-II to pick up rotated TLS certificates (and any change to
SSL-related configuration) when receiving SIGHUP (i.e. systemctl reload
pgpool2), matching the behavior PostgreSQL has had since PostgreSQL 12.

Problem:
All SSL configuration parameters (ssl_cert, ssl_key, ssl_ca_cert,
ssl_ciphers, etc.) were declared CFGCXT_INIT, meaning they were silently
ignored when pool_get_config() was called under CFGCXT_RELOAD.
Furthermore, SSL_ServerSide_init() was only called once at startup in
main.c and never again, so the in-memory SSL_CTX was never refreshed.

Fix:
1. src/main/pgpool_main.c
   - Include utils/pool_ssl.h.
   - In reload_config(), call SSL_ServerSide_init() (guarded by
     #ifdef USE_SSL) *before* kill_all_children(SIGHUP).  The function
     already replaces SSL_frontend_context atomically: it frees the old
     SSL_CTX only after a new one has been created successfully, so a
     failed reload leaves the existing context intact.

2. src/protocol/child.c
   - In check_config_reload(), call SSL_ServerSide_init() (guarded by
     #ifdef USE_SSL) so each worker child also refreshes its own copy of
     the SSL context for subsequent new connections.  In-flight TLS
     sessions are unaffected because they hold a direct reference to the
     SSL object, not to SSL_frontend_context.

3. src/config/pool_config_variables.c
   - Change CFGCXT_INIT -> CFGCXT_RELOAD for:
       ssl_prefer_server_ciphers, ssl_cert, ssl_key, ssl_ca_cert,
       ssl_ca_cert_dir, ssl_crl_file, ssl_ciphers, ssl_ecdh_curve,
       ssl_dh_params_file, ssl_passphrase_command.
   - The 'ssl' boolean (master enable flag) is intentionally left as
     CFGCXT_INIT because dynamically enabling SSL at runtime is a
     larger, separate concern.

Usage after this change:
Standard in-place certificate rotation (cert-manager, ACME, manual
openssl refresh at the same path):

    # replace /etc/pgpool/server.{crt,key} with new files
    systemctl reload pgpool2
    # or: pgpool -f /etc/pgpool/pgpool.conf reload

New connections will use the new certificates after workers process
the reload signal. Existing connections are not interrupted.

Switching to a different certificate path also works: update
pgpool.conf then reload — the new paths are now accepted in
CFGCXT_RELOAD context.

Author: Bob Ross <[email protected]>
Reviewed-by: Tatsuo Ishii <[email protected]>
Discussion: https://www.postgresql.org/message-id/flat/CAHtZvrddqfbnERYY_DqgURWCjuXeTjM0y08k-ZP_B0bAHYx2ag%40mail.gmail.com
---
 src/config/pool_config_variables.c            |  20 +-
 src/main/pgpool_main.c                        |  17 ++
 src/protocol/child.c                          |  11 +
 .../regression/tests/042.ssl_reload/README    |   6 +
 .../tests/042.ssl_reload/server.crt           |  79 ++++++++
 .../tests/042.ssl_reload/server.key           |  27 +++
 .../tests/042.ssl_reload/server.req           |  61 ++++++
 .../regression/tests/042.ssl_reload/test.sh   | 290 ++++++++++++++++++++++++
 8 files changed, 433 insertions(+), 10 deletions(-)
 create mode 100644 src/test/regression/tests/042.ssl_reload/README
 create mode 100644 src/test/regression/tests/042.ssl_reload/server.crt
 create mode 100644 src/test/regression/tests/042.ssl_reload/server.key
 create mode 100644 src/test/regression/tests/042.ssl_reload/server.req
 create mode 100755 src/test/regression/tests/042.ssl_reload/test.sh

diff --git a/src/config/pool_config_variables.c b/src/config/pool_config_variables.c
index ce13c42f6..ca40c341a 100644
--- a/src/config/pool_config_variables.c
+++ b/src/config/pool_config_variables.c
@@ -705,7 +705,7 @@ static struct config_bool ConfigureNamesBool[] =
 	},
 
 	{
-		{"ssl_prefer_server_ciphers", CFGCXT_INIT, SSL_CONFIG,
+		{"ssl_prefer_server_ciphers", CFGCXT_RELOAD, SSL_CONFIG,
 			"Use server's SSL cipher preferences, rather than the client's",
 			CONFIG_VAR_TYPE_BOOL, false, 0
 		},
@@ -1271,7 +1271,7 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
-		{"ssl_cert", CFGCXT_INIT, SSL_CONFIG,
+		{"ssl_cert", CFGCXT_RELOAD, SSL_CONFIG,
 			"SSL public certificate file.",
 			CONFIG_VAR_TYPE_STRING, false, 0
 		},
@@ -1281,7 +1281,7 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
-		{"ssl_key", CFGCXT_INIT, SSL_CONFIG,
+		{"ssl_key", CFGCXT_RELOAD, SSL_CONFIG,
 			"SSL private key file.",
 			CONFIG_VAR_TYPE_STRING, false, 0
 		},
@@ -1291,7 +1291,7 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
-		{"ssl_ca_cert", CFGCXT_INIT, SSL_CONFIG,
+		{"ssl_ca_cert", CFGCXT_RELOAD, SSL_CONFIG,
 			"Single PEM format file containing CA root certificate(s).",
 			CONFIG_VAR_TYPE_STRING, false, 0
 		},
@@ -1301,7 +1301,7 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
-		{"ssl_ca_cert_dir", CFGCXT_INIT, SSL_CONFIG,
+		{"ssl_ca_cert_dir", CFGCXT_RELOAD, SSL_CONFIG,
 			"Directory containing CA root certificate(s).",
 			CONFIG_VAR_TYPE_STRING, false, 0
 		},
@@ -1311,7 +1311,7 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
-		{"ssl_crl_file", CFGCXT_INIT, SSL_CONFIG,
+		{"ssl_crl_file", CFGCXT_RELOAD, SSL_CONFIG,
 			"SSL certificate revocation list file",
 			CONFIG_VAR_TYPE_STRING, false, 0
 		},
@@ -1321,7 +1321,7 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
-		{"ssl_ciphers", CFGCXT_INIT, SSL_CONFIG,
+		{"ssl_ciphers", CFGCXT_RELOAD, SSL_CONFIG,
 			"Allowed SSL ciphers.",
 			CONFIG_VAR_TYPE_STRING, false, 0
 		},
@@ -1331,7 +1331,7 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
-		{"ssl_ecdh_curve", CFGCXT_INIT, SSL_CONFIG,
+		{"ssl_ecdh_curve", CFGCXT_RELOAD, SSL_CONFIG,
 			"The curve to use in ECDH key exchange.",
 			CONFIG_VAR_TYPE_STRING, false, 0
 		},
@@ -1341,7 +1341,7 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
-		{"ssl_dh_params_file", CFGCXT_INIT, SSL_CONFIG,
+		{"ssl_dh_params_file", CFGCXT_RELOAD, SSL_CONFIG,
 			"Path to the Diffie-Hellman parameters contained file",
 			CONFIG_VAR_TYPE_STRING, false, 0
 		},
@@ -1351,7 +1351,7 @@ static struct config_string ConfigureNamesString[] =
 	},
 
 	{
-		{"ssl_passphrase_command", CFGCXT_INIT, SSL_CONFIG,
+		{"ssl_passphrase_command", CFGCXT_RELOAD, SSL_CONFIG,
 			"Path to the Diffie-Hellman parameters contained file",
 			CONFIG_VAR_TYPE_STRING, false, 0
 		},
diff --git a/src/main/pgpool_main.c b/src/main/pgpool_main.c
index bf7c452e2..0a9c92826 100644
--- a/src/main/pgpool_main.c
+++ b/src/main/pgpool_main.c
@@ -61,6 +61,7 @@
 #include "watchdog/wd_lifecheck.h"
 #include "watchdog/watchdog.h"
 #include "pcp/pcp_worker.h"
+#include "utils/pool_ssl.h"
 #include <grp.h>
 
 /*
@@ -3489,6 +3490,22 @@ reload_config(void)
 	if (pool_config->enable_pool_hba)
 		load_hba(hba_file);
 
+#ifdef USE_SSL
+	/*
+	 * If SSL is enabled, re-initialize the SSL context so that new
+	 * connections pick up rotated certificates without requiring a restart.
+	 * SSL_ServerSide_init() is safe to call repeatedly: it frees and replaces
+	 * the existing SSL_CTX only on success, leaving the old context intact on
+	 * failure.
+	 */
+	if (pool_config->ssl)
+	{
+		ereport(LOG,
+				(errmsg("reload SSL certificates.")));
+		SSL_ServerSide_init();
+	}
+#endif							/* USE_SSL */
+
 	kill_all_children(SIGHUP);
 }
 
diff --git a/src/protocol/child.c b/src/protocol/child.c
index c34f05728..713bfe28f 100644
--- a/src/protocol/child.c
+++ b/src/protocol/child.c
@@ -1796,6 +1796,17 @@ check_config_reload(void)
 		if (strcmp("", pool_config->pool_passwd))
 			pool_reopen_passwd_file();
 
+#ifdef USE_SSL
+		/*
+		 * Re-initialize the frontend SSL context so this child process
+		 * serves new connections with any rotated certificates without a
+		 * restart.  In-flight TLS sessions are unaffected; they hold a
+		 * direct reference to the old SSL object.
+		 */
+		if (pool_config->ssl)
+			SSL_ServerSide_init();
+#endif						/* USE_SSL */
+
 		got_sighup = 0;
 	}
 }
diff --git a/src/test/regression/tests/042.ssl_reload/README b/src/test/regression/tests/042.ssl_reload/README
new file mode 100644
index 000000000..c73cf0bd3
--- /dev/null
+++ b/src/test/regression/tests/042.ssl_reload/README
@@ -0,0 +1,6 @@
+The sample server.key and server.crt was created by using following commands:
+
+openssl req -new -text -out server.req
+openssl rsa -in privkey.pem -out server.key
+rm privkey.pem
+openssl req -x509 -days 3650 -in server.req -text -key server.key -out server.crt
diff --git a/src/test/regression/tests/042.ssl_reload/server.crt b/src/test/regression/tests/042.ssl_reload/server.crt
new file mode 100644
index 000000000..90d5e08e7
--- /dev/null
+++ b/src/test/regression/tests/042.ssl_reload/server.crt
@@ -0,0 +1,79 @@
+Certificate:
+    Data:
+        Version: 3 (0x2)
+        Serial Number:
+            f4:86:4a:aa:50:42:63:dc
+    Signature Algorithm: sha256WithRSAEncryption
+        Issuer: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
+        Validity
+            Not Before: Aug 29 02:52:36 2018 GMT
+            Not After : Aug 26 02:52:36 2028 GMT
+        Subject: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:f4:e3:30:f0:09:e2:43:0e:a1:67:2e:3b:ef:b5:
+                    88:1e:4e:a9:06:fa:f2:94:8b:fa:4f:0a:9f:e0:57:
+                    45:95:2c:c1:18:1d:21:6d:c8:5c:2a:05:94:0b:c6:
+                    49:c5:97:88:ac:88:ba:73:fb:81:28:eb:e1:cd:7f:
+                    9d:fb:e0:c5:0d:ef:35:cc:12:b8:74:0b:a1:e9:65:
+                    d4:19:38:9b:a8:e1:c5:ef:d5:f1:9c:cf:8a:de:bf:
+                    fa:d7:6c:f9:d7:85:10:db:9f:e9:03:e9:7e:f1:81:
+                    de:9d:f3:b3:a3:6f:19:31:c8:bb:31:c0:e7:7d:ea:
+                    6b:02:98:21:7c:c2:f5:9d:0d:7c:85:2b:5d:81:7c:
+                    71:74:42:89:ab:5c:31:ac:19:fd:c2:0b:fb:e5:c2:
+                    b2:54:15:64:40:9c:bf:ed:d2:b1:bb:75:f9:e9:d8:
+                    67:b3:4e:63:c4:3e:f4:8a:2c:87:50:27:dd:22:97:
+                    f1:f7:26:49:87:03:55:08:a4:d2:44:21:e1:9a:33:
+                    82:96:09:b3:08:65:bc:a8:3a:f4:64:f3:60:62:d0:
+                    98:d9:82:0c:1b:be:b6:9c:22:e8:7f:e6:eb:20:d9:
+                    71:67:2c:d5:14:83:aa:f1:37:75:98:4c:68:1d:95:
+                    fe:1f:ec:cb:9b:17:9c:f4:92:22:da:bb:78:46:f3:
+                    de:7d
+                Exponent: 65537 (0x10001)
+        X509v3 extensions:
+            X509v3 Subject Key Identifier: 
+                68:ED:A7:FE:1E:36:26:18:80:2B:C6:A2:07:23:1C:A4:00:57:16:68
+            X509v3 Authority Key Identifier: 
+                keyid:68:ED:A7:FE:1E:36:26:18:80:2B:C6:A2:07:23:1C:A4:00:57:16:68
+
+            X509v3 Basic Constraints: critical
+                CA:TRUE
+    Signature Algorithm: sha256WithRSAEncryption
+         dd:61:62:83:6e:fa:e8:8a:1b:02:c6:9f:7f:f3:52:f8:04:5c:
+         c9:35:f9:4c:1d:4f:0f:9f:6c:a2:18:95:f0:76:93:e5:99:58:
+         4a:88:7a:54:68:cf:28:64:8e:01:3f:fb:7e:28:6f:ad:c6:08:
+         a2:09:77:4c:13:4b:1d:68:70:38:91:d4:dc:f7:c3:c8:81:36:
+         48:b9:01:46:f9:fa:e8:f7:ba:fe:23:4c:e3:27:a9:58:2d:a6:
+         3d:88:ac:b8:71:9b:84:ec:bd:82:c4:45:1d:ba:77:ed:73:54:
+         a9:16:76:80:40:0b:80:42:47:60:84:cf:41:e0:0f:8e:85:d3:
+         28:36:fb:f6:8c:f8:c6:20:b3:c4:06:cc:2d:6d:37:78:b4:d5:
+         4d:14:db:f0:04:56:66:d8:5a:cc:ff:bd:0c:19:6d:39:bf:26:
+         ac:17:0c:91:a4:68:4b:bc:86:4f:0a:10:81:b5:ac:1e:a6:78:
+         b1:7f:e9:f3:9e:1b:32:92:b2:8f:f7:e2:a3:ae:44:e2:99:b0:
+         04:0a:15:eb:7a:37:10:b2:7b:ef:35:6c:a5:db:13:96:42:e9:
+         22:3c:72:6a:34:16:0d:b5:2c:49:f3:83:c7:ff:da:ec:57:14:
+         ab:0d:8d:76:8f:f0:a2:21:4f:88:54:bc:2f:c6:b9:7b:8c:da:
+         42:9a:b1:12
+-----BEGIN CERTIFICATE-----
+MIIDYDCCAkigAwIBAgIJAPSGSqpQQmPcMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQwHhcNMTgwODI5MDI1MjM2WhcNMjgwODI2MDI1MjM2WjBF
+MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
+ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA9OMw8AniQw6hZy4777WIHk6pBvrylIv6Twqf4FdFlSzBGB0hbchcKgWU
+C8ZJxZeIrIi6c/uBKOvhzX+d++DFDe81zBK4dAuh6WXUGTibqOHF79XxnM+K3r/6
+12z514UQ25/pA+l+8YHenfOzo28ZMci7McDnfeprApghfML1nQ18hStdgXxxdEKJ
+q1wxrBn9wgv75cKyVBVkQJy/7dKxu3X56dhns05jxD70iiyHUCfdIpfx9yZJhwNV
+CKTSRCHhmjOClgmzCGW8qDr0ZPNgYtCY2YIMG762nCLof+brINlxZyzVFIOq8Td1
+mExoHZX+H+zLmxec9JIi2rt4RvPefQIDAQABo1MwUTAdBgNVHQ4EFgQUaO2n/h42
+JhiAK8aiByMcpABXFmgwHwYDVR0jBBgwFoAUaO2n/h42JhiAK8aiByMcpABXFmgw
+DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEA3WFig2766IobAsaf
+f/NS+ARcyTX5TB1PD59sohiV8HaT5ZlYSoh6VGjPKGSOAT/7fihvrcYIogl3TBNL
+HWhwOJHU3PfDyIE2SLkBRvn66Pe6/iNM4yepWC2mPYisuHGbhOy9gsRFHbp37XNU
+qRZ2gEALgEJHYITPQeAPjoXTKDb79oz4xiCzxAbMLW03eLTVTRTb8ARWZthazP+9
+DBltOb8mrBcMkaRoS7yGTwoQgbWsHqZ4sX/p854bMpKyj/fio65E4pmwBAoV63o3
+ELJ77zVspdsTlkLpIjxyajQWDbUsSfODx//a7FcUqw2Ndo/woiFPiFS8L8a5e4za
+QpqxEg==
+-----END CERTIFICATE-----
diff --git a/src/test/regression/tests/042.ssl_reload/server.key b/src/test/regression/tests/042.ssl_reload/server.key
new file mode 100644
index 000000000..0ddd69303
--- /dev/null
+++ b/src/test/regression/tests/042.ssl_reload/server.key
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEA9OMw8AniQw6hZy4777WIHk6pBvrylIv6Twqf4FdFlSzBGB0h
+bchcKgWUC8ZJxZeIrIi6c/uBKOvhzX+d++DFDe81zBK4dAuh6WXUGTibqOHF79Xx
+nM+K3r/612z514UQ25/pA+l+8YHenfOzo28ZMci7McDnfeprApghfML1nQ18hStd
+gXxxdEKJq1wxrBn9wgv75cKyVBVkQJy/7dKxu3X56dhns05jxD70iiyHUCfdIpfx
+9yZJhwNVCKTSRCHhmjOClgmzCGW8qDr0ZPNgYtCY2YIMG762nCLof+brINlxZyzV
+FIOq8Td1mExoHZX+H+zLmxec9JIi2rt4RvPefQIDAQABAoIBAD6EfaraKxxJcOUh
+hYWlx3FNTZONnz5TGfzxzmz8erQhr84TKcSYIQdNU0VKQu0hyW+anFcdvxSOW6AV
+02RJNqVfC1Hk+ZgOnDA0odgqfnq34MtgyATrax2Az24N0R63Rt16zocEJjdLm2Sh
+oZu4sirmfvutrquTm+wWoH30W7XTCrd17thq8+5VBumXLW4sr40PWXcfPC1Od7JH
+utYZ0lGxr89fhuPpnpLw7V67EdslwmYl8avhzrUlzkXPqufZ33XdWFi/IXoNjMZ2
+MFgZFNKHv682nqjrrodyn4iXEzMSj4z4QLTNxoH79HWvCb2HjUpEWTNrfdu3LNCZ
+FahqHmECgYEA/5MmEEB2GNlhaMP+NMK/3x9RCfDfleqEdExf0KA6TuISNYUgeEeB
+dfczCN8WtxyDMor6fvwINxEAHX64/CompE/ya+Z25VdBQMcLpNVGS01aDdrqWN5B
+4qG8OyK3+eAjCnvyCzWsvvpK1I5u65q6+Q+Cw1wQaxYzhsZkEazQ0OkCgYEA9Ut9
+m74RMGudjkvJK7JIPLDLGEsko+yrh8IuoGn/wLpUJwmkZFQu8HRqdddMVjwQi4CN
+IDScbvyH0uE2yN+gg/BB0eBIyhfrI3xl6FJIQBnI0/7wmb2U82OT0LS18h9n8dAK
++mONcR3zL7XDe8xy1qTS0jjd1QT1QS4YLGPCxHUCgYEAowftCgT00NkqaDhOWr24
+w84oVd0P44QcRkvJ+z2atGNGFln74n5KuUOdjJUy2lAX6Q/6xzJi0y3HEwmZW1JQ
+IBTXobj8M0Q73eSbKuTZ2INZZOk3AMWW5ckiV97H2V//OlrihgARWCo1ve22GBk2
+GFaqpZB+8LDS4bCAeT3yXrECgYEA5rZ3USonLry5d2JOt5u7F+JNU+8xakErYMhC
+ZLzuQY6/oewOxBLuB1nn3CiBc0aRZTSnCFiTnkxFUBJmHe9AIXiz37wtmm9+yWSy
+0R27ORdHbiYGlQPcekP5fr7Jtw7VDHraKIHEQlWiKwix8dntVXe3luTHuRktuH2r
+XO0D/xUCgYEAlQtXyGSl/taUjKyfvfxlFDtpOwBAwUj2CsNzeUd2/5aWkqUrtYz8
+JNCPgSLPKDhLpavH0vUEmftF3uDVPxvMQ4JG9MQ7meHgL7AZmtKdU0VI+Av9xiJe
+d7A1x6o88gv1TqvGRit2qRxNOT0mzhDcXuR2EIQqUav45NyBokSo9xw=
+-----END RSA PRIVATE KEY-----
diff --git a/src/test/regression/tests/042.ssl_reload/server.req b/src/test/regression/tests/042.ssl_reload/server.req
new file mode 100644
index 000000000..fdfd5235d
--- /dev/null
+++ b/src/test/regression/tests/042.ssl_reload/server.req
@@ -0,0 +1,61 @@
+Certificate Request:
+    Data:
+        Version: 1 (0x0)
+        Subject: C = AU, ST = Some-State, O = Internet Widgits Pty Ltd
+        Subject Public Key Info:
+            Public Key Algorithm: rsaEncryption
+                Public-Key: (2048 bit)
+                Modulus:
+                    00:f4:e3:30:f0:09:e2:43:0e:a1:67:2e:3b:ef:b5:
+                    88:1e:4e:a9:06:fa:f2:94:8b:fa:4f:0a:9f:e0:57:
+                    45:95:2c:c1:18:1d:21:6d:c8:5c:2a:05:94:0b:c6:
+                    49:c5:97:88:ac:88:ba:73:fb:81:28:eb:e1:cd:7f:
+                    9d:fb:e0:c5:0d:ef:35:cc:12:b8:74:0b:a1:e9:65:
+                    d4:19:38:9b:a8:e1:c5:ef:d5:f1:9c:cf:8a:de:bf:
+                    fa:d7:6c:f9:d7:85:10:db:9f:e9:03:e9:7e:f1:81:
+                    de:9d:f3:b3:a3:6f:19:31:c8:bb:31:c0:e7:7d:ea:
+                    6b:02:98:21:7c:c2:f5:9d:0d:7c:85:2b:5d:81:7c:
+                    71:74:42:89:ab:5c:31:ac:19:fd:c2:0b:fb:e5:c2:
+                    b2:54:15:64:40:9c:bf:ed:d2:b1:bb:75:f9:e9:d8:
+                    67:b3:4e:63:c4:3e:f4:8a:2c:87:50:27:dd:22:97:
+                    f1:f7:26:49:87:03:55:08:a4:d2:44:21:e1:9a:33:
+                    82:96:09:b3:08:65:bc:a8:3a:f4:64:f3:60:62:d0:
+                    98:d9:82:0c:1b:be:b6:9c:22:e8:7f:e6:eb:20:d9:
+                    71:67:2c:d5:14:83:aa:f1:37:75:98:4c:68:1d:95:
+                    fe:1f:ec:cb:9b:17:9c:f4:92:22:da:bb:78:46:f3:
+                    de:7d
+                Exponent: 65537 (0x10001)
+        Attributes:
+            a0:00
+    Signature Algorithm: sha256WithRSAEncryption
+         7a:30:69:6c:aa:30:6f:f3:bc:dc:85:78:04:ef:f6:0c:b2:04:
+         e7:03:55:fd:4a:98:74:d6:fd:24:a1:e9:e8:3d:e3:a1:b0:dc:
+         12:b9:1f:38:fe:9e:42:5a:0c:06:b8:0c:f6:65:0b:78:95:73:
+         27:31:14:e5:4d:4f:e2:82:3f:52:24:45:ba:31:e7:87:b7:c8:
+         b9:8a:db:5f:5e:fd:1a:f2:6c:7d:d6:d1:1d:19:77:5e:10:51:
+         d3:24:7f:5a:7d:3f:eb:db:33:0b:27:97:72:b9:f0:ea:89:79:
+         ca:b7:23:7c:c0:8a:e9:11:30:45:99:09:58:da:08:86:28:32:
+         21:c0:3f:2e:87:3e:a4:96:55:f1:65:72:4f:06:0b:b3:a1:97:
+         7d:54:6c:0d:96:b4:41:11:6e:28:45:cb:16:d7:1e:70:1e:a8:
+         a2:4e:7f:65:8e:71:e9:05:e2:ad:cc:9a:79:1d:73:39:e8:f0:
+         e8:f3:75:ab:bf:9d:44:7b:b7:76:3f:0d:50:e0:9c:ef:2c:d5:
+         eb:c3:0d:4f:c1:77:af:56:7e:78:db:e8:a0:52:05:f6:49:89:
+         ab:c0:ff:d6:97:9d:9d:84:14:12:73:ee:31:1d:12:ad:e7:91:
+         8d:ac:ff:ee:8d:18:07:be:c8:ec:57:9d:78:41:9c:1e:a1:75:
+         2b:99:f7:70
+-----BEGIN CERTIFICATE REQUEST-----
+MIICijCCAXICAQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUx
+ITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDCCASIwDQYJKoZIhvcN
+AQEBBQADggEPADCCAQoCggEBAPTjMPAJ4kMOoWcuO++1iB5OqQb68pSL+k8Kn+BX
+RZUswRgdIW3IXCoFlAvGScWXiKyIunP7gSjr4c1/nfvgxQ3vNcwSuHQLoell1Bk4
+m6jhxe/V8ZzPit6/+tds+deFENuf6QPpfvGB3p3zs6NvGTHIuzHA533qawKYIXzC
+9Z0NfIUrXYF8cXRCiatcMawZ/cIL++XCslQVZECcv+3Ssbt1+enYZ7NOY8Q+9Ios
+h1An3SKX8fcmSYcDVQik0kQh4ZozgpYJswhlvKg69GTzYGLQmNmCDBu+tpwi6H/m
+6yDZcWcs1RSDqvE3dZhMaB2V/h/sy5sXnPSSItq7eEbz3n0CAwEAAaAAMA0GCSqG
+SIb3DQEBCwUAA4IBAQB6MGlsqjBv87zchXgE7/YMsgTnA1X9Sph01v0koenoPeOh
+sNwSuR84/p5CWgwGuAz2ZQt4lXMnMRTlTU/igj9SJEW6MeeHt8i5ittfXv0a8mx9
+1tEdGXdeEFHTJH9afT/r2zMLJ5dyufDqiXnKtyN8wIrpETBFmQlY2giGKDIhwD8u
+hz6kllXxZXJPBguzoZd9VGwNlrRBEW4oRcsW1x5wHqiiTn9ljnHpBeKtzJp5HXM5
+6PDo83Wrv51Ee7d2Pw1Q4JzvLNXrww1PwXevVn542+igUgX2SYmrwP/Wl52dhBQS
+c+4xHRKt55GNrP/ujRgHvsjsV514QZweoXUrmfdw
+-----END CERTIFICATE REQUEST-----
diff --git a/src/test/regression/tests/042.ssl_reload/test.sh b/src/test/regression/tests/042.ssl_reload/test.sh
new file mode 100755
index 000000000..302216878
--- /dev/null
+++ b/src/test/regression/tests/042.ssl_reload/test.sh
@@ -0,0 +1,290 @@
+#!/usr/bin/env bash
+#-------------------------------------------------------------------
+# test script for SSL connection upon reloading for: frontend <--> Pgpool-II and Pgpool-II and PostgreSQL.
+#
+source $TESTLIBS
+TESTDIR=testdir
+PSQL=$PGBIN/psql
+PG_CTL=$PGBIN/pg_ctl
+export PGDATABASE=test
+SSL_KEY=server.key
+SSL_CRT=server.crt
+
+#-------------------------------------------
+# Check psql output for \conninfo to see if SSL enabled
+#-------------------------------------------
+function check_ssl {
+    $PSQL -h localhost test <<EOF > result
+\conninfo
+\q
+EOF
+
+    # PostgreSQL 18 or later prints tablular output for \conninfo.
+    # For SSL, "SSL Connection | true (or false)"
+    if [ $PGVERSION -ge 18 ];then
+	grep "SSL Connection" result|grep true
+    else
+	grep SSL result
+    fi
+}
+
+# ---------------------------------------------------------------
+# Test ssl configuration param.
+# params:
+# $1: configuration name. e.g. ssl_cert
+# $2: good value for the config
+#
+# This performs following tests:
+# 1. Set bad value to the config and restart pgpool to make sure SSL connection does not establish.
+# 2. Set good value to the config and reload to make sure SSL connection establishes.
+# If test fails, exit with status 1
+function test_ssl {
+    # set bad value
+    echo "$1 = 'bad_value'" >> etc/pgpool.conf
+    # restart pgpool
+    ./startall
+    wait_for_pgpool_startup
+    check_ssl
+    if [ $? = 0 ];then
+	echo "Checking SSL connection between frontend and Pgpool-II succeeded despite bad config value for $1"
+	./shutdownall
+	exit 1
+    fi
+    echo "Checking SSL connection between frontend and Pgpool-II failed due to bad config value for $1 as expected."
+
+    # Make sure that SSL connection succeeds with good config value
+    echo "$1 = '$2'" >> etc/pgpool.conf
+    ./pgpool_reload
+    sleep 1
+    check_ssl
+    if [ $? = 0 ];then
+	echo "Checking SSL connection between frontend and Pgpool-II succeeded with good $1"
+    else
+	echo "Checking SSL connection between frontend and Pgpool-II failed with good $1"
+	./shutdownall
+	exit 1
+    fi
+    ./shutdownall
+}
+
+# main script starts here
+rm -fr $TESTDIR
+mkdir $TESTDIR
+cd $TESTDIR
+
+# create test environment. Number of backend node is 1 is enough.
+echo -n "creating test environment..."
+$PGPOOL_SETUP -m s -n 1 || exit 1
+echo "done."
+
+# setup SSL key and crt file
+cp -p ../$SSL_KEY etc/
+chmod og-rwx etc/$SSL_KEY
+cp -p ../$SSL_CRT etc/
+cp -p ../$SSL_KEY data0/
+chmod og-rwx data0/$SSL_KEY
+cp -p ../$SSL_CRT data0/
+
+# enable SSL support
+dir=`pwd`
+
+echo "ssl = on" >> etc/pgpool.conf
+echo "ssl_key = '$SSL_KEY'" >> etc/pgpool.conf
+echo "ssl_cert = '$SSL_CRT'" >> etc/pgpool.conf
+echo "ssl_prefer_server_ciphers = on" >> etc/pgpool.conf
+echo "ssl_ciphers = 'EECDH:HIGH:MEDIUM:+3DES:!aNULL'" >> etc/pgpool.conf
+
+echo "ssl = on" >> data0/postgresql.conf
+echo "ssl_cert_file = '$SSL_CRT'" >> data0/postgresql.conf
+echo "ssl_key_file = '$SSL_KEY'" >> data0/postgresql.conf
+
+# backend must be connected via TCP/IP
+echo "backend_hostname0 = 'localhost'" >> etc/pgpool.conf
+
+# produce debug message since the only way to confirm the SSL
+# connections is being established is, look into the debug log.
+echo "log_min_messages = debug5" >> etc/pgpool.conf
+
+# allow to access IPv6 localhost
+echo "host    all             all             ::1/128                 trust" >> data0/pg_hba.conf
+
+source ./bashrc.ports
+
+./startall
+
+export PGPORT=$PGPOOL_PORT
+
+wait_for_pgpool_startup
+
+# first, checking frontend<-->Pgpool-II...
+check_ssl
+if [ $? != 0 ];then
+    echo "Checking SSL connection between frontend and Pgpool-II failed."
+    ./shutdownall
+    exit 1
+fi
+echo "Checking SSL connection between frontend and Pgpool-II was ok."
+
+if [ $PGVERSION -ge 18 ];then
+    grep "SSL Protocol" result|grep TLSv1.2
+else
+    grep SSL result |grep TLSv1.2
+fi
+
+# if SSl protocol version TLSv1.2
+if [ $? = 0 ];then
+    grep SSL result |grep ECDH
+
+    if [ $? != 0 ];then
+        echo "Checking SSL connection with ECDH between frontend and Pgpool-II failed."
+        ./shutdownall
+        exit 1
+    fi
+	echo "Checking SSL connection with ECDH between frontend and Pgpool-II was ok."
+fi
+
+grep "client->server SSL response: S" log/pgpool.log >/dev/null
+if [ $? != 0 ];then
+    echo "Checking SSL connection between Pgpool-II and backend failed."
+    ./shutdownall
+    exit 1
+fi
+echo "Checking SSL connection between Pgpool-II and backend was ok."
+
+# So far SSL connection between clients and Pgpool-II, Pgpool-II and backend are ok.
+
+./shutdownall
+
+# ---------------------------------------------------------------
+# Test SSL params
+
+config_names[0]=ssl_cert
+config_names[1]=ssl_ciphers
+config_names[2]=ssl_crl_file
+config_names[3]=ssl_dh_params_file	# ssl_dh_params_file can be a invalid file (fallback mechanism)
+config_names[4]=ssl_ecdh_curve
+config_names[5]=ssl_key
+config_names[6]=ssl_passphrase_command	# cert does not require pass passphrase
+config_names[7]=ssl_prefer_server_ciphers	# this affects server side ciphers
+
+good_values[0]=server.crt
+good_values[1]=HIGH:MEDIUM:+3DES:!aNULL
+good_values[2]=""
+good_values[3]=skip
+good_values[4]=prime256v1
+good_values[5]=server.key
+good_values[6]=skip
+good_values[7]=skip
+
+for i in {0..7}
+do
+    echo "===== ${config_names[$i]} ====="
+    if [ "${good_values[$i]}" = "skip" ];then
+	echo "skip this test"
+    else
+	test_ssl ${config_names[$i]} ${good_values[$i]}
+    fi
+done
+
+# ---------------------------------------------------------------
+# Test 4: ssl_ca_cert swap – client cert rejected after CA rotation
+#
+# 1. Two independent self-signed CAs are generated (CA #1 / CA #2).
+# 2. A client certificate is signed with CA #1.
+# 3. pgpool starts trusting CA #1 with pool_hba.conf set to require
+#    client-certificate authentication (cert method).
+# 4. Verify the CA1-signed client cert is accepted.
+# 5. Reload pgpool with ssl_ca_cert pointing at CA #2.
+# 6. Verify the same client cert is now rejected because its issuer
+#    (CA #1) is no longer trusted.
+# ---------------------------------------------------------------
+echo "===== ssl_ca_cert swap (client cert auth reload) ====="
+
+CADIR=`pwd`/catest
+mkdir -p "$CADIR"
+
+openssl req -new -x509 -days 3650 -nodes \
+    -subj "/CN=TestCA1" \
+    -keyout "$CADIR/ca1.key" -out "$CADIR/ca1.crt" 2>/dev/null
+
+openssl req -new -x509 -days 3650 -nodes \
+    -subj "/CN=TestCA2" \
+    -keyout "$CADIR/ca2.key" -out "$CADIR/ca2.crt" 2>/dev/null
+
+openssl req -new -nodes \
+    -subj "/CN=ssltest" \
+    -keyout "$CADIR/client.key" -out "$CADIR/client.csr" 2>/dev/null
+openssl x509 -req -days 3650 \
+    -CA "$CADIR/ca1.crt" -CAkey "$CADIR/ca1.key" -CAcreateserial \
+    -in "$CADIR/client.csr" -out "$CADIR/client.crt" 2>/dev/null
+chmod 600 "$CADIR/client.key"
+
+# Generate a dedicated server CA and a new backend cert (with SAN for localhost)
+# signed by it.  This CA is stable across the two reload phases so pgpool can
+# always verify the backend, while ca1/ca2 are swapped to control client-cert
+# trust.  ca1.crt and ca2.crt are used only for client-certificate auth.
+openssl req -new -x509 -days 3650 -nodes \
+    -subj "/CN=TestServerCA" \
+    -keyout "$CADIR/server_ca.key" -out "$CADIR/server_ca.crt" 2>/dev/null
+
+openssl req -new -nodes \
+    -subj "/CN=localhost" \
+    -addext "subjectAltName=DNS:localhost,IP:127.0.0.1" \
+    -keyout "$CADIR/backend.key" -out "$CADIR/backend.csr" 2>/dev/null
+openssl x509 -req -days 3650 \
+    -CA "$CADIR/server_ca.crt" -CAkey "$CADIR/server_ca.key" -CAcreateserial \
+    -extfile <(echo "subjectAltName=DNS:localhost,IP:127.0.0.1") \
+    -in "$CADIR/backend.csr" -out "$CADIR/backend.crt" 2>/dev/null
+chmod 600 "$CADIR/backend.key"
+
+# Replace the static server.crt/server.key with the new CA-signed cert so that
+# both pgpool (frontend SSL) and PostgreSQL (backend SSL) use it.
+cp "$CADIR/backend.crt" etc/$SSL_CRT
+cp "$CADIR/backend.key" etc/$SSL_KEY
+chmod og-rwx etc/$SSL_KEY
+cp "$CADIR/backend.crt" data0/$SSL_CRT
+cp "$CADIR/backend.key" data0/$SSL_KEY
+chmod og-rwx data0/$SSL_KEY
+
+# CA bundles: server_ca (verifies backend) + client CA (verifies client cert).
+cat "$CADIR/server_ca.crt" "$CADIR/ca1.crt" > "$CADIR/combined_ca1.crt"
+cat "$CADIR/server_ca.crt" "$CADIR/ca2.crt" > "$CADIR/combined_ca2.crt"
+
+echo "ssl_ca_cert = '$CADIR/combined_ca1.crt'" >> etc/pgpool.conf
+echo "enable_pool_hba = on" >> etc/pgpool.conf
+cat >> etc/pool_hba.conf <<'HBA'
+hostssl all ssltest 127.0.0.1/32 cert
+hostssl all ssltest ::1/128 cert
+HBA
+
+./startall
+wait_for_pgpool_startup
+
+$PSQL -h localhost -p $PGPOOL_PORT test -c "CREATE ROLE ssltest LOGIN" 2>/dev/null ||:
+
+PGSSLMODE=require PGSSLCERT="$CADIR/client.crt" PGSSLKEY="$CADIR/client.key" \
+    PGSSLROOTCERT="$CADIR/server_ca.crt" $PSQL -h localhost -U ssltest test -c "SELECT 1" >/dev/null 2>&1
+if [ $? = 0 ]; then
+    echo "CA cert swap: CA1-signed client cert accepted before reload – ok."
+else
+    echo "CA cert swap: CA1-signed client cert rejected before reload – unexpected."
+    ./shutdownall
+    exit 1
+fi
+
+echo "ssl_ca_cert = '$CADIR/combined_ca2.crt'" >> etc/pgpool.conf
+./pgpool_reload
+sleep 1
+
+PGSSLMODE=require PGSSLCERT="$CADIR/client.crt" PGSSLKEY="$CADIR/client.key" \
+    PGSSLROOTCERT="$CADIR/server_ca.crt" $PSQL -h localhost -U ssltest test -c "SELECT 1" >/dev/null 2>&1
+if [ $? != 0 ]; then
+    echo "CA cert swap: CA1-signed client cert rejected after reload to CA2 – ok."
+else
+    echo "CA cert swap: CA1-signed client cert still accepted after CA2 reload – unexpected."
+    ./shutdownall
+    exit 1
+fi
+
+./shutdownall
+exit 0
-- 
2.43.0

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected], [email protected]
  Subject: Re: Rotate SSL certificates on reload (SIGHUP) without restart
  In-Reply-To: <CAHtZvrcgCbM8=xTdxhdm_qOnQ4=ttAJpB_amTdG8r4NzcukYAQ@mail.gmail.com>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox