Details
Description
(edited) NOTE: Fixed by 288ea9e146a238872998d7089070e82f39272728 – see comments from 2024-07-04
Recently I ran into this:
WSREP_SST: [INFO] Evaluating '/usr//bin/mbstream' -c 'xtrabackup_galera_info' | socat stdio openssl-connect:JOINER_IP:4444,linger=10,cert='/etc/mysql/ssl/galera.crt',key='/etc/mysql/ssl/galera.key',cafile='/etc/mysql/ssl/ca.crt',commonname='CN '; RC=( ${PIPESTATUS[@]} ) (20231002 18:20:06.014)
|
2023/10/02 14:16:55 socat[1316] E certificate is valid but its commonName does not match hostname
|
So, the donor refuses to connect to the joiner because the commonname does not match. And the common name is CN<space>, which is unexpected and wrong.
The commonname should be autodetected by the joiner and passed to the donor, here (10.3 branch, at mariadb-10.3.39):
./scripts/wsrep_sst_mariabackup.sh
wait_for_listen()
|
{
|
for i in {1..150}; do
|
if check_port "" "$SST_PORT" 'socat|nc'; then
|
break
|
fi
|
sleep 0.2
|
done
|
echo "ready $ADDR:$SST_PORT/$MODULE/$lsn/$sst_ver"
|
}
|
The donor turns that response into:
2023-10-02 18:53:19 1 [Note] WSREP: Prepared SST request: mariabackup|CN :e4083cfc25e917fca34c140c56397c60@JOINER_IP:4444/xtrabackup_sst//1
|
The parts before the "@" get collected by sst_prepare_other into wsrep_sst_donate_cb where it is passed to ./scripts/wsrep_sst_mariabackup.sh (in ./scripts/wsrep_sst_common.sh) as WSREP_SST_OPT_REMOTE_AUTH:
WSREP_SST_OPT_REMOTE_AUTH="${WSREP_SST_OPT_REMOTE_AUTH:-}"
|
...
|
readonly WSREP_SST_OPT_REMOTE_USER="${WSREP_SST_OPT_REMOTE_AUTH%%:*}"
|
readonly WSREP_SST_OPT_REMOTE_PSWD="${WSREP_SST_OPT_REMOTE_AUTH#*:}"
|
Here it is finally used in ./scripts/wsrep_sst_mariabackup.sh:
else
|
# CA verification
|
verify_ca_matches_cert "$tpem" "$tcert" "$tcap"
|
if [ -n "$WSREP_SST_OPT_REMOTE_USER" ]; then
|
CN_option=",commonname='$WSREP_SST_OPT_REMOTE_USER'"
|
elif [ "$WSREP_SST_OPT_ROLE" = 'joiner' -o $encrypt -eq 4 ]
|
then
|
CN_option=",commonname=''"
|
elif is_local_ip "$WSREP_SST_OPT_HOST_UNESCAPED"; then
|
CN_option=',commonname=localhost'
|
else
|
CN_option=",commonname='$WSREP_SST_OPT_HOST_UNESCAPED'"
|
fi
|
Where we get the strange "CN" value. Disabling commonname checking with encrypt=4 is not even possible.
Working back again, we see where the "ready $ADDR" comes from. If tmode starts with VERIFY (on the joiner), it runs (./scripts/wsrep_sst_mariabackup.sh):
if [ "${tmode#VERIFY}" != "$tmode" ]; then
|
# backward-incompatible behavior:
|
CN=""
|
if [ -n "$tpem" ]; then
|
# find out my Common Name
|
get_openssl
|
if [ -z "$OPENSSL_BINARY" ]; then
|
wsrep_log_error \
|
'openssl not found but it is required for authentication'
|
exit 42
|
fi
|
CN=$("$OPENSSL_BINARY" x509 -noout -subject -in "$tpem" | \
|
tr ',' '\n' | grep -F 'CN =' | cut -d '=' -f2 | sed s/^\ // | \
|
sed s/\ %//)
|
fi
|
MY_SECRET="$(wsrep_gen_secret)"
|
# Add authentication data to address
|
ADDR="$CN:$MY_SECRET@$ADDR"
|
And that CN generation is broken.
The trouble arises with the following example strings:
(openssl 1.1 and openssl 3.0)
subject=CN = galera-node1, O = OSSO B.V., C = NL, ST = Groningen, L = Groningen
|
(openssl 1.0)
subject= /CN=galera-node1/O=OSSO B.V./C=NL/ST=Groningen/L=Groningen
|
I don't expect the openssl-1.0 string to work. But the openssl-1.1/3.0 strings don't work either when CN is the first keyword of the subject.
See these:
$ echo 'subject= /CN=galera-node1/O=OSSO B.V./C=NL/ST=Groningen/L=Groningen' | tr ',' '\n' | grep -F 'CN =' | cut -d '=' -f2 | sed s/^\ // | sed s/\ %// | cat -A
|
$ echo 'subject=CN = galera-node1, O = OSSO B.V., C = NL, ST = Groningen, L = Groningen' | tr ',' '\n' | grep -F 'CN =' | cut -d '=' -f2 | sed s/^\ // | sed s/\ %// | cat -A
|
CN $
|
The only one that would work, would be something like:
$ echo 'subject=O = OSSO B.V., CN = galera-node1, C = NL, ST = Groningen, L = Groningen' | tr ',' '\n' | grep -F 'CN =' | cut -d '=' -f2 | sed s/^\ // | sed s/\ %// | cat -A
|
galera-node1$
|
I suggest replacing the tr+grep+cut+sed madness, with a single sed oneliner:
sed -e 's/^subject=//;s/^/, /;s@.*[/,][[:blank:]]*CN[[:blank:]]*=[[:blank:]]*@@;s@[/,].*@@'
|
That works on all mentioned -subject output lines.
Diff:
diff --git a/scripts/wsrep_sst_mariabackup.sh b/scripts/wsrep_sst_mariabackup.sh
|
index 7e26af83701..45dd1f3c4ff 100644
|
--- a/scripts/wsrep_sst_mariabackup.sh
|
+++ b/scripts/wsrep_sst_mariabackup.sh
|
@@ -1334,9 +1334,11 @@ else # joiner
|
'openssl not found but it is required for authentication'
|
exit 42
|
fi
|
- CN=$("$OPENSSL_BINARY" x509 -noout -subject -in "$tpem" | \
|
- tr ',' '\n' | grep -F 'CN =' | cut -d '=' -f2 | sed s/^\ // | \
|
- sed s/\ %//)
|
+ CN=$("$OPENSSL_BINARY" x509 -noout -subject -in "$tpem" | sed -e '
|
+ s/^subject=//
|
+ s/^/, /
|
+ s@.*[/,][[:blank:]]*CN[[:blank:]]*=[[:blank:]]*@@
|
+ s@[/,].*@@')
|
fi
|
MY_SECRET="$(wsrep_gen_secret)"
|
# Add authentication data to address
|
This was tested with the following config:
[mysqld]
|
wsrep_sst_method=mariabackup
|
ssl-cert=/etc/mysql/ssl/galera.crt
|
ssl-key=/etc/mysql/ssl/galera.key
|
ssl-ca=/etc/mysql/ssl/ca.crt
|
 |
[sst]
|
ssl-mode=VERIFY_CA
|
encrypt=3
|
This yields on donor (10.3.39+maria~ubu2004):
WSREP_SST: [INFO] SSL configuration: CA='/etc/mysql/ssl/ca.crt', CAPATH='', CERT='/etc/mysql/ssl/galera.crt', KEY='/etc/mysql/ssl/galera.key', MODE='VERIFY_CA', encrypt='3' (20231002 20:20:44.172)
|
...
|
WSREP_SST: [INFO] Evaluating '/usr//bin/mbstream' -c 'xtrabackup_galera_info' | socat stdio openssl-connect:JOINER_IP:4444,linger=10,cert='/etc/mysql/ssl/galera.crt',key='/etc/mysql/ssl/galera.key',cafile='/etc/mysql/ssl/ca.crt',commonname='galera-node3'; RC=( ${PIPESTATUS[@]} ) (20231002 20:20:44.323)
|
...
|
And everyone lives happily after.
Cheers,
Walter Doekes
OSSO B.V.
Attachments
Issue Links
- relates to
-
MDEV-32344 IST "Donor does not know my secret" with ssl-mode=VERIFY_CA
- Closed
-
MDEV-26360 Using hostnames for MariaBackup SSTs breaks certificate validation with encrypt=3
- Closed