Commit 54d7ba96 authored by Alexey Yurchenko's avatar Alexey Yurchenko Committed by Julius Goryavsky

MDEV-25418: Improve mariabackup SST script compliance with native MariaDB SSL practices

and configuration.

1. Pass joiner's authentication information to donor together with address
   in State Transfer Request. This allows joiner to authenticate donor on
   connection. Previously joiner would accept data from anywhere.

2. Deprecate custom SSL configuration variables tca, tcert and tkey in favor
   of more familiar ssl-ca, ssl-cert and ssl-key. For backward compatibility
   tca, tcert and tkey are still supported.

3. Allow falling back to server-wide SSL configuration in [mysqld] if no SSL
   configuration is found in [sst] section of the config file.

4. Introduce ssl-mode variable in [sst] section that takes standard values
   and has following effects:
    - old-style SSL configuration present in [sst]: no effect
      otherwise:
    - ssl-mode=DISABLED or absent: retains old, backward compatible behavior
      and ignores any other SSL configuration
    - ssl-mode=VERIFY*: verify joiner's certificate and CN on donor,
                        verify donor's secret on joiner
                        (passed to donor via State Transfer Request)
                        BACKWARD INCOMPATIBLE BEHAVIOR
    - anything else enables new SSL configuration convetions but does not
      require verification

    ssl-mode should be set to VERIFY only in a fully upgraded cluster.

    Examples:

    [mysqld]
    ssl-cert=/path/to/cert
    ssl-key=/path/to/key
    ssl-ca=/path/to/ca

    [sst]

     -- server-wide SSL configuration is ignored, SST does not use SSL

    [mysqld]
    ssl-cert=/path/to/cert
    ssl-key=/path/to/key
    ssl-ca=/path/to/ca

    [sst]
    ssl-mode=REQUIRED

     -- use server-wide SSL configuration for SST but don't attempt to
        verify the peer identity

    [sst]
    ssl-cert=/path/to/cert
    ssl-key=/path/to/key
    ssl-ca=/path/to/ca
    ssl-mode=VERIFY_CA

     -- use SST-specific SSL configuration for SST and require verification
        on both sides
Signed-off-by: default avatarJulius Goryavsky <julius.goryavsky@mariadb.com>
parent cf67ca48
SELECT 1; SELECT 1;
1 1
1 1
include/assert_grep.inc [Using openssl based encryption with socat]
SELECT 1;
1
1
include/assert_grep.inc [Using openssl based encryption with socat]
# #
# This test checks that key and cert encryption options can be passed to mariabackup via the my.cnf file # This test checks that key and cert encryption options can be passed to
# Initial SST happens via mariabackup, so there is not much to do in the body of the test # mariabackup via the my.cnf file
# Initial SST happens via mariabackup, so there is not much to do in the body
# of the test
# #
--source include/big_test.inc --source include/big_test.inc
...@@ -12,3 +14,11 @@ SELECT 1; ...@@ -12,3 +14,11 @@ SELECT 1;
--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size'; --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/wait_condition.inc
# Confirm that transfer was SSL-encrypted
--let $assert_text = Using openssl based encryption with socat
--let $assert_select = Using openssl based encryption with socat: with key and crt
--let $assert_count = 1
--let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.1.err
--let $assert_only_after = CURRENT_TEST
--source include/assert_grep.inc
!include ../galera_2nodes.cnf
[mysqld]
wsrep_sst_method=mariabackup
wsrep_sst_auth="root:"
wsrep_debug=ON
ssl-cert=@ENV.MYSQL_TEST_DIR/std_data/client-cert.pem
ssl-key=@ENV.MYSQL_TEST_DIR/std_data/client-key.pem
ssl-ca=@ENV.MYSQL_TEST_DIR/std_data/cacert.pem
[sst]
ssl-mode=VERIFY_CA
\ No newline at end of file
#
# This test checks that if SST SSL is not explicitly donfigured mariabackup SST
# uses server SSL configuration if present.
# Initial SST happens via mariabackup, so there is not much to do in the body
# of the test
#
--source include/big_test.inc
--source include/galera_cluster.inc
--source include/have_innodb.inc
--source include/have_mariabackup.inc
--source include/have_ssl_communication.inc
SELECT 1;
--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM INFORMATION_SCHEMA.GLOBAL_STATUS WHERE VARIABLE_NAME = 'wsrep_cluster_size';
--source include/wait_condition.inc
# Confirm that transfer was SSL-encrypted
--let $assert_text = Using openssl based encryption with socat
--let $assert_select = Using openssl based encryption with socat: with key and c
--let $assert_count = 1
--let $assert_file = $MYSQLTEST_VARDIR/log/mysqld.1.err
--let $assert_only_after = CURRENT_TEST
--source include/assert_grep.inc
...@@ -637,49 +637,30 @@ static void* sst_joiner_thread (void* a) ...@@ -637,49 +637,30 @@ static void* sst_joiner_thread (void* a)
return NULL; return NULL;
} }
#define WSREP_SST_AUTH_ENV "WSREP_SST_OPT_AUTH" #define WSREP_SST_AUTH_ENV "WSREP_SST_OPT_AUTH"
#define WSREP_SST_REMOTE_AUTH_ENV "WSREP_SST_OPT_REMOTE_AUTH"
#define DATA_HOME_DIR_ENV "INNODB_DATA_HOME_DIR"
static int sst_append_auth_env(wsp::env& env, const char* sst_auth) static int sst_append_env_var(wsp::env& env,
const char* const var,
const char* const val)
{ {
int const sst_auth_size= strlen(WSREP_SST_AUTH_ENV) + 1 /* = */ int const env_str_size= strlen(var) + 1 /* = */
+ (sst_auth ? strlen(sst_auth) : 0) + 1 /* \0 */; + (val ? strlen(val) : 0) + 1 /* \0 */;
wsp::string sst_auth_str(sst_auth_size); // for automatic cleanup on return wsp::string env_str(env_str_size); // for automatic cleanup on return
if (!sst_auth_str()) return -ENOMEM; if (!env_str()) return -ENOMEM;
int ret= snprintf(sst_auth_str(), sst_auth_size, "%s=%s", int ret= snprintf(env_str(), env_str_size, "%s=%s", var, val ? val : "");
WSREP_SST_AUTH_ENV, sst_auth ? sst_auth : "");
if (ret < 0 || ret >= sst_auth_size) if (ret < 0 || ret >= env_str_size)
{ {
WSREP_ERROR("sst_append_auth_env(): snprintf() failed: %d", ret); WSREP_ERROR("sst_append_env_var(): snprintf(%s=%s) failed: %d",
var, val, ret);
return (ret < 0 ? ret : -EMSGSIZE); return (ret < 0 ? ret : -EMSGSIZE);
} }
env.append(sst_auth_str()); env.append(env_str());
return -env.error();
}
#define DATA_HOME_DIR_ENV "INNODB_DATA_HOME_DIR"
static int sst_append_data_dir(wsp::env& env, const char* data_dir)
{
int const data_dir_size= strlen(DATA_HOME_DIR_ENV) + 1 /* = */
+ (data_dir ? strlen(data_dir) : 0) + 1 /* \0 */;
wsp::string data_dir_str(data_dir_size); // for automatic cleanup on return
if (!data_dir_str()) return -ENOMEM;
int ret= snprintf(data_dir_str(), data_dir_size, "%s=%s",
DATA_HOME_DIR_ENV, data_dir ? data_dir : "");
if (ret < 0 || ret >= data_dir_size)
{
WSREP_ERROR("sst_append_data_dir(): snprintf() failed: %d", ret);
return (ret < 0 ? ret : -EMSGSIZE);
}
env.append(data_dir_str());
return -env.error(); return -env.error();
} }
...@@ -1090,7 +1071,7 @@ static ssize_t sst_prepare_other (const char* method, ...@@ -1090,7 +1071,7 @@ static ssize_t sst_prepare_other (const char* method,
return -env.error(); return -env.error();
} }
if ((ret= sst_append_auth_env(env, sst_auth))) if ((ret= sst_append_env_var(env, WSREP_SST_AUTH_ENV, sst_auth)))
{ {
WSREP_ERROR("sst_prepare_other(): appending auth failed: %d", ret); WSREP_ERROR("sst_prepare_other(): appending auth failed: %d", ret);
return ret; return ret;
...@@ -1098,7 +1079,7 @@ static ssize_t sst_prepare_other (const char* method, ...@@ -1098,7 +1079,7 @@ static ssize_t sst_prepare_other (const char* method,
if (data_home_dir) if (data_home_dir)
{ {
if ((ret= sst_append_data_dir(env, data_home_dir))) if ((ret= sst_append_env_var(env, DATA_HOME_DIR_ENV, data_home_dir)))
{ {
WSREP_ERROR("sst_prepare_other(): appending data " WSREP_ERROR("sst_prepare_other(): appending data "
"directory failed: %d", ret); "directory failed: %d", ret);
...@@ -1275,12 +1256,12 @@ ssize_t wsrep_sst_prepare (void** msg) ...@@ -1275,12 +1256,12 @@ ssize_t wsrep_sst_prepare (void** msg)
*msg = malloc (msg_len); *msg = malloc (msg_len);
if (NULL != *msg) { if (NULL != *msg) {
char* const method_ptr(reinterpret_cast<char*>(*msg)); char* const method_ptr(static_cast<char*>(*msg));
strcpy (method_ptr, wsrep_sst_method); strcpy (method_ptr, wsrep_sst_method);
char* const addr_ptr(method_ptr + method_len + 1); char* const addr_ptr(method_ptr + method_len + 1);
strcpy (addr_ptr, addr_out); strcpy (addr_ptr, addr_out);
WSREP_INFO ("Prepared SST request: %s|%s", method_ptr, addr_ptr); WSREP_DEBUG("Prepared SST request: %s|%s", method_ptr, addr_ptr);
} }
else { else {
WSREP_ERROR("Failed to allocate SST request of size %zu. Can't continue.", WSREP_ERROR("Failed to allocate SST request of size %zu. Can't continue.",
...@@ -1733,6 +1714,7 @@ static int sst_donate_other (const char* method, ...@@ -1733,6 +1714,7 @@ static int sst_donate_other (const char* method,
"wsrep_sst_%s " "wsrep_sst_%s "
WSREP_SST_OPT_ROLE " 'donor' " WSREP_SST_OPT_ROLE " 'donor' "
WSREP_SST_OPT_ADDR " '%s' " WSREP_SST_OPT_ADDR " '%s' "
WSREP_SST_OPT_LPORT " '%u' "
WSREP_SST_OPT_SOCKET " '%s' " WSREP_SST_OPT_SOCKET " '%s' "
WSREP_SST_OPT_DATA " '%s' " WSREP_SST_OPT_DATA " '%s' "
"%s" "%s"
...@@ -1740,7 +1722,8 @@ static int sst_donate_other (const char* method, ...@@ -1740,7 +1722,8 @@ static int sst_donate_other (const char* method,
WSREP_SST_OPT_GTID_DOMAIN_ID " '%d'" WSREP_SST_OPT_GTID_DOMAIN_ID " '%d'"
"%s" "%s"
"%s", "%s",
method, addr, mysqld_unix_port, mysql_real_data_home, method, addr, mysqld_port, mysqld_unix_port,
mysql_real_data_home,
wsrep_defaults_file, wsrep_defaults_file,
uuid, (long long) seqno, wsrep_gtid_domain_id, uuid, (long long) seqno, wsrep_gtid_domain_id,
binlog_opt_val, binlog_opt_val,
...@@ -1820,7 +1803,21 @@ wsrep_cb_status_t wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx, ...@@ -1820,7 +1803,21 @@ wsrep_cb_status_t wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx,
const char* data = method + method_len + 1; const char* data = method + method_len + 1;
if (check_request_str(data, address_char)) /* check for auth@addr separator */
const char* addr= strrchr(data, '@');
wsp::string remote_auth;
if (addr)
{
remote_auth.set(strndup(data, addr - data));
addr++;
}
else
{
// no auth part
addr= data;
}
if (check_request_str(addr, address_char))
{ {
WSREP_ERROR("Bad SST address string. SST canceled."); WSREP_ERROR("Bad SST address string. SST canceled.");
return WSREP_CB_FAILURE; return WSREP_CB_FAILURE;
...@@ -1841,15 +1838,25 @@ wsrep_cb_status_t wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx, ...@@ -1841,15 +1838,25 @@ wsrep_cb_status_t wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx,
} }
int ret; int ret;
if ((ret= sst_append_auth_env(env, sst_auth_real))) if ((ret= sst_append_env_var(env, WSREP_SST_AUTH_ENV, sst_auth_real)))
{ {
WSREP_ERROR("wsrep_sst_donate_cb(): appending auth env failed: %d", ret); WSREP_ERROR("wsrep_sst_donate_cb(): appending auth env failed: %d", ret);
return WSREP_CB_FAILURE; return WSREP_CB_FAILURE;
} }
if (remote_auth())
{
if ((ret= sst_append_env_var(env, WSREP_SST_REMOTE_AUTH_ENV,remote_auth())))
{
WSREP_ERROR("wsrep_sst_donate_cb(): appending remote auth env failed: "
"%d", ret);
return WSREP_CB_FAILURE;
}
}
if (data_home_dir) if (data_home_dir)
{ {
if ((ret= sst_append_data_dir(env, data_home_dir))) if ((ret= sst_append_env_var(env, DATA_HOME_DIR_ENV, data_home_dir)))
{ {
WSREP_ERROR("wsrep_sst_donate_cb(): appending data " WSREP_ERROR("wsrep_sst_donate_cb(): appending data "
"directory failed: %d", ret); "directory failed: %d", ret);
...@@ -1859,12 +1866,12 @@ wsrep_cb_status_t wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx, ...@@ -1859,12 +1866,12 @@ wsrep_cb_status_t wsrep_sst_donate_cb (void* app_ctx, void* recv_ctx,
if (!strcmp (WSREP_SST_MYSQLDUMP, method)) if (!strcmp (WSREP_SST_MYSQLDUMP, method))
{ {
ret = sst_donate_mysqldump(data, &current_gtid->uuid, uuid_str, ret = sst_donate_mysqldump(addr, &current_gtid->uuid, uuid_str,
current_gtid->seqno, bypass, env()); current_gtid->seqno, bypass, env());
} }
else else
{ {
ret = sst_donate_other(method, data, uuid_str, ret = sst_donate_other(method, addr, uuid_str,
current_gtid->seqno, bypass, env()); current_gtid->seqno, bypass, env());
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment