nixos/mysql: run ExecStartPost as an unprivileged user

This commit is contained in:
Aaron Andersen 2020-08-11 21:54:51 -04:00
parent 31098a03a2
commit e3c210dfd1

View File

@ -321,7 +321,7 @@ in
binlog-ignore-db = [ "information_schema" "performance_schema" "mysql" ]; binlog-ignore-db = [ "information_schema" "performance_schema" "mysql" ];
}) })
(mkIf (!isMariaDB) { (mkIf (!isMariaDB) {
plugin-load-add = optional (cfg.ensureUsers != []) "auth_socket.so"; plugin-load-add = "auth_socket.so";
}) })
]; ];
@ -383,6 +383,8 @@ in
ExecStart = "${cfg.package}/bin/mysqld --defaults-file=/etc/my.cnf ${mysqldOptions} $_WSREP_NEW_CLUSTER $_WSREP_START_POSITION"; ExecStart = "${cfg.package}/bin/mysqld --defaults-file=/etc/my.cnf ${mysqldOptions} $_WSREP_NEW_CLUSTER $_WSREP_START_POSITION";
ExecStartPost = ExecStartPost =
let let
# The super user account to use on *first* run of MySQL server
superUser = if isMariaDB then cfg.user else "root";
setupScript = pkgs.writeScript "mysql-setup" '' setupScript = pkgs.writeScript "mysql-setup" ''
#!${pkgs.runtimeShell} -e #!${pkgs.runtimeShell} -e
@ -405,6 +407,12 @@ in
if [ -f ${cfg.dataDir}/mysql_init ] if [ -f ${cfg.dataDir}/mysql_init ]
then then
# While MariaDB comes with a 'mysql' super user account since 10.4.x MySQL does not
# Since we don't want to run this service as 'root' we need to ensure the account exists on first run
( echo "CREATE USER IF NOT EXISTS '${cfg.user}'@'localhost' IDENTIFIED WITH ${if isMariaDB then "unix_socket" else "auth_socket"};"
echo "GRANT ALL PRIVILEGES ON *.* TO '${cfg.user}'@'localhost' WITH GRANT OPTION;"
) | ${cfg.package}/bin/mysql -u ${superUser} -N
${concatMapStrings (database: '' ${concatMapStrings (database: ''
# Create initial databases # Create initial databases
if ! test -e "${cfg.dataDir}/${database.name}"; then if ! test -e "${cfg.dataDir}/${database.name}"; then
@ -424,7 +432,7 @@ in
cat ${database.schema}/mysql-databases/*.sql cat ${database.schema}/mysql-databases/*.sql
fi fi
''} ''}
) | ${cfg.package}/bin/mysql -u root -N ) | ${cfg.package}/bin/mysql -u ${superUser} -N
fi fi
'') cfg.initialDatabases} '') cfg.initialDatabases}
@ -436,7 +444,7 @@ in
echo "CREATE USER '${cfg.replication.masterUser}'@'${cfg.replication.slaveHost}' IDENTIFIED WITH mysql_native_password;" echo "CREATE USER '${cfg.replication.masterUser}'@'${cfg.replication.slaveHost}' IDENTIFIED WITH mysql_native_password;"
echo "SET PASSWORD FOR '${cfg.replication.masterUser}'@'${cfg.replication.slaveHost}' = PASSWORD('${cfg.replication.masterPassword}');" echo "SET PASSWORD FOR '${cfg.replication.masterUser}'@'${cfg.replication.slaveHost}' = PASSWORD('${cfg.replication.masterPassword}');"
echo "GRANT REPLICATION SLAVE ON *.* TO '${cfg.replication.masterUser}'@'${cfg.replication.slaveHost}';" echo "GRANT REPLICATION SLAVE ON *.* TO '${cfg.replication.masterUser}'@'${cfg.replication.slaveHost}';"
) | ${cfg.package}/bin/mysql -u root -N ) | ${cfg.package}/bin/mysql -u ${superUser} -N
''} ''}
${optionalString (cfg.replication.role == "slave") ${optionalString (cfg.replication.role == "slave")
@ -446,7 +454,7 @@ in
( echo "stop slave;" ( echo "stop slave;"
echo "change master to master_host='${cfg.replication.masterHost}', master_user='${cfg.replication.masterUser}', master_password='${cfg.replication.masterPassword}';" echo "change master to master_host='${cfg.replication.masterHost}', master_user='${cfg.replication.masterUser}', master_password='${cfg.replication.masterPassword}';"
echo "start slave;" echo "start slave;"
) | ${cfg.package}/bin/mysql -u root -N ) | ${cfg.package}/bin/mysql -u ${superUser} -N
''} ''}
${optionalString (cfg.initialScript != null) ${optionalString (cfg.initialScript != null)
@ -454,7 +462,7 @@ in
# Execute initial script # Execute initial script
# using toString to avoid copying the file to nix store if given as path instead of string, # using toString to avoid copying the file to nix store if given as path instead of string,
# as it might contain credentials # as it might contain credentials
cat ${toString cfg.initialScript} | ${cfg.package}/bin/mysql -u root -N cat ${toString cfg.initialScript} | ${cfg.package}/bin/mysql -u ${superUser} -N
''} ''}
rm ${cfg.dataDir}/mysql_init rm ${cfg.dataDir}/mysql_init
@ -465,7 +473,7 @@ in
${concatMapStrings (database: '' ${concatMapStrings (database: ''
echo "CREATE DATABASE IF NOT EXISTS \`${database}\`;" echo "CREATE DATABASE IF NOT EXISTS \`${database}\`;"
'') cfg.ensureDatabases} '') cfg.ensureDatabases}
) | ${cfg.package}/bin/mysql -u root -N ) | ${cfg.package}/bin/mysql -N
''} ''}
${concatMapStrings (user: ${concatMapStrings (user:
@ -474,13 +482,11 @@ in
${concatStringsSep "\n" (mapAttrsToList (database: permission: '' ${concatStringsSep "\n" (mapAttrsToList (database: permission: ''
echo "GRANT ${permission} ON ${database} TO '${user.name}'@'localhost';" echo "GRANT ${permission} ON ${database} TO '${user.name}'@'localhost';"
'') user.ensurePermissions)} '') user.ensurePermissions)}
) | ${cfg.package}/bin/mysql -u root -N ) | ${cfg.package}/bin/mysql -N
'') cfg.ensureUsers} '') cfg.ensureUsers}
''; '';
in in
# ensureDatbases & ensureUsers depends on this script being run as root "${setupScript}";
# when the user has secured their mysql install
"+${setupScript}";
# User and group # User and group
User = cfg.user; User = cfg.user;
Group = cfg.group; Group = cfg.group;