From 3805a68f295fb3adb93d1b4b9b8691498fb73267 Mon Sep 17 00:00:00 2001 From: Daniel Black Date: Tue, 1 Feb 2022 17:50:49 +1100 Subject: [PATCH] MDEV-27732: Add env MARIADB_MYSQL_LOCALHOST_{USER,GRANTS} We create a mysql@localhost user under MARIADB_MYSQL_LOCALHOST_USER=1 with its default USAGE privileges. This gives access to SHOW GLOBAL STATUS/VARIABLES but no other real access including database visibility or process visibility. Being a @localhost this restricts access to via the unix socket. The level of access can be increased controlled by the environment variable MARIADB_MYSQL_LOCALHOST_GRANTS. If you are using monitoring replication or processes addition privileges are required, and the setting of the environment variable is the comma separated list of grants possible. For the moment, these are a set of global grants only. If you share the unix socket location, /var/run/mysqld by default, as a volume with another container, you have effectively given that container the mysql@localhost provided they have the same uid map or can create arbitrary users. This can be good for things like backup. This would require the datadir volume as well and the set of privileges (https://mariadb.com/kb/en/mariabackup-overview/#authentication-and-privileges). Any grants of UPDATE on mysql database will mean that the mysql@localhost user can manipulate any other user, potentially transparently adding unix_socket auth (in 10.4+), and the being able to gain their privileges. Grants of CREATE USER, or INSERT on the mysql database allow the creation of user and privilege escalation. For these reasons, ALL for MARIADB_MYSQL_LOCALHOST_GRANTS gains a warning. Many thanks to Daniel Rudolf for all the reviews and the support to develop this feature. --- .test/run.sh | 59 +++++++++++++++++++++++++++++++-------- 10.2/docker-entrypoint.sh | 27 ++++++++++++++++++ 10.3/docker-entrypoint.sh | 27 ++++++++++++++++++ 10.4/docker-entrypoint.sh | 27 ++++++++++++++++++ 10.5/docker-entrypoint.sh | 27 ++++++++++++++++++ 10.6/docker-entrypoint.sh | 27 ++++++++++++++++++ 10.7/docker-entrypoint.sh | 27 ++++++++++++++++++ 10.8/docker-entrypoint.sh | 27 ++++++++++++++++++ docker-entrypoint.sh | 27 ++++++++++++++++++ 9 files changed, 264 insertions(+), 11 deletions(-) diff --git a/.test/run.sh b/.test/run.sh index f58ef31a..50755098 100755 --- a/.test/run.sh +++ b/.test/run.sh @@ -116,31 +116,68 @@ killoff ;& mysql_root_password_is_set) -echo -e "Test: MYSQL_ROOT_PASSWORD\n" + echo -e "Test: MYSQL_ROOT_PASSWORD and mysql@localhost user\n" -runandwait -e MYSQL_ROOT_PASSWORD=examplepass "${image}" -mariadbclient -u root -pexamplepass -e 'select current_user()' -mariadbclient -u root -pwrongpass -e 'select current_user()' || echo 'expected failure' -killoff + runandwait -e MYSQL_ROOT_PASSWORD=examplepass -e MARIADB_MYSQL_LOCALHOST_USER=1 "${image}" + mariadbclient -u root -pexamplepass -e 'select current_user()' + mariadbclient -u root -pwrongpass -e 'select current_user()' || echo 'expected failure' + + otherusers=$(mariadbclient -u root -pexamplepass --skip-column-names -Be "select user,host from mysql.user where (user,host) not in (('root', 'localhost'), ('root', '%'), ('mariadb.sys', 'localhost'), ('mysql','localhost'))") + [ "$otherusers" != '' ] && die "unexpected users $otherusers" + + createuser=$(docker exec --user mysql -i \ + "$cname" \ + mysql \ + --silent \ + -e "show create user") + # shellcheck disable=SC2016 + [ "${createuser//\'/\`}" == 'CREATE USER `mysql`@`localhost` IDENTIFIED VIA unix_socket' ] || die "I wasn't created how I was expected" + + grants="$(docker exec --user mysql -i \ + $cname \ + mysql \ + --silent \ + -e show\ grants)" + + # shellcheck disable=SC2016 + [ "${grants//\'/\`}" == 'GRANT USAGE ON *.* TO `mysql`@`localhost` IDENTIFIED VIA unix_socket' ] || die "I wasn't granted what I was expected" + + killoff ;& mysql_random_password_is_complex) echo -e "Test: MYSQL_RANDOM_ROOT_PASSWORD, needs to satisify minimium complexity of simple-password-check plugin\n" -runandwait -e MYSQL_RANDOM_ROOT_PASSWORD=1 "${image}" --plugin-load-add=simple_password_check +runandwait -e MYSQL_RANDOM_ROOT_PASSWORD=1 -e MARIADB_MYSQL_LOCALHOST_GRANTS="RELOAD, PROCESS, LOCK TABLES" "${image}" --plugin-load-add=simple_password_check pass=$(docker logs "$cid" | grep 'GENERATED ROOT PASSWORD' 2>&1) # trim up until passwod pass=${pass#*GENERATED ROOT PASSWORD: } mariadbclient -u root -p"${pass}" -e 'select current_user()' -killoff + + docker exec --user mysql -i \ + "$cname" \ + mysql \ + --silent \ + -e "select 'I connect therefore I am'" || die "I'd hoped to work around MDEV-24111" + + grants="$(docker exec --user mysql -i \ + $cname \ + mysql \ + --silent \ + -e show\ grants)" + + # shellcheck disable=SC2016 + [ "${grants//\'/\`}" == 'GRANT RELOAD, PROCESS, LOCK TABLES ON *.* TO `mysql`@`localhost` IDENTIFIED VIA unix_socket' ] || die "I wasn't granted what I was expected" + + killoff ;& mysql_random_password_is_different) -echo -e "Test: second instance of MYSQL_RANDOM_ROOT_PASSWORD has a different password\n" +echo -e "Test: second instance of MYSQL_RANDOM_ROOT_PASSWORD has a different password (and mysql@localhost can be created(\n" -runandwait -e MYSQL_RANDOM_ROOT_PASSWORD=1 "${image}" --plugin-load-add=simple_password_check +runandwait -e MYSQL_RANDOM_ROOT_PASSWORD=1 -e MARIADB_MYSQL_LOCALHOST_USER=1 "${image}" --plugin-load-add=simple_password_check newpass=$(docker logs "$cid" | grep 'GENERATED ROOT PASSWORD' 2>&1) # trim up until passwod newpass=${newpass#*GENERATED ROOT PASSWORD: } @@ -274,7 +311,7 @@ mariadbclient -u root -e 'show databases' othertables=$(mariadbclient -u root --skip-column-names -Be "select group_concat(SCHEMA_NAME) from information_schema.SCHEMATA where SCHEMA_NAME not in ('mysql', 'information_schema', 'performance_schema', 'sys')") [ "${othertables}" != 'NULL' ] && die "unexpected table(s) $othertables" -otherusers=$(mariadbclient -u root --skip-column-names -Be "select user,host from mysql.user where (user,host) not in (('root', 'localhost'), ('root', '%'), ('mariadb.sys', 'localhost'))") +otherusers=$(mariadbclient -u root --skip-column-names -Be "select user,host from mysql.user where (user,host) not in (('root', 'localhost'), ('root', '%'), ('mariadb.sys', 'localhost'), ('mysql','localhost'))") [ "$otherusers" != '' ] && die "unexpected users $otherusers" killoff @@ -286,7 +323,7 @@ echo -e "Test: MARIADB_ROOT_PASSWORD\n" runandwait -e MARIADB_ROOT_PASSWORD=examplepass "${image}" mariadbclient -u root -pexamplepass -e 'select current_user()' mariadbclient -u root -pwrongpass -e 'select current_user()' || echo 'expected failure' -killoff +killoff ;& mariadb_root_password_is_complex) diff --git a/10.2/docker-entrypoint.sh b/10.2/docker-entrypoint.sh index 1cfd48b6..ea43470f 100755 --- a/10.2/docker-entrypoint.sh +++ b/10.2/docker-entrypoint.sh @@ -295,6 +295,31 @@ docker_setup_db() { EOSQL fi + local mysqlAtLocalhost= + local mysqlAtLocalhostGrants= + # Install mysql@localhost user + if [ -n "$MARIADB_MYSQL_LOCALHOST_USER" ] || [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + local pw= + pw="$(pwgen --numerals --capitalize --symbols --remove-chars="'\\" -1 32)" + # MDEV-24111 before MariaDB-10.4 cannot create unix_socket user directly auth with simple_password_check + # It wasn't until 10.4 that the unix_socket auth was built in to the server. + read -r -d '' mysqlAtLocalhost <<-EOSQL || true + EXECUTE IMMEDIATE IF(VERSION() RLIKE '^10\.[23]\.', + "INSTALL PLUGIN /*M10401 IF NOT EXISTS */ unix_socket SONAME 'auth_socket'", + "SELECT 'already there'"); + CREATE USER mysql@localhost IDENTIFIED BY '$pw'; + ALTER USER mysql@localhost IDENTIFIED VIA unix_socket; + EOSQL + if [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + if [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = ALL* ]] || \ + [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = *UPDATE* ]] || \ + [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = *INSERT* ]]; then + mysql_warn "ALL/INSERT/UPDATE privileges ON *.* TO mysql@localhost facilitates privilege escalation, recommending limiting to required privileges" + fi + mysqlAtLocalhostGrants="GRANT ${MARIADB_MYSQL_LOCALHOST_GRANTS} ON *.* TO mysql@localhost;"; + fi + fi + mysql_note "Securing system users (equivalent to running mysql_secure_installation)" # tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set # --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding. @@ -310,6 +335,8 @@ docker_setup_db() { SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${rootPasswordEscaped}') ; ${rootCreate} + ${mysqlAtLocalhost} + ${mysqlAtLocalhostGrants} -- pre-10.3 DROP DATABASE IF EXISTS test ; EOSQL diff --git a/10.3/docker-entrypoint.sh b/10.3/docker-entrypoint.sh index 1cfd48b6..ea43470f 100755 --- a/10.3/docker-entrypoint.sh +++ b/10.3/docker-entrypoint.sh @@ -295,6 +295,31 @@ docker_setup_db() { EOSQL fi + local mysqlAtLocalhost= + local mysqlAtLocalhostGrants= + # Install mysql@localhost user + if [ -n "$MARIADB_MYSQL_LOCALHOST_USER" ] || [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + local pw= + pw="$(pwgen --numerals --capitalize --symbols --remove-chars="'\\" -1 32)" + # MDEV-24111 before MariaDB-10.4 cannot create unix_socket user directly auth with simple_password_check + # It wasn't until 10.4 that the unix_socket auth was built in to the server. + read -r -d '' mysqlAtLocalhost <<-EOSQL || true + EXECUTE IMMEDIATE IF(VERSION() RLIKE '^10\.[23]\.', + "INSTALL PLUGIN /*M10401 IF NOT EXISTS */ unix_socket SONAME 'auth_socket'", + "SELECT 'already there'"); + CREATE USER mysql@localhost IDENTIFIED BY '$pw'; + ALTER USER mysql@localhost IDENTIFIED VIA unix_socket; + EOSQL + if [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + if [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = ALL* ]] || \ + [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = *UPDATE* ]] || \ + [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = *INSERT* ]]; then + mysql_warn "ALL/INSERT/UPDATE privileges ON *.* TO mysql@localhost facilitates privilege escalation, recommending limiting to required privileges" + fi + mysqlAtLocalhostGrants="GRANT ${MARIADB_MYSQL_LOCALHOST_GRANTS} ON *.* TO mysql@localhost;"; + fi + fi + mysql_note "Securing system users (equivalent to running mysql_secure_installation)" # tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set # --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding. @@ -310,6 +335,8 @@ docker_setup_db() { SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${rootPasswordEscaped}') ; ${rootCreate} + ${mysqlAtLocalhost} + ${mysqlAtLocalhostGrants} -- pre-10.3 DROP DATABASE IF EXISTS test ; EOSQL diff --git a/10.4/docker-entrypoint.sh b/10.4/docker-entrypoint.sh index 1cfd48b6..ea43470f 100755 --- a/10.4/docker-entrypoint.sh +++ b/10.4/docker-entrypoint.sh @@ -295,6 +295,31 @@ docker_setup_db() { EOSQL fi + local mysqlAtLocalhost= + local mysqlAtLocalhostGrants= + # Install mysql@localhost user + if [ -n "$MARIADB_MYSQL_LOCALHOST_USER" ] || [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + local pw= + pw="$(pwgen --numerals --capitalize --symbols --remove-chars="'\\" -1 32)" + # MDEV-24111 before MariaDB-10.4 cannot create unix_socket user directly auth with simple_password_check + # It wasn't until 10.4 that the unix_socket auth was built in to the server. + read -r -d '' mysqlAtLocalhost <<-EOSQL || true + EXECUTE IMMEDIATE IF(VERSION() RLIKE '^10\.[23]\.', + "INSTALL PLUGIN /*M10401 IF NOT EXISTS */ unix_socket SONAME 'auth_socket'", + "SELECT 'already there'"); + CREATE USER mysql@localhost IDENTIFIED BY '$pw'; + ALTER USER mysql@localhost IDENTIFIED VIA unix_socket; + EOSQL + if [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + if [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = ALL* ]] || \ + [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = *UPDATE* ]] || \ + [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = *INSERT* ]]; then + mysql_warn "ALL/INSERT/UPDATE privileges ON *.* TO mysql@localhost facilitates privilege escalation, recommending limiting to required privileges" + fi + mysqlAtLocalhostGrants="GRANT ${MARIADB_MYSQL_LOCALHOST_GRANTS} ON *.* TO mysql@localhost;"; + fi + fi + mysql_note "Securing system users (equivalent to running mysql_secure_installation)" # tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set # --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding. @@ -310,6 +335,8 @@ docker_setup_db() { SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${rootPasswordEscaped}') ; ${rootCreate} + ${mysqlAtLocalhost} + ${mysqlAtLocalhostGrants} -- pre-10.3 DROP DATABASE IF EXISTS test ; EOSQL diff --git a/10.5/docker-entrypoint.sh b/10.5/docker-entrypoint.sh index 1cfd48b6..ea43470f 100755 --- a/10.5/docker-entrypoint.sh +++ b/10.5/docker-entrypoint.sh @@ -295,6 +295,31 @@ docker_setup_db() { EOSQL fi + local mysqlAtLocalhost= + local mysqlAtLocalhostGrants= + # Install mysql@localhost user + if [ -n "$MARIADB_MYSQL_LOCALHOST_USER" ] || [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + local pw= + pw="$(pwgen --numerals --capitalize --symbols --remove-chars="'\\" -1 32)" + # MDEV-24111 before MariaDB-10.4 cannot create unix_socket user directly auth with simple_password_check + # It wasn't until 10.4 that the unix_socket auth was built in to the server. + read -r -d '' mysqlAtLocalhost <<-EOSQL || true + EXECUTE IMMEDIATE IF(VERSION() RLIKE '^10\.[23]\.', + "INSTALL PLUGIN /*M10401 IF NOT EXISTS */ unix_socket SONAME 'auth_socket'", + "SELECT 'already there'"); + CREATE USER mysql@localhost IDENTIFIED BY '$pw'; + ALTER USER mysql@localhost IDENTIFIED VIA unix_socket; + EOSQL + if [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + if [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = ALL* ]] || \ + [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = *UPDATE* ]] || \ + [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = *INSERT* ]]; then + mysql_warn "ALL/INSERT/UPDATE privileges ON *.* TO mysql@localhost facilitates privilege escalation, recommending limiting to required privileges" + fi + mysqlAtLocalhostGrants="GRANT ${MARIADB_MYSQL_LOCALHOST_GRANTS} ON *.* TO mysql@localhost;"; + fi + fi + mysql_note "Securing system users (equivalent to running mysql_secure_installation)" # tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set # --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding. @@ -310,6 +335,8 @@ docker_setup_db() { SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${rootPasswordEscaped}') ; ${rootCreate} + ${mysqlAtLocalhost} + ${mysqlAtLocalhostGrants} -- pre-10.3 DROP DATABASE IF EXISTS test ; EOSQL diff --git a/10.6/docker-entrypoint.sh b/10.6/docker-entrypoint.sh index 9fc71760..1a7f4ca1 100755 --- a/10.6/docker-entrypoint.sh +++ b/10.6/docker-entrypoint.sh @@ -295,6 +295,31 @@ docker_setup_db() { EOSQL fi + local mysqlAtLocalhost= + local mysqlAtLocalhostGrants= + # Install mysql@localhost user + if [ -n "$MARIADB_MYSQL_LOCALHOST_USER" ] || [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + local pw= + pw="$(pwgen --numerals --capitalize --symbols --remove-chars="'\\" -1 32)" + # MDEV-24111 before MariaDB-10.4 cannot create unix_socket user directly auth with simple_password_check + # It wasn't until 10.4 that the unix_socket auth was built in to the server. + read -r -d '' mysqlAtLocalhost <<-EOSQL || true + EXECUTE IMMEDIATE IF(VERSION() RLIKE '^10\.[23]\.', + "INSTALL PLUGIN /*M10401 IF NOT EXISTS */ unix_socket SONAME 'auth_socket'", + "SELECT 'already there'"); + CREATE USER mysql@localhost IDENTIFIED BY '$pw'; + ALTER USER mysql@localhost IDENTIFIED VIA unix_socket; + EOSQL + if [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + if [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = ALL* ]] || \ + [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = *UPDATE* ]] || \ + [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = *INSERT* ]]; then + mysql_warn "ALL/INSERT/UPDATE privileges ON *.* TO mysql@localhost facilitates privilege escalation, recommending limiting to required privileges" + fi + mysqlAtLocalhostGrants="GRANT ${MARIADB_MYSQL_LOCALHOST_GRANTS} ON *.* TO mysql@localhost;"; + fi + fi + mysql_note "Securing system users (equivalent to running mysql_secure_installation)" # tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set # --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding. @@ -310,6 +335,8 @@ docker_setup_db() { SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${rootPasswordEscaped}') ; ${rootCreate} + ${mysqlAtLocalhost} + ${mysqlAtLocalhostGrants} -- pre-10.3 DROP DATABASE IF EXISTS test ; EOSQL diff --git a/10.7/docker-entrypoint.sh b/10.7/docker-entrypoint.sh index 9fc71760..1a7f4ca1 100755 --- a/10.7/docker-entrypoint.sh +++ b/10.7/docker-entrypoint.sh @@ -295,6 +295,31 @@ docker_setup_db() { EOSQL fi + local mysqlAtLocalhost= + local mysqlAtLocalhostGrants= + # Install mysql@localhost user + if [ -n "$MARIADB_MYSQL_LOCALHOST_USER" ] || [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + local pw= + pw="$(pwgen --numerals --capitalize --symbols --remove-chars="'\\" -1 32)" + # MDEV-24111 before MariaDB-10.4 cannot create unix_socket user directly auth with simple_password_check + # It wasn't until 10.4 that the unix_socket auth was built in to the server. + read -r -d '' mysqlAtLocalhost <<-EOSQL || true + EXECUTE IMMEDIATE IF(VERSION() RLIKE '^10\.[23]\.', + "INSTALL PLUGIN /*M10401 IF NOT EXISTS */ unix_socket SONAME 'auth_socket'", + "SELECT 'already there'"); + CREATE USER mysql@localhost IDENTIFIED BY '$pw'; + ALTER USER mysql@localhost IDENTIFIED VIA unix_socket; + EOSQL + if [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + if [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = ALL* ]] || \ + [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = *UPDATE* ]] || \ + [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = *INSERT* ]]; then + mysql_warn "ALL/INSERT/UPDATE privileges ON *.* TO mysql@localhost facilitates privilege escalation, recommending limiting to required privileges" + fi + mysqlAtLocalhostGrants="GRANT ${MARIADB_MYSQL_LOCALHOST_GRANTS} ON *.* TO mysql@localhost;"; + fi + fi + mysql_note "Securing system users (equivalent to running mysql_secure_installation)" # tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set # --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding. @@ -310,6 +335,8 @@ docker_setup_db() { SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${rootPasswordEscaped}') ; ${rootCreate} + ${mysqlAtLocalhost} + ${mysqlAtLocalhostGrants} -- pre-10.3 DROP DATABASE IF EXISTS test ; EOSQL diff --git a/10.8/docker-entrypoint.sh b/10.8/docker-entrypoint.sh index 9fc71760..1a7f4ca1 100755 --- a/10.8/docker-entrypoint.sh +++ b/10.8/docker-entrypoint.sh @@ -295,6 +295,31 @@ docker_setup_db() { EOSQL fi + local mysqlAtLocalhost= + local mysqlAtLocalhostGrants= + # Install mysql@localhost user + if [ -n "$MARIADB_MYSQL_LOCALHOST_USER" ] || [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + local pw= + pw="$(pwgen --numerals --capitalize --symbols --remove-chars="'\\" -1 32)" + # MDEV-24111 before MariaDB-10.4 cannot create unix_socket user directly auth with simple_password_check + # It wasn't until 10.4 that the unix_socket auth was built in to the server. + read -r -d '' mysqlAtLocalhost <<-EOSQL || true + EXECUTE IMMEDIATE IF(VERSION() RLIKE '^10\.[23]\.', + "INSTALL PLUGIN /*M10401 IF NOT EXISTS */ unix_socket SONAME 'auth_socket'", + "SELECT 'already there'"); + CREATE USER mysql@localhost IDENTIFIED BY '$pw'; + ALTER USER mysql@localhost IDENTIFIED VIA unix_socket; + EOSQL + if [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + if [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = ALL* ]] || \ + [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = *UPDATE* ]] || \ + [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = *INSERT* ]]; then + mysql_warn "ALL/INSERT/UPDATE privileges ON *.* TO mysql@localhost facilitates privilege escalation, recommending limiting to required privileges" + fi + mysqlAtLocalhostGrants="GRANT ${MARIADB_MYSQL_LOCALHOST_GRANTS} ON *.* TO mysql@localhost;"; + fi + fi + mysql_note "Securing system users (equivalent to running mysql_secure_installation)" # tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set # --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding. @@ -310,6 +335,8 @@ docker_setup_db() { SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${rootPasswordEscaped}') ; ${rootCreate} + ${mysqlAtLocalhost} + ${mysqlAtLocalhostGrants} -- pre-10.3 DROP DATABASE IF EXISTS test ; EOSQL diff --git a/docker-entrypoint.sh b/docker-entrypoint.sh index 1cfd48b6..ea43470f 100755 --- a/docker-entrypoint.sh +++ b/docker-entrypoint.sh @@ -295,6 +295,31 @@ docker_setup_db() { EOSQL fi + local mysqlAtLocalhost= + local mysqlAtLocalhostGrants= + # Install mysql@localhost user + if [ -n "$MARIADB_MYSQL_LOCALHOST_USER" ] || [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + local pw= + pw="$(pwgen --numerals --capitalize --symbols --remove-chars="'\\" -1 32)" + # MDEV-24111 before MariaDB-10.4 cannot create unix_socket user directly auth with simple_password_check + # It wasn't until 10.4 that the unix_socket auth was built in to the server. + read -r -d '' mysqlAtLocalhost <<-EOSQL || true + EXECUTE IMMEDIATE IF(VERSION() RLIKE '^10\.[23]\.', + "INSTALL PLUGIN /*M10401 IF NOT EXISTS */ unix_socket SONAME 'auth_socket'", + "SELECT 'already there'"); + CREATE USER mysql@localhost IDENTIFIED BY '$pw'; + ALTER USER mysql@localhost IDENTIFIED VIA unix_socket; + EOSQL + if [ -n "$MARIADB_MYSQL_LOCALHOST_GRANTS" ]; then + if [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = ALL* ]] || \ + [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = *UPDATE* ]] || \ + [[ "$MARIADB_MYSQL_LOCALHOST_GRANTS" = *INSERT* ]]; then + mysql_warn "ALL/INSERT/UPDATE privileges ON *.* TO mysql@localhost facilitates privilege escalation, recommending limiting to required privileges" + fi + mysqlAtLocalhostGrants="GRANT ${MARIADB_MYSQL_LOCALHOST_GRANTS} ON *.* TO mysql@localhost;"; + fi + fi + mysql_note "Securing system users (equivalent to running mysql_secure_installation)" # tell docker_process_sql to not use MARIADB_ROOT_PASSWORD since it is just now being set # --binary-mode to save us from the semi-mad users go out of their way to confuse the encoding. @@ -310,6 +335,8 @@ docker_setup_db() { SET PASSWORD FOR 'root'@'localhost'=PASSWORD('${rootPasswordEscaped}') ; ${rootCreate} + ${mysqlAtLocalhost} + ${mysqlAtLocalhostGrants} -- pre-10.3 DROP DATABASE IF EXISTS test ; EOSQL