MySQL-Datenbank auf dedizierter Partition unter SELinux

Bei aktiviertem SELinux gestaltet sich die Auslagerung der Datenbank auf einer dedizierten Partition ein wenig kompizierter als bei deaktiviertem SELinux. Der Hintergrund ist, dass SELinux den Zugriff auf sämtliche Ressourcen stark reglementiert (das ist ja der Sinn hinter SELinux!). Durch Setzen von SELinux-Labels können die SELinux-unbekannten Verzeichnisse wieder die benötigten Rechte erhalten.

Rund um MySQL gibt es die folgenden Labels:

SELinux-TypBedeutung
mysqld_db_t
Dieses Flag kennzeichnet Dateien der MySQL-Datenbank. Diese Dateien liegen standardmäßig unter /var/lib/mysql.
mysqld_etc_t
Label für die Hauptkonfigurationsdatei (/etc/my.cnf) oder zusätzliche Konfigurationsdateien der MySQL-Datenbank (i.d.R. unterhalb /etc/mysql).
mysqld_exec_t
Flag für das Binärprogramm der MySQL-Datenbank - standardmäßig liegt es unter /usr/libexec/mysqld. Es gilt nicht für /usr/bin/mysqld_safe - hierfür gibt es ein eigenes Label
mysqld_safe_exec_t
Label für das zu verwendende Binärprogramm zum Betreiben einer MySQL-Datenbank - standardmäßig liegt es unter /usr/bin/mysqld_safe. Eine MySQL-Datenbank wird in der Regel über dieses Programm und nicht direkt über /usr/lib/exec/mysqld gestartet - das o.g. Programm fügt Sicherheitsfunktionen und Logging-Mechanismen hinzu.
mysqld_initrc_exec_t
Dieses Flag kennzeichnet das Init-Skript unterhalb /etc/rc.d/init.d - einige Distirbutionen, wie z. B. RHEL, verlinken /etc/rc.d/init.d und /etc/init.d, wodurch beide Skripte verlinkt sind und über die selben SELinux-Label verfügen.
mysqld_log_t
Log-Dateien, in die MySQL schreiben darf, müssen mit diesem Label versehen werden. Standardmäßig gilt dieses Label für die Wildcard /var/log/mysql.*.
mysqld_var_run_t
PID-Files und Sockets müssen mit diesem Flag versehen werden, damit MySQL startet. Das PID-File und evtl. Sockets liegen i.d.R. unter /var/run/mysqld/mysqld.pid und /var/lib/mysql/mysql.sock

Im folgenden Beispiel sollen die Daten einer lokal installierten MySQL-Datenbank von /var/lib/mysql nach /data/mysql verschoben werden.

Zuerst wird die Datenbank gestoppt und die Konfigurationsdatei dahingehend angepasst, dass sie auf den neuen Pfad zeigt:

1# service mysqld stop
2# cp /etc/my.cnf /etc/my.cnf.initial
3# vi /etc/my.cnf
4...
5datadir=/data/mysql
6socket=/var/lib/mysql/mysql.sock
7...
8ZZ

Anschließend wird das neue Verzeichnis angelegt und erhält eine Kopie der vorherigen MySQL-Daten unter Berücksichtigung der Zugriffsrechte:

1# mkdir -p /data/mysql
2# cp --preserve=all -R /var/lib/mysql/* /data/mysql/

Das SELinux-Label "mysqld_db_t" (siehe oben) wurden nicht übernommen, da sie nicht in den Inodes des Dateisystems gespeichert werden. Sie werden manuell vergeben:

1# semanage fcontext -a -t mysqld_db_t "/data/mysql(/.*)?"
2# restorecon -R -v /data/mysql

Build all the SELinux rules!

Versucht man jetzt, den MySQL-Dienst zu starten, schlägt das fehl. Es wird noch eine SELinux-Regel benötigt, die den Zugriff auf die dedizierte Partition erlaubt. In der SELinux-Logdatei (/var/log/audit/audit.log) werden alle Regelverstöße vermerkt. Mithilfe von audit2allow kann eine Ausnahmeregel, die später zu einem Modul gebündelt wird, erstellt werden. Nach der Installation des Moduls funktioniert der Zugriff.

Eine detailliertere Fehlermeldung des Regelverstoßes lässt sich mit audit2why anzeigen:

1# audit2why < /var/log/audit/audit.log

Es empfiehlt sich vorher das Audit-Log zu leeren, damit auch wirklich nur der MySQL-Regelverstoß erfasst und zu einem Modul konvertiert wird:

1# > /var/log/audit/audit.log
2# service mysqld start
3# audit2allow -m local < /var/log/audit/audit.log > local.te

Die generierte Datei local.te sollte eine solche Konfiguration enthalten:

 1# cat local.te
 2
 3module local 1.0;
 4
 5require {
 6        type file_t;
 7        type mysqld_t;
 8        class dir { getattr search };
 9}
10
11#============= mysqld_t =============
12allow mysqld_t file_t:dir { getattr search };

Anschließend wird ein Modul generiert und installiert. Es empfiehlt sich, die Datei local.te aufzubewahren, um eventuelle spätere Ausnahmeregeln darin zu dokumentieren.

1# checkmodule -M -m -o local.mod local.te
2checkmodule:  loading policy configuration from local.te
3checkmodule:  policy configuration loaded
4checkmodule:  writing binary representation (version 10) to local.mod
5
6# semodule_package -o local.pp -m local.mod
7# semodule -i local.pp

Anschließend kann MySQL auch gestartet werden:

1# service mysqld start
2Starting mysqld:                  [  OK  ]

🙂