Merge pull request #87833 from Izorkin/sandbox-mysql

This commit is contained in:
Jörg Thalheim 2020-06-16 18:13:43 +01:00 committed by GitHub
commit a9a5016644
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 51 additions and 9 deletions

View File

@ -94,6 +94,22 @@ services.mysql.initialScript = pkgs.writeText "mariadb-init.sql" ''
When MariaDB data directory is just upgraded (not initialized), the users are not created or modified.
</para>
</listitem>
<listitem>
<para>
MySQL server is now started with additional systemd sandbox/hardening options for better security. The PrivateTmp, ProtectHome, and ProtectSystem options
may be problematic when MySQL is attempting to read from or write to your filesystem anywhere outside of its own state directory, for example when
calling <literal>LOAD DATA INFILE or SELECT * INTO OUTFILE</literal>. In this scenario a variant of the following may be required:
- allow MySQL to read from /home and /tmp directories when using <literal>LOAD DATA INFILE</literal>
<programlisting>
systemd.services.mysql.serviceConfig.ProtectHome = lib.mkForce "read-only";
</programlisting>
- allow MySQL to write to custom folder <literal>/var/data</literal> when using <literal>SELECT * INTO OUTFILE</literal>, assuming the mysql user has write
access to <literal>/var/data</literal>
<programlisting>
systemd.services.mysql.serviceConfig.ReadWritePaths = [ "/var/data" ];
</programlisting>
</para>
</listitem>
</itemizedlist>
</section>

View File

@ -334,7 +334,8 @@ in
environment.etc."my.cnf".source = cfg.configFile;
systemd.tmpfiles.rules = [
"d '${cfg.dataDir}' 0700 ${cfg.user} mysql -"
"d '${cfg.dataDir}' 0700 ${cfg.user} mysql - -"
"z '${cfg.dataDir}' 0700 ${cfg.user} mysql - -"
];
systemd.services.mysql = let
@ -357,21 +358,17 @@ in
preStart = if isMariaDB then ''
if ! test -e ${cfg.dataDir}/mysql; then
${mysql}/bin/mysql_install_db --defaults-file=/etc/my.cnf ${mysqldOptions}
touch /tmp/mysql_init
touch ${cfg.dataDir}/mysql_init
fi
'' else ''
if ! test -e ${cfg.dataDir}/mysql; then
${mysql}/bin/mysqld --defaults-file=/etc/my.cnf ${mysqldOptions} --initialize-insecure
touch /tmp/mysql_init
touch ${cfg.dataDir}/mysql_init
fi
'';
serviceConfig = {
User = cfg.user;
Group = "mysql";
Type = if hasNotify then "notify" else "simple";
RuntimeDirectory = "mysqld";
RuntimeDirectoryMode = "0755";
Restart = "on-abort";
RestartSec = "5s";
# The last two environment variables are used for starting Galera clusters
@ -398,7 +395,7 @@ in
done
''}
if [ -f /tmp/mysql_init ]
if [ -f ${cfg.dataDir}/mysql_init ]
then
${concatMapStrings (database: ''
# Create initial databases
@ -452,7 +449,7 @@ in
cat ${toString cfg.initialScript} | ${mysql}/bin/mysql -u root -N
''}
rm /tmp/mysql_init
rm ${cfg.dataDir}/mysql_init
fi
${optionalString (cfg.ensureDatabases != []) ''
@ -476,6 +473,35 @@ in
# ensureDatbases & ensureUsers depends on this script being run as root
# when the user has secured their mysql install
"+${setupScript}";
# User and group
User = cfg.user;
Group = "mysql";
# Runtime directory and mode
RuntimeDirectory = "mysqld";
RuntimeDirectoryMode = "0755";
# Access write directories
ReadWritePaths = [ cfg.dataDir ];
# Capabilities
CapabilityBoundingSet = "";
# Security
NoNewPrivileges = true;
# Sandboxing
ProtectSystem = "strict";
ProtectHome = true;
PrivateTmp = true;
PrivateDevices = true;
ProtectHostname = true;
ProtectKernelTunables = true;
ProtectKernelModules = true;
ProtectControlGroups = true;
RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" "AF_INET6" ];
LockPersonality = true;
MemoryDenyWriteExecute = true;
RestrictRealtime = true;
RestrictSUIDSGID = true;
PrivateMounts = true;
# System Call Filtering
SystemCallArchitectures = "native";
};
};