Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
connection node_2;
connection node_1;
connection node_1;
connection node_2;
connection node_1;
call mtr.add_suppression("WSREP: .*State transfer to.* failed:");
call mtr.add_suppression("WSREP: Will never receive state. Need to abort.");
connection node_2;
# Force a fresh SST on node_2
# Start node_2 with SSL cert/key simulated as missing
# node_2 failed to start, as expected
# Joiner refused the SST instead of running unencrypted
FOUND 1 /ssl-mode is set to .REQUIRED., but no usable SSL/ in mysqld.2.err
# Restart node_2 normally so it rejoins
connection node_2;
call mtr.add_suppression("WSREP_SST:");
call mtr.add_suppression("WSREP: Process completed with error:");
call mtr.add_suppression("WSREP: Failed to read .ready <addr>.");
call mtr.add_suppression("WSREP: Failed to read uuid:seqno and wsrep_gtid_domain_id from joiner script.");
call mtr.add_suppression("WSREP: Failed to read state from: .*");
call mtr.add_suppression("WSREP: Failed to prepare for .*");
call mtr.add_suppression("WSREP: SST failed:.*");
call mtr.add_suppression("WSREP: SST request callback failed. This is unrecoverable, restart required.");
call mtr.add_suppression("WSREP: .*State transfer to.* failed:");
call mtr.add_suppression("WSREP: Will never receive state. Need to abort.");
call mtr.add_suppression("WSREP: Requesting state transfer failed:.*");
connection node_1;
27 changes: 27 additions & 0 deletions mysql-test/suite/galera/r/galera_sst_rsync_missing_stunnel.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
connection node_2;
connection node_1;
connection node_1;
connection node_2;
connection node_1;
call mtr.add_suppression("WSREP: .*State transfer to.* failed:");
call mtr.add_suppression("WSREP: Will never receive state. Need to abort.");
connection node_2;
# Force a fresh SST on node_2
# Start node_2 with stunnel simulated as missing
# node_2 failed to start, as expected
# Joiner refused the SST instead of running unencrypted
FOUND 1 /ssl-mode is set to .REQUIRED., but the .stunnel. binary was not found/ in mysqld.2.err
# Restart node_2 normally so it rejoins
connection node_2;
call mtr.add_suppression("WSREP_SST:");
call mtr.add_suppression("WSREP: Process completed with error:");
call mtr.add_suppression("WSREP: Failed to read .ready <addr>.");
call mtr.add_suppression("WSREP: Failed to read uuid:seqno and wsrep_gtid_domain_id from joiner script.");
call mtr.add_suppression("WSREP: Failed to read state from: .*");
call mtr.add_suppression("WSREP: Failed to prepare for .*");
call mtr.add_suppression("WSREP: SST failed:.*");
call mtr.add_suppression("WSREP: SST request callback failed. This is unrecoverable, restart required.");
call mtr.add_suppression("WSREP: .*State transfer to.* failed:");
call mtr.add_suppression("WSREP: Will never receive state. Need to abort.");
call mtr.add_suppression("WSREP: Requesting state transfer failed:.*");
connection node_1;
11 changes: 11 additions & 0 deletions mysql-test/suite/galera/t/galera_sst_mariabackup_missing_ssl.cnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
!include ../galera_2nodes.cnf

[mysqld]
wsrep_sst_method=mariabackup
wsrep_sst_auth="root:"
ssl-cert=@ENV.MYSQL_TEST_DIR/std_data/server-cert.pem
ssl-key=@ENV.MYSQL_TEST_DIR/std_data/server-key.pem
ssl-ca=@ENV.MYSQL_TEST_DIR/std_data/cacert.pem

[sst]
ssl-mode=REQUIRED
69 changes: 69 additions & 0 deletions mysql-test/suite/galera/t/galera_sst_mariabackup_missing_ssl.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# MDEV-28233: with ssl-mode requiring encryption but no usable cert/key,
# wsrep_sst_mariabackup used to fall back to an unencrypted transfer
# WITHOUT any error or warning. Before the fix the joiner only logged the
# informational line:
# WSREP_SST: [INFO] SSL configuration: ... MODE='REQUIRED' ... encrypt='0'
# and then opened a cleartext socket.
#
# Steps:
# 1. Form a 2-node cluster with ssl-mode=REQUIRED and SSL cert/key.
# 2. Shut node_2 down and force a fresh SST.
# 3. Restart node_2 with cert/key simulated as missing
# (MTR_SST_SIMULATE_NO_SSL_CERT=1).
# 4. Check the joiner refuses the SST and logs the error.
# 5. Restart node_2 normally so it rejoins.
#
--source include/galera_cluster.inc
--source include/have_innodb.inc
--source include/have_mariabackup.inc

# Save auto_increment_offset values.
--let $node_1=node_1
--let $node_2=node_2
--source include/auto_increment_offset_save.inc

--connection node_1
# Donor-side noise when the joiner aborts the SST.
call mtr.add_suppression("WSREP: .*State transfer to.* failed:");
call mtr.add_suppression("WSREP: Will never receive state. Need to abort.");

--connection node_2
--source include/shutdown_mysqld.inc

--echo # Force a fresh SST on node_2
--remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat

--echo # Start node_2 with SSL cert/key simulated as missing
# Abort exit code varies by platform.
--error 1,134
--exec MTR_SST_SIMULATE_NO_SSL_CERT=1 $MYSQLD_LAST_CMD
--echo # node_2 failed to start, as expected

--echo # Joiner refused the SST instead of running unencrypted
--let SEARCH_FILE = $MYSQLTEST_VARDIR/log/mysqld.2.err
--let SEARCH_PATTERN = ssl-mode is set to .REQUIRED., but no usable SSL
--source include/search_pattern_in_file.inc

--echo # Restart node_2 normally so it rejoins
--source include/start_mysqld.inc
--source include/wait_until_connected_again.inc

--connection node_2
# Joiner-side noise from the failed SST attempt.
call mtr.add_suppression("WSREP_SST:");
call mtr.add_suppression("WSREP: Process completed with error:");
call mtr.add_suppression("WSREP: Failed to read .ready <addr>.");
call mtr.add_suppression("WSREP: Failed to read uuid:seqno and wsrep_gtid_domain_id from joiner script.");
call mtr.add_suppression("WSREP: Failed to read state from: .*");
call mtr.add_suppression("WSREP: Failed to prepare for .*");
call mtr.add_suppression("WSREP: SST failed:.*");
call mtr.add_suppression("WSREP: SST request callback failed. This is unrecoverable, restart required.");
call mtr.add_suppression("WSREP: .*State transfer to.* failed:");
call mtr.add_suppression("WSREP: Will never receive state. Need to abort.");
call mtr.add_suppression("WSREP: Requesting state transfer failed:.*");

--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

--source include/auto_increment_offset_restore.inc
10 changes: 10 additions & 0 deletions mysql-test/suite/galera/t/galera_sst_rsync_missing_stunnel.cnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
!include ../galera_2nodes.cnf

[mysqld]
wsrep_sst_method=rsync
ssl-cert=@ENV.MYSQL_TEST_DIR/std_data/server-cert.pem
ssl-key=@ENV.MYSQL_TEST_DIR/std_data/server-key.pem
ssl-ca=@ENV.MYSQL_TEST_DIR/std_data/cacert.pem

[sst]
ssl-mode=REQUIRED
66 changes: 66 additions & 0 deletions mysql-test/suite/galera/t/galera_sst_rsync_missing_stunnel.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# MDEV-28233: the rsync SST script must NOT silently fall back to an
# unencrypted transfer when encryption is requested (ssl-mode is set to a
# value other than DISABLED) but the stunnel binary is not installed.
#
# Steps:
# 1. Form a 2-node cluster with ssl-mode=REQUIRED (stunnel present).
# 2. Shut node_2 down and force a fresh SST.
# 3. Restart node_2 with stunnel hidden (MTR_SST_SIMULATE_NO_STUNNEL=1).
# 4. Check the joiner refuses the SST and logs the error.
# 5. Restart node_2 normally so it rejoins.
#
--source include/galera_cluster.inc
--source include/have_innodb.inc
# Needed for the initial SST; only simulated as missing below.
--source include/have_stunnel.inc

# Save auto_increment_offset values.
--let $node_1=node_1
--let $node_2=node_2
--source include/auto_increment_offset_save.inc

--connection node_1
# Donor-side noise when the joiner aborts the SST.
call mtr.add_suppression("WSREP: .*State transfer to.* failed:");
call mtr.add_suppression("WSREP: Will never receive state. Need to abort.");

--connection node_2
--source include/shutdown_mysqld.inc

--echo # Force a fresh SST on node_2
--remove_file $MYSQLTEST_VARDIR/mysqld.2/data/grastate.dat

--echo # Start node_2 with stunnel simulated as missing
# Abort exit code
--error 1,134
--exec MTR_SST_SIMULATE_NO_STUNNEL=1 $MYSQLD_LAST_CMD
--echo # node_2 failed to start, as expected

--echo # Joiner refused the SST instead of running unencrypted
--let SEARCH_FILE = $MYSQLTEST_VARDIR/log/mysqld.2.err
--let SEARCH_PATTERN = ssl-mode is set to .REQUIRED., but the .stunnel. binary was not found
--source include/search_pattern_in_file.inc

--echo # Restart node_2 normally so it rejoins
--source include/start_mysqld.inc
--source include/wait_until_connected_again.inc

--connection node_2
# Joiner-side noise from the failed SST attempt.
call mtr.add_suppression("WSREP_SST:");
call mtr.add_suppression("WSREP: Process completed with error:");
call mtr.add_suppression("WSREP: Failed to read .ready <addr>.");
call mtr.add_suppression("WSREP: Failed to read uuid:seqno and wsrep_gtid_domain_id from joiner script.");
call mtr.add_suppression("WSREP: Failed to read state from: .*");
call mtr.add_suppression("WSREP: Failed to prepare for .*");
call mtr.add_suppression("WSREP: SST failed:.*");
call mtr.add_suppression("WSREP: SST request callback failed. This is unrecoverable, restart required.");
call mtr.add_suppression("WSREP: .*State transfer to.* failed:");
call mtr.add_suppression("WSREP: Will never receive state. Need to abort.");
call mtr.add_suppression("WSREP: Requesting state transfer failed:.*");

--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

--source include/auto_increment_offset_restore.inc
15 changes: 15 additions & 0 deletions scripts/wsrep_sst_mariabackup.sh
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,11 @@ read_cnf()
if [ "$tmode" != 'DISABLED' -o $encrypt -ge 2 ]; then
check_server_ssl_config
fi
# MTR test hook: simulate a missing SSL certificate and key.
if [ -n "${MTR_SST_SIMULATE_NO_SSL_CERT:-}" ]; then
tpem=""
tkey=""
fi
if [ "$tmode" != 'DISABLED' ]; then
if [ 0 -eq $encrypt -a -n "$tpem" -a -n "$tkey" ]
then
Expand Down Expand Up @@ -593,6 +598,16 @@ read_cnf()
"CERT='$tpem', KEY='$tkey', MODE='$tmode'," \
"encrypt='$encrypt'"

# ssl-mode requires encryption but none could be set up (no usable
# cert/key): abort instead of silently transferring in cleartext.
if [ "$tmode" != 'DISABLED' -a $encrypt -eq 0 ]; then
wsrep_log_error "ssl-mode is set to '$tmode', but no usable SSL" \
"certificate and key were found. Cannot perform an" \
"encrypted transfer. Please configure ssl-cert and" \
"ssl-key, or set ssl-mode to DISABLED."
exit 22 # EINVAL
fi

if [ $encrypt -ge 2 ]; then
ssl_dhparams=$(parse_cnf "$encgroups" 'ssl-dhparams')
fi
Expand Down
23 changes: 16 additions & 7 deletions scripts/wsrep_sst_rsync.sh
Original file line number Diff line number Diff line change
Expand Up @@ -192,14 +192,11 @@ SSTCAP="$tcap"
SSLMODE=$(parse_cnf "$encgroups" 'ssl-mode' | tr '[[:lower:]]' '[[:upper:]]')

if [ -z "$SSLMODE" ]; then
# Implicit verification if CA is set and the SSL mode
# is not specified by user:
# ssl-mode not set: derive it from the SSL config. Set it even when
# stunnel is absent, so the check below aborts instead of silently
# falling back to an unencrypted transfer.
if [ -n "$SSTCA$SSTCAP" ]; then
STUNNEL_BIN=$(commandex 'stunnel')
if [ -n "$STUNNEL_BIN" ]; then
SSLMODE='VERIFY_CA'
fi
# Require SSL by default if SSL key and cert are present:
SSLMODE='VERIFY_CA'
elif [ -n "$SSTKEY" -a -n "$SSTCERT" ]; then
SSLMODE='REQUIRED'
fi
Expand Down Expand Up @@ -267,10 +264,22 @@ if [ -n "$SSLMODE" -a "$SSLMODE" != 'DISABLED' ]; then
if [ -z "${STUNNEL_BIN+x}" ]; then
STUNNEL_BIN=$(commandex 'stunnel')
fi
# MTR test hook: simulate a missing stunnel binary.
if [ -n "${MTR_SST_SIMULATE_NO_STUNNEL:-}" ]; then
STUNNEL_BIN=""
fi
if [ -n "$STUNNEL_BIN" ]; then
wsrep_log_info "Using stunnel for SSL encryption: CA: '$SSTCA'," \
"CAPATH='$SSTCAP', ssl-mode='$SSLMODE'"
STUNNEL="$STUNNEL_BIN $STUNNEL_CONF"
else
# Encryption required but stunnel missing: abort instead of
# silently falling back to an unencrypted transfer.
wsrep_log_error "ssl-mode is set to '$SSLMODE', but the 'stunnel'" \
"binary was not found in the path. Cannot perform" \
"an encrypted transfer. Please install stunnel or" \
"set ssl-mode to DISABLED."
exit 2 # ENOENT
fi
fi

Expand Down