Loading ci/OWNERS +1 −0 Original line number Diff line number Diff line Loading @@ -253,6 +253,7 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt /nixos/tests/postgresql @NixOS/postgres # MySQL/MariaDB and related stuff /nixos/modules/services/databases/mysql.nix @6543 /nixos/modules/services/backup/mysql-backup.nix @6543 # Hardened profile & related modules Loading nixos/modules/services/databases/mysql.nix +194 −145 Original line number Diff line number Diff line { config, lib, pkgs, ... }: { config, lib, pkgs, ... }: let cfg = config.services.mysql; Loading @@ -8,8 +13,7 @@ let # Oracle MySQL has supported "notify" service type since 8.0 hasNotify = isMariaDB || (isOracle && lib.versionAtLeast cfg.package.version "8.0"); mysqldOptions = "--user=${cfg.user} --datadir=${cfg.dataDir} --basedir=${cfg.package}"; mysqldOptions = "--user=${cfg.user} --datadir=${cfg.dataDir} --basedir=${cfg.package}"; format = pkgs.formats.ini { listsAsDuplicateKeys = true; }; configFile = format.generate "my.cnf" cfg.settings; Loading @@ -18,11 +22,31 @@ in { imports = [ (lib.mkRemovedOptionModule [ "services" "mysql" "pidDir" ] "Don't wait for pidfiles, describe dependencies through systemd.") (lib.mkRemovedOptionModule [ "services" "mysql" "rootPassword" ] "Use socket authentication or set the password outside of the nix store.") (lib.mkRemovedOptionModule [ "services" "mysql" "extraOptions" ] "Use services.mysql.settings.mysqld instead.") (lib.mkRemovedOptionModule [ "services" "mysql" "bind" ] "Use services.mysql.settings.mysqld.bind-address instead.") (lib.mkRemovedOptionModule [ "services" "mysql" "port" ] "Use services.mysql.settings.mysqld.port instead.") (lib.mkRemovedOptionModule [ "services" "mysql" "pidDir" ] "Don't wait for pidfiles, describe dependencies through systemd.") (lib.mkRemovedOptionModule [ "services" "mysql" "rootPassword" ] "Use socket authentication or set the password outside of the nix store.") (lib.mkRemovedOptionModule [ "services" "mysql" "extraOptions" ] "Use services.mysql.settings.mysqld instead.") (lib.mkRemovedOptionModule [ "services" "mysql" "bind" ] "Use services.mysql.settings.mysqld.bind-address instead.") (lib.mkRemovedOptionModule [ "services" "mysql" "port" ] "Use services.mysql.settings.mysqld.port instead.") ]; ###### interface Loading Loading @@ -137,7 +161,8 @@ in }; initialDatabases = lib.mkOption { type = lib.types.listOf (lib.types.submodule { type = lib.types.listOf ( lib.types.submodule { options = { name = lib.mkOption { type = lib.types.str; Loading @@ -154,7 +179,8 @@ in ''; }; }; }); } ); default = [ ]; description = '' List of database names and their initial schemas that should be used to create databases on the first startup Loading Loading @@ -190,7 +216,8 @@ in }; ensureUsers = lib.mkOption { type = lib.types.listOf (lib.types.submodule { type = lib.types.listOf ( lib.types.submodule { options = { name = lib.mkOption { type = lib.types.str; Loading Loading @@ -221,7 +248,8 @@ in ''; }; }; }); } ); default = [ ]; description = '' Ensures that the specified users exist and have at least the ensured permissions. Loading Loading @@ -251,7 +279,11 @@ in replication = { role = lib.mkOption { type = lib.types.enum [ "master" "slave" "none" ]; type = lib.types.enum [ "master" "slave" "none" ]; default = "none"; description = "Role of the MySQL server instance."; }; Loading Loading @@ -292,14 +324,13 @@ in }; ###### implementation config = lib.mkIf cfg.enable { services.mysql.dataDir = lib.mkDefault (if lib.versionAtLeast config.system.stateVersion "17.09" then "/var/lib/mysql" else "/var/mysql"); services.mysql.dataDir = lib.mkDefault ( if lib.versionAtLeast config.system.stateVersion "17.09" then "/var/lib/mysql" else "/var/mysql" ); services.mysql.settings.mysqld = lib.mkMerge [ { Loading @@ -311,7 +342,11 @@ in log-bin-index = "mysql-bin-${toString cfg.replication.serverId}.index"; relay-log = "mysql-relay-bin"; server-id = cfg.replication.serverId; binlog-ignore-db = [ "information_schema" "performance_schema" "mysql" ]; binlog-ignore-db = [ "information_schema" "performance_schema" "mysql" ]; }) (lib.mkIf (!isMariaDB) { plugin-load-add = [ "auth_socket.so" ]; Loading Loading @@ -355,12 +390,16 @@ in pkgs.nettools ]; preStart = if isMariaDB then '' preStart = if isMariaDB then '' if ! test -e ${cfg.dataDir}/mysql; then ${cfg.package}/bin/mysql_install_db --defaults-file=/etc/my.cnf ${mysqldOptions} touch ${cfg.dataDir}/mysql_init fi '' else '' '' else '' if ! test -e ${cfg.dataDir}/mysql; then ${cfg.package}/bin/mysqld --defaults-file=/etc/my.cnf ${mysqldOptions} --initialize-insecure touch ${cfg.dataDir}/mysql_init Loading @@ -379,10 +418,12 @@ in exec ${cfg.package}/bin/mysqld --defaults-file=/etc/my.cnf ${mysqldOptions} $_WSREP_NEW_CLUSTER $_WSREP_START_POSITION ''; postStart = let postStart = let # The super user account to use on *first* run of MySQL server superUser = if isMariaDB then cfg.user else "root"; in '' in '' ${lib.optionalString (!hasNotify) '' # Wait until the MySQL server is available for use while [ ! -e /run/mysqld/mysqld.sock ] Loading @@ -396,7 +437,9 @@ in 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 "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 Loading @@ -423,8 +466,7 @@ in fi '') cfg.initialDatabases} ${lib.optionalString (cfg.replication.role == "master") '' ${lib.optionalString (cfg.replication.role == "master") '' # Set up the replication master ( echo "use mysql;" Loading @@ -434,8 +476,7 @@ in ) | ${cfg.package}/bin/mysql -u ${superUser} -N ''} ${lib.optionalString (cfg.replication.role == "slave") '' ${lib.optionalString (cfg.replication.role == "slave") '' # Set up the replication slave ( echo "stop slave;" Loading @@ -444,8 +485,7 @@ in ) | ${cfg.package}/bin/mysql -u ${superUser} -N ''} ${lib.optionalString (cfg.initialScript != null) '' ${lib.optionalString (cfg.initialScript != null) '' # Execute initial script # using toString to avoid copying the file to nix store if given as path instead of string, # as it might contain credentials Loading @@ -463,12 +503,15 @@ in ) | ${cfg.package}/bin/mysql -N ''} ${lib.concatMapStrings (user: '' ( echo "CREATE USER IF NOT EXISTS '${user.name}'@'localhost' IDENTIFIED WITH ${if isMariaDB then "unix_socket" else "auth_socket"};" ${lib.concatStringsSep "\n" (lib.mapAttrsToList (database: permission: '' ${lib.concatMapStrings (user: '' ( echo "CREATE USER IF NOT EXISTS '${user.name}'@'localhost' IDENTIFIED WITH ${ if isMariaDB then "unix_socket" else "auth_socket" };" ${lib.concatStringsSep "\n" ( lib.mapAttrsToList (database: permission: '' echo "GRANT ${permission} ON ${database} TO '${user.name}'@'localhost';" '') user.ensurePermissions)} '') user.ensurePermissions )} ) | ${cfg.package}/bin/mysql -N '') cfg.ensureUsers} ''; Loading Loading @@ -500,7 +543,11 @@ in ProtectKernelTunables = true; ProtectKernelModules = true; ProtectControlGroups = true; RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ]; RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ]; LockPersonality = true; MemoryDenyWriteExecute = true; RestrictRealtime = true; Loading @@ -516,4 +563,6 @@ in ]; }; }; meta.maintainers = [ lib.maintainers._6543 ]; } Loading
ci/OWNERS +1 −0 Original line number Diff line number Diff line Loading @@ -253,6 +253,7 @@ pkgs/development/python-modules/buildcatrust/ @ajs124 @lukegb @mweinelt /nixos/tests/postgresql @NixOS/postgres # MySQL/MariaDB and related stuff /nixos/modules/services/databases/mysql.nix @6543 /nixos/modules/services/backup/mysql-backup.nix @6543 # Hardened profile & related modules Loading
nixos/modules/services/databases/mysql.nix +194 −145 Original line number Diff line number Diff line { config, lib, pkgs, ... }: { config, lib, pkgs, ... }: let cfg = config.services.mysql; Loading @@ -8,8 +13,7 @@ let # Oracle MySQL has supported "notify" service type since 8.0 hasNotify = isMariaDB || (isOracle && lib.versionAtLeast cfg.package.version "8.0"); mysqldOptions = "--user=${cfg.user} --datadir=${cfg.dataDir} --basedir=${cfg.package}"; mysqldOptions = "--user=${cfg.user} --datadir=${cfg.dataDir} --basedir=${cfg.package}"; format = pkgs.formats.ini { listsAsDuplicateKeys = true; }; configFile = format.generate "my.cnf" cfg.settings; Loading @@ -18,11 +22,31 @@ in { imports = [ (lib.mkRemovedOptionModule [ "services" "mysql" "pidDir" ] "Don't wait for pidfiles, describe dependencies through systemd.") (lib.mkRemovedOptionModule [ "services" "mysql" "rootPassword" ] "Use socket authentication or set the password outside of the nix store.") (lib.mkRemovedOptionModule [ "services" "mysql" "extraOptions" ] "Use services.mysql.settings.mysqld instead.") (lib.mkRemovedOptionModule [ "services" "mysql" "bind" ] "Use services.mysql.settings.mysqld.bind-address instead.") (lib.mkRemovedOptionModule [ "services" "mysql" "port" ] "Use services.mysql.settings.mysqld.port instead.") (lib.mkRemovedOptionModule [ "services" "mysql" "pidDir" ] "Don't wait for pidfiles, describe dependencies through systemd.") (lib.mkRemovedOptionModule [ "services" "mysql" "rootPassword" ] "Use socket authentication or set the password outside of the nix store.") (lib.mkRemovedOptionModule [ "services" "mysql" "extraOptions" ] "Use services.mysql.settings.mysqld instead.") (lib.mkRemovedOptionModule [ "services" "mysql" "bind" ] "Use services.mysql.settings.mysqld.bind-address instead.") (lib.mkRemovedOptionModule [ "services" "mysql" "port" ] "Use services.mysql.settings.mysqld.port instead.") ]; ###### interface Loading Loading @@ -137,7 +161,8 @@ in }; initialDatabases = lib.mkOption { type = lib.types.listOf (lib.types.submodule { type = lib.types.listOf ( lib.types.submodule { options = { name = lib.mkOption { type = lib.types.str; Loading @@ -154,7 +179,8 @@ in ''; }; }; }); } ); default = [ ]; description = '' List of database names and their initial schemas that should be used to create databases on the first startup Loading Loading @@ -190,7 +216,8 @@ in }; ensureUsers = lib.mkOption { type = lib.types.listOf (lib.types.submodule { type = lib.types.listOf ( lib.types.submodule { options = { name = lib.mkOption { type = lib.types.str; Loading Loading @@ -221,7 +248,8 @@ in ''; }; }; }); } ); default = [ ]; description = '' Ensures that the specified users exist and have at least the ensured permissions. Loading Loading @@ -251,7 +279,11 @@ in replication = { role = lib.mkOption { type = lib.types.enum [ "master" "slave" "none" ]; type = lib.types.enum [ "master" "slave" "none" ]; default = "none"; description = "Role of the MySQL server instance."; }; Loading Loading @@ -292,14 +324,13 @@ in }; ###### implementation config = lib.mkIf cfg.enable { services.mysql.dataDir = lib.mkDefault (if lib.versionAtLeast config.system.stateVersion "17.09" then "/var/lib/mysql" else "/var/mysql"); services.mysql.dataDir = lib.mkDefault ( if lib.versionAtLeast config.system.stateVersion "17.09" then "/var/lib/mysql" else "/var/mysql" ); services.mysql.settings.mysqld = lib.mkMerge [ { Loading @@ -311,7 +342,11 @@ in log-bin-index = "mysql-bin-${toString cfg.replication.serverId}.index"; relay-log = "mysql-relay-bin"; server-id = cfg.replication.serverId; binlog-ignore-db = [ "information_schema" "performance_schema" "mysql" ]; binlog-ignore-db = [ "information_schema" "performance_schema" "mysql" ]; }) (lib.mkIf (!isMariaDB) { plugin-load-add = [ "auth_socket.so" ]; Loading Loading @@ -355,12 +390,16 @@ in pkgs.nettools ]; preStart = if isMariaDB then '' preStart = if isMariaDB then '' if ! test -e ${cfg.dataDir}/mysql; then ${cfg.package}/bin/mysql_install_db --defaults-file=/etc/my.cnf ${mysqldOptions} touch ${cfg.dataDir}/mysql_init fi '' else '' '' else '' if ! test -e ${cfg.dataDir}/mysql; then ${cfg.package}/bin/mysqld --defaults-file=/etc/my.cnf ${mysqldOptions} --initialize-insecure touch ${cfg.dataDir}/mysql_init Loading @@ -379,10 +418,12 @@ in exec ${cfg.package}/bin/mysqld --defaults-file=/etc/my.cnf ${mysqldOptions} $_WSREP_NEW_CLUSTER $_WSREP_START_POSITION ''; postStart = let postStart = let # The super user account to use on *first* run of MySQL server superUser = if isMariaDB then cfg.user else "root"; in '' in '' ${lib.optionalString (!hasNotify) '' # Wait until the MySQL server is available for use while [ ! -e /run/mysqld/mysqld.sock ] Loading @@ -396,7 +437,9 @@ in 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 "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 Loading @@ -423,8 +466,7 @@ in fi '') cfg.initialDatabases} ${lib.optionalString (cfg.replication.role == "master") '' ${lib.optionalString (cfg.replication.role == "master") '' # Set up the replication master ( echo "use mysql;" Loading @@ -434,8 +476,7 @@ in ) | ${cfg.package}/bin/mysql -u ${superUser} -N ''} ${lib.optionalString (cfg.replication.role == "slave") '' ${lib.optionalString (cfg.replication.role == "slave") '' # Set up the replication slave ( echo "stop slave;" Loading @@ -444,8 +485,7 @@ in ) | ${cfg.package}/bin/mysql -u ${superUser} -N ''} ${lib.optionalString (cfg.initialScript != null) '' ${lib.optionalString (cfg.initialScript != null) '' # Execute initial script # using toString to avoid copying the file to nix store if given as path instead of string, # as it might contain credentials Loading @@ -463,12 +503,15 @@ in ) | ${cfg.package}/bin/mysql -N ''} ${lib.concatMapStrings (user: '' ( echo "CREATE USER IF NOT EXISTS '${user.name}'@'localhost' IDENTIFIED WITH ${if isMariaDB then "unix_socket" else "auth_socket"};" ${lib.concatStringsSep "\n" (lib.mapAttrsToList (database: permission: '' ${lib.concatMapStrings (user: '' ( echo "CREATE USER IF NOT EXISTS '${user.name}'@'localhost' IDENTIFIED WITH ${ if isMariaDB then "unix_socket" else "auth_socket" };" ${lib.concatStringsSep "\n" ( lib.mapAttrsToList (database: permission: '' echo "GRANT ${permission} ON ${database} TO '${user.name}'@'localhost';" '') user.ensurePermissions)} '') user.ensurePermissions )} ) | ${cfg.package}/bin/mysql -N '') cfg.ensureUsers} ''; Loading Loading @@ -500,7 +543,11 @@ in ProtectKernelTunables = true; ProtectKernelModules = true; ProtectControlGroups = true; RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ]; RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ]; LockPersonality = true; MemoryDenyWriteExecute = true; RestrictRealtime = true; Loading @@ -516,4 +563,6 @@ in ]; }; }; meta.maintainers = [ lib.maintainers._6543 ]; }