Uploaded image for project: 'MariaDB Server'
  1. MariaDB Server
  2. MDEV-32342

WSREP_SST_OPT_REMOTE_AUTH bad value, causes bad socat commonname, causes SST to fail

    XMLWordPrintable

Details

    Description

      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

          Activity

            People

              sysprg Julius Goryavsky
              wdoekes Walter Doekes
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:

                Git Integration

                  Error rendering 'com.xiplink.jira.git.jira_git_plugin:git-issue-webpanel'. Please contact your Jira administrators.