MySQL/MariaDB, logrotate, and SELinux

Assumption: You have SELinux Enforcing on your database server. If you’re still solving problems by permanently setting SELinux to Permissive, I don’t think you can really call yourself an IT professional.

Here are the commands to set the SELinux context of all text MySQL log files to var_log_t so that they can be rotated by logrotate:

semanage fcontext -a -t var_log_t "/var/lib/mysql(/.*\.log(-[0-9]+(\.gz)*)*)+"
restorecon -R -v -F /var/lib/mysql

NOTE: This expression will also match the file /var/lib/mysql/tc.log and change its context, which will prevent MySQL from starting. If your version of MySQL uses tc.log, here is one possibility:

semanage fcontext -a -t var_log_t "/var/lib/mysql(/db-server-01\.log(-[0-9]+(\.gz)*)*)+"

This expression is server-specific, because MySQL uses the hostname to name the log file.

An older Redhat Knowledge Base article recommends setting the context of the entire directory to var_log_t. This is poor advice when you accept the Redhat default of placing text log files in /var/lib/mysql. If you change the context of this directory to var_log_t, MySQL will not be able to start, because it will try to create the socket file mysql.sock with the wrong context (var_log_t)!

The semanage fcontext command operates on files with their complete path specified by a regular expression. Coming up with these regular expressions is not easy, so here is a tip to ensure that you are targeting exactly the right files:

find `pwd` | grep --color=auto -E "/var/lib/mysql(/.*\.log(-[0-9]+(\.gz)*)*)+"

Here’s how it works. The find command gives you a list of the full path to every file in the current directory. grep then uses colored output to show you which text is matched by your regular expression.

Finally, here’s my logrotate configuration. Note that you have to change the log names in the first line to match the actual log names on your server. The next time I configure a MySQL server, I might configure MySQL so that the log names do not contain the sever hostname, so that I can reuse the logrotate config files more easily. I also might put the text log files in a different path, to simplify the SELinux configuration.

# Rotate text logs daily or every 100MB, whichever comes first
/var/lib/mysql/sql-server-hostname.log /var/lib/mysql/sql-server-hostname.log{
    create 660 mysql mysql
    notifempty
    daily
    maxsize 100M
    dateext
    rotate 5
    missingok
    compress
    delaycompress
    postrotate
        # just if mysqld is really running
        if test -x /usr/bin/mysqladmin && \
           /usr/bin/mysqladmin ping &>/dev/null
        then
           echo "Flushing Logs"
           /usr/bin/mysqladmin flush-logs
        fi
    endscript
}

Leave a Reply