From 223a2aa1ed53c4dc03656be8742a7238147f3627 Mon Sep 17 00:00:00 2001 From: Hemant Dangi Date: Tue, 7 Jul 2026 15:31:57 +0530 Subject: [PATCH] MDEV-23744: Unable to specify both client and server certificates. Issue: The SST TLS options are not role-specific, so a node cannot present a different certificate as donor (TLS client) than as joiner (TLS server), which some environments require. Solution: In the shared check_server_ssl_config, add role-specific options that override the generic ones: ssl-server-{ca,capath,cert,key} for the joiner and ssl-client-{ca,capath,cert,key} for the donor. Applies to both mariabackup and rsync SST. --- ...lera_sst_mariabackup_ssl_role_certs.result | 8 ++++ .../r/galera_sst_rsync_ssl_role_certs.result | 8 ++++ .../galera_sst_mariabackup_ssl_role_certs.cnf | 18 +++++++++ ...galera_sst_mariabackup_ssl_role_certs.test | 40 +++++++++++++++++++ .../t/galera_sst_rsync_ssl_role_certs.cnf | 16 ++++++++ .../t/galera_sst_rsync_ssl_role_certs.test | 40 +++++++++++++++++++ scripts/wsrep_sst_common.sh | 14 +++++++ 7 files changed, 144 insertions(+) create mode 100644 mysql-test/suite/galera/r/galera_sst_mariabackup_ssl_role_certs.result create mode 100644 mysql-test/suite/galera/r/galera_sst_rsync_ssl_role_certs.result create mode 100644 mysql-test/suite/galera/t/galera_sst_mariabackup_ssl_role_certs.cnf create mode 100644 mysql-test/suite/galera/t/galera_sst_mariabackup_ssl_role_certs.test create mode 100644 mysql-test/suite/galera/t/galera_sst_rsync_ssl_role_certs.cnf create mode 100644 mysql-test/suite/galera/t/galera_sst_rsync_ssl_role_certs.test diff --git a/mysql-test/suite/galera/r/galera_sst_mariabackup_ssl_role_certs.result b/mysql-test/suite/galera/r/galera_sst_mariabackup_ssl_role_certs.result new file mode 100644 index 0000000000000..9abeb1602a0d0 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_sst_mariabackup_ssl_role_certs.result @@ -0,0 +1,8 @@ +connection node_2; +connection node_1; +connection node_1; +connection node_2; +connection node_2; +connection node_1; +connection node_2; +include/assert_grep.inc [SST used OpenSSL-based encryption] diff --git a/mysql-test/suite/galera/r/galera_sst_rsync_ssl_role_certs.result b/mysql-test/suite/galera/r/galera_sst_rsync_ssl_role_certs.result new file mode 100644 index 0000000000000..519261e10bd61 --- /dev/null +++ b/mysql-test/suite/galera/r/galera_sst_rsync_ssl_role_certs.result @@ -0,0 +1,8 @@ +connection node_2; +connection node_1; +connection node_1; +connection node_2; +connection node_2; +connection node_1; +connection node_2; +include/assert_grep.inc [SST used stunnel for SSL encryption] diff --git a/mysql-test/suite/galera/t/galera_sst_mariabackup_ssl_role_certs.cnf b/mysql-test/suite/galera/t/galera_sst_mariabackup_ssl_role_certs.cnf new file mode 100644 index 0000000000000..66fbb1dde79d9 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_sst_mariabackup_ssl_role_certs.cnf @@ -0,0 +1,18 @@ +!include ../galera_2nodes.cnf + +# Role-specific SSL certificates for SST: the joiner (TLS server) uses +# the server cert/key, the donor (TLS client) uses the client cert/key. +# No generic ssl-cert/ssl-key is set, so SST can only succeed if the +# role-specific options are honored. +[mysqld] +wsrep_sst_method=mariabackup +wsrep_sst_auth="root:" +wsrep_debug=1 +ssl-ca=@ENV.MYSQL_TEST_DIR/std_data/cacert.pem + +[sst] +ssl-mode=VERIFY_CA +ssl-server-cert=@ENV.MYSQL_TEST_DIR/std_data/server-cert.pem +ssl-server-key=@ENV.MYSQL_TEST_DIR/std_data/server-key.pem +ssl-client-cert=@ENV.MYSQL_TEST_DIR/std_data/client-cert.pem +ssl-client-key=@ENV.MYSQL_TEST_DIR/std_data/client-key.pem diff --git a/mysql-test/suite/galera/t/galera_sst_mariabackup_ssl_role_certs.test b/mysql-test/suite/galera/t/galera_sst_mariabackup_ssl_role_certs.test new file mode 100644 index 0000000000000..85454f11fedf8 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_sst_mariabackup_ssl_role_certs.test @@ -0,0 +1,40 @@ +# +# mariabackup SST honors separate client/server SSL certificates by role. +# +# STEPS: +# - Start a 2-node cluster with only role-specific SST certificates set +# (joiner=server cert/key, donor=client cert/key), no generic ssl-cert. +# - Force node 2 to rejoin via a fresh SST. +# - Confirm node 2 rejoins and the transfer was OpenSSL-encrypted. +# +--source include/galera_cluster.inc +--source include/have_innodb.inc +--source include/have_mariabackup.inc + +--let $node_1=node_1 +--let $node_2=node_2 +--source include/auto_increment_offset_save.inc + +--connection node_2 +--source include/shutdown_mysqld.inc + +# Force a fresh SST on node 2. +--remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat + +--source include/start_mysqld.inc +--source include/wait_until_connected_again.inc + +--connection node_1 +--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size' +--source include/wait_condition.inc + +# The joiner must have used OpenSSL-based transfer for the SST. +--connection node_2 +--let $assert_text = SST used OpenSSL-based encryption +--let $assert_select = Using openssl based encryption with socat +--let $assert_match = Using openssl based encryption with socat +--let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.2.err +--let $assert_only_after = CURRENT_TEST +--source include/assert_grep.inc + +--source include/auto_increment_offset_restore.inc diff --git a/mysql-test/suite/galera/t/galera_sst_rsync_ssl_role_certs.cnf b/mysql-test/suite/galera/t/galera_sst_rsync_ssl_role_certs.cnf new file mode 100644 index 0000000000000..6ad9285c6f880 --- /dev/null +++ b/mysql-test/suite/galera/t/galera_sst_rsync_ssl_role_certs.cnf @@ -0,0 +1,16 @@ +!include ../galera_2nodes.cnf + +# Role-specific SSL certificates for rsync/stunnel SST: the joiner +# (stunnel server) uses the server cert/key, the donor (stunnel client) +# uses the client cert/key. No generic ssl-cert/ssl-key is set, so SST +# can only succeed if the role-specific options are honored. +[mysqld] +wsrep_sst_method=rsync +ssl-ca=@ENV.MYSQL_TEST_DIR/std_data/cacert.pem + +[sst] +ssl-mode=VERIFY_CA +ssl-server-cert=@ENV.MYSQL_TEST_DIR/std_data/server-cert.pem +ssl-server-key=@ENV.MYSQL_TEST_DIR/std_data/server-key.pem +ssl-client-cert=@ENV.MYSQL_TEST_DIR/std_data/client-cert.pem +ssl-client-key=@ENV.MYSQL_TEST_DIR/std_data/client-key.pem diff --git a/mysql-test/suite/galera/t/galera_sst_rsync_ssl_role_certs.test b/mysql-test/suite/galera/t/galera_sst_rsync_ssl_role_certs.test new file mode 100644 index 0000000000000..1d5490201b88d --- /dev/null +++ b/mysql-test/suite/galera/t/galera_sst_rsync_ssl_role_certs.test @@ -0,0 +1,40 @@ +# +# rsync SST honors separate client/server SSL certificates by role. +# +# STEPS: +# - Start a 2-node cluster with only role-specific SST certificates set +# (joiner=server cert/key, donor=client cert/key), no generic ssl-cert. +# - Force node 2 to rejoin via a fresh SST. +# - Confirm node 2 rejoins and the transfer went through stunnel (SSL). +# +--source include/galera_cluster.inc +--source include/have_innodb.inc +--source include/have_stunnel.inc + +--let $node_1=node_1 +--let $node_2=node_2 +--source include/auto_increment_offset_save.inc + +--connection node_2 +--source include/shutdown_mysqld.inc + +# Force a fresh SST on node 2. +--remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat + +--source include/start_mysqld.inc +--source include/wait_until_connected_again.inc + +--connection node_1 +--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size' +--source include/wait_condition.inc + +# The joiner must have used stunnel (SSL) for the SST transfer. +--connection node_2 +--let $assert_text = SST used stunnel for SSL encryption +--let $assert_select = Using stunnel for SSL encryption +--let $assert_match = Using stunnel for SSL encryption +--let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.2.err +--let $assert_only_after = CURRENT_TEST +--source include/assert_grep.inc + +--source include/auto_increment_offset_restore.inc diff --git a/scripts/wsrep_sst_common.sh b/scripts/wsrep_sst_common.sh index 3009889cdefbd..0065828df779e 100644 --- a/scripts/wsrep_sst_common.sh +++ b/scripts/wsrep_sst_common.sh @@ -1644,6 +1644,20 @@ check_server_ssl_config() "of the tca[path], tcert and/or tkey in the [sst] section" fi fi + # Role-specific overrides: the joiner is the TLS server (listener), + # the donor the TLS client (connector). Allow a distinct cert, key + # and CA per role for setups where they differ. + if [ "$WSREP_SST_OPT_ROLE" = 'joiner' ]; then + tcert=$(parse_cnf "$encgroups" 'ssl-server-ca' "$tcert") + tcap=$(parse_cnf "$encgroups" 'ssl-server-capath' "$tcap") + tpem=$(parse_cnf "$encgroups" 'ssl-server-cert' "$tpem") + tkey=$(parse_cnf "$encgroups" 'ssl-server-key' "$tkey") + else + tcert=$(parse_cnf "$encgroups" 'ssl-client-ca' "$tcert") + tcap=$(parse_cnf "$encgroups" 'ssl-client-capath' "$tcap") + tpem=$(parse_cnf "$encgroups" 'ssl-client-cert' "$tpem") + tkey=$(parse_cnf "$encgroups" 'ssl-client-key' "$tkey") + fi if [ -n "$tcert" ]; then if [ "${tcert%/}" != "$tcert" -o -d "$tcert" ]; then tcap="$tcert"