Skip to content

Commit 03ab357

Browse files
committed
MDEV-10112: mysql_secure_installation: use DDL instead of DML for Galera compatibility
The script previously used direct DML statements (UPDATE, DELETE, INSERT) on MyISAM system tables (mysql.global_priv, mysql.db) which are not replicated by Galera clusters. Running the script on one node would leave other cluster nodes unsecured. Replace all such DML with Galera-safe DDL equivalents: 1. set_root_password: Before: UPDATE mysql.global_priv SET priv=json_set(...) WHERE User='root' After: ALTER USER ... IDENTIFIED BY '...' Uses PREPARE/EXECUTE to handle all root accounts across all hosts. 2. enable unix_socket authentication: Before: UPDATE mysql.global_priv SET priv=json_set(...) WHERE User='root' After: INSTALL SONAME 'auth_socket' (ensure plugin is loaded) ALTER USER ... IDENTIFIED VIA mysql_native_password USING 'invalid' OR unix_socket Uses PREPARE/EXECUTE to handle all root accounts across all hosts. 3. remove_anonymous_users: Before: DELETE FROM mysql.global_priv WHERE User='' After: DROP USER IF EXISTS ''@'host1', ''@'host2', ... Uses SELECT/GROUP_CONCAT to build the list of anonymous accounts dynamically. DROP USER automatically removes all privilege table entries for the dropped users, including mysql.db rows. 4. remove_remote_root: Before: DELETE FROM mysql.global_priv WHERE User='root' AND Host NOT IN (...) After: DROP USER IF EXISTS 'root'@'remotehost', ... Uses SELECT/GROUP_CONCAT to build the list of remote root accounts. 5. remove_test_database privileges: Before: DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%' After: REVOKE ALL PRIVILEGES ON test.* FROM non-anonymous users in mysql.db, followed by FLUSH PRIVILEGES to purge stale cache entries. Anonymous user entries are already cleaned up in step 3, since DROP USER automatically removes all mysql.db rows for the dropped user. All five changes use PREPARE/EXECUTE with GROUP_CONCAT-generated DDL to handle cases where multiple rows need to be acted on in a single statement.
1 parent 96e6070 commit 03ab357

1 file changed

Lines changed: 11 additions & 5 deletions

File tree

scripts/mysql_secure_installation.sh

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -316,7 +316,7 @@ set_root_password() {
316316
fi
317317

318318
esc_pass=`basic_single_escape "$password1"`
319-
do_query "UPDATE mysql.global_priv SET priv=json_set(priv, '$.plugin', 'mysql_native_password', '$.authentication_string', PASSWORD('$esc_pass')) WHERE User='root';"
319+
do_query "SET @str = IFNULL((SELECT GROUP_CONCAT(CONCAT('\'', User, '\'@\'', Host, '\'')) FROM mysql.global_priv WHERE User='root'), 'root@localhost'); SET @str = CONCAT('ALTER USER ', @str, ' IDENTIFIED BY \'$esc_pass\''); PREPARE stmt FROM @str; EXECUTE stmt; DEALLOCATE PREPARE stmt;"
320320
if [ $? -eq 0 ]; then
321321
echo "Password updated successfully!"
322322
echo "Reloading privilege tables.."
@@ -336,7 +336,7 @@ set_root_password() {
336336
}
337337

338338
remove_anonymous_users() {
339-
do_query "DELETE FROM mysql.global_priv WHERE User='';"
339+
do_query "SET @str = (SELECT IFNULL(CONCAT('DROP USER IF EXISTS ', GROUP_CONCAT(CONCAT('\'', User, '\'@\'', Host, '\''))), '') FROM mysql.global_priv WHERE User=''); SET @str = IF(@str = '', 'DO 1', @str); PREPARE stmt FROM @str; EXECUTE stmt; DEALLOCATE PREPARE stmt;"
340340
if [ $? -eq 0 ]; then
341341
echo " ... Success!"
342342
else
@@ -348,7 +348,7 @@ remove_anonymous_users() {
348348
}
349349

350350
remove_remote_root() {
351-
do_query "DELETE FROM mysql.global_priv WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');"
351+
do_query "SET @str = (SELECT IFNULL(CONCAT('DROP USER IF EXISTS ', GROUP_CONCAT(CONCAT('\'', User, '\'@\'', Host, '\''))), '') FROM mysql.global_priv WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1')); SET @str = IF(@str = '', 'DO 1', @str); PREPARE stmt FROM @str; EXECUTE stmt; DEALLOCATE PREPARE stmt;"
352352
if [ $? -eq 0 ]; then
353353
echo " ... Success!"
354354
else
@@ -366,12 +366,17 @@ remove_test_database() {
366366
fi
367367

368368
echo " - Removing privileges on test database..."
369-
do_query "DELETE FROM mysql.db WHERE Db='test' OR Db='test\\_%'"
369+
# REVOKE explicit grants on 'test' from any remaining named users.
370+
# Anonymous users (User='') are already removed by remove_anonymous_users()
371+
# via DROP USER, which also removes their mysql.db rows automatically.
372+
# FLUSH PRIVILEGES below clears any remaining stale cache entries.
373+
do_query "SET @str = (SELECT IFNULL(CONCAT('REVOKE ALL PRIVILEGES ON \`test\`.* FROM ', GROUP_CONCAT(CONCAT('\'', User, '\'@\'', Host, '\''))), 'DO 1') FROM mysql.db WHERE Db='test' AND User <> ''); PREPARE stmt FROM @str; EXECUTE stmt; DEALLOCATE PREPARE stmt;"
370374
if [ $? -eq 0 ]; then
371375
echo " ... Success!"
372376
else
373377
echo " ... Failed! Not critical, keep moving..."
374378
fi
379+
do_query "FLUSH PRIVILEGES;"
375380

376381
return 0
377382
}
@@ -448,7 +453,8 @@ if [ "$reply" = "n" ]; then
448453
echo " ... skipping."
449454
else
450455
emptypass=0
451-
do_query "UPDATE mysql.global_priv SET priv=json_set(priv, '$.password_last_changed', UNIX_TIMESTAMP(), '$.plugin', 'mysql_native_password', '$.authentication_string', 'invalid', '$.auth_or', json_array(json_object(), json_object('plugin', 'unix_socket'))) WHERE User='root';"
456+
do_query "INSTALL SONAME 'auth_socket';"
457+
do_query "SET @str = IFNULL((SELECT GROUP_CONCAT(CONCAT('\'', User, '\'@\'', Host, '\'')) FROM mysql.global_priv WHERE User='root'), 'root@localhost'); SET @str = CONCAT('ALTER USER ', @str, ' IDENTIFIED VIA mysql_native_password USING \'invalid\' OR unix_socket'); PREPARE stmt FROM @str; EXECUTE stmt; DEALLOCATE PREPARE stmt;"
452458
if [ $? -eq 0 ]; then
453459
echo "Enabled successfully!"
454460
echo "Reloading privilege tables.."

0 commit comments

Comments
 (0)