Working with SELinux¶
The Linux kernel, through the Linux Security Module (LSM), supports Security-Enhanced Linux (SELinux). This module provides a way to support mandatory access control policies. SELinux defines how confined processes interact with files, network ports, directories, other processes, and additional server components.
An SELinux policy defines the set of rules, the types
for files, and the domains
for processes. Rules determine how a process interacts with another type. SELinux decides whether to allow or deny an action based on the subject’s context, what object initiates the action and what object is the action’s target.
A label represents the context for administrators and users.
CentOS 7 and CentOS 8 contain a MySQL SELinux policy. Percona Server for MySQL is a drop-in replacement for MySQL and can use this policy without changes.
SELinux context example¶
To view the SELinux context, add the -Z
switch to many of the utilities. Here is an example of the context for mysqld
:
$ ps -eZ | grep mysqld_t
Expected output
system_u:system_r:mysqld_t:s0 3356 ? 00:00:01 mysqld
The context has the following properties:
-
User - system_u
-
Role - system_r
-
Type or domain - mysqld_t
-
Sensitivity level - s0 3356
Most SELinux policy rules are based on the type or domain.
List SELinux types or domains associated with files¶
The security property that SELinux relies on is the Type security property. The type name often end with a _t
. A group of objects with the same type security value belongs to the same domain.
To view the mysqldb_t
types associated with the MySQL directories and files, run the following command:
$ ls -laZ /var/lib/ | grep mysql
Expected output
drwxr-x--x. mysql mysql system_u:object_r:mysqld_db_t:s0 mysql
drwxr-x---. mysql mysql system_u:object_r:mysqld_db_t:s0 mysql-files
drwxr-x---. mysql mysql system_u:object_r:mysqld_db_t:s0 mysql-keyring
Note
If a policy type does not define the type property for an object, the default value is unconfined_t
.
SELinux modes¶
SELinux has the following modes:
-
Disabled - No SELinux policy modules loaded, which disables policies. Nothing is reported.
-
Permissive - SELinux is active, but policy modules are not enforced. A policy violation is reported but does not stop the action.
-
Enforcing - SELinux is active, and violations are reported and denied. If there is no rule to allow access to a confined resource, SELinux denies the access.
Policy types¶
SELinux has several policy types:
-
Targeted - Most processes operate without restriction. Specific services are contained in security domains and defined by policies.
-
Strict - All processes are contained in security domains and defined by policies.
SELinux has confined processes that run in a domain and restricts everything unless explicitly allowed. An unconfined process in an unconfined domain is allowed almost all access.
MySQL is a confined process, and the policy module defines which files are read, which ports are opened, and so on. SELinux assumes the Percona Server for MySQL installation uses the default file locations and default ports.
If you change the default, you must also edit the policy. If you do not update the policy, SELinux, in enforcing mode, denies access to all non-default resources.
Check the SELinux mode¶
To check the current SELinux mode, use either of the following commands:
$ sestatus
Expected output
SELinux status: enabled
SELinuxfs mount: /sys/fs/selinux
SELinux root directory: /etc/selinux
Loaded policy name: targeted
Current mode: enforcing
Mode from config file: enforcing
Policy MLS status: enabled
Policy deny_unknown status: allowed
Memory protection checking: actual (secure)
Max kernel policy version: 31
or
$ grep ^SELINUX= /etc/selinux/config
Expected output
SELINUX=enforcing
Note
Add the -b
parameter to sestatus
to display the Policy booleans
. The boolean values for each parameter is shown. An example of using the b
parameter is the following:
$ sestatus -b | grep mysql
Expected output
mysql_connect_any off
selinuxuser_mysql_connect_enabled
The /etc/selinux/config
file controls if SELinux is disabled or enabled, and if enabled, whether SELinux operates in enforcing mode or permissive mode.
Disable SELinux¶
If you plan to use the enforcing mode at another time, use the permissive mode instead of disabling SELinux. During the time that SELinux is disabled, the system may contain mislabeled objects or objects with no label. If you re-enable SELinux and plan to set SELinux to enforcing, you must follow the steps to Relabel the entire file system.
On boot, to disable SELinux, set the selinux=0
kernel option. The kernel does not load the SELinux infrastructure. This option has the same effect as changing the SELINUX=disabled
instruction in the configuration file and then rebooting the system.
Additional SELinux tools¶
Install the SELinux management tools, such as semanage
or sesearch
, if needed.
On RHEL 7 or compatible operating systems, use the following command as root:
$ yum -y install policycoreutils-python
On RHEL 8 or compatible operating systems, use the following command as root:
$ yum -y install policycoreutils-python-utils
Note
You may need root privileges to run SELinux management commands.
Switch the mode in the configuration file¶
Switching between modes may help when troubleshooting or when modifying rules.
To permanently change the mode, edit the /etc/selinux/config
file and change the SELINUX=
value. You should also verify the change.
$ cat /etc/selinux/config | grep SELINUX= | grep -v ^#
Expected output
SELINUX=enforcing
SELINUX=enforcing
$ sudo sed -i 's/^SELINUX=.*/SELINUX=permissive/g' /etc/selinux/config
$ cat /etc/selinux/config | grep SELINUX= | grep -v ^#
Expected output
SELINUX=permissive
SELINUX=permissive
Reboot your system after the change.
If switching from either disabled mode or permissive mode to enforcing, see Relabel the entire file system.
Switch the mode until the next reboot¶
To change the mode until the next reboot, use either of the following commands as root:
$ setenforce Enforcing
or
$ setenforce 1
The following setenforce
parameters are available:
setenforce parameters | Also Permitted |
---|---|
0 | Permissive |
1 | Enforcing |
You can view the current mode by running either of the following commands:
$ getenforce
Expected output
Enforcing
or
$ sestatus | grep -i mode
Expected output
Current mode: permissive
Mode from config file: enforcing
Switch the mode for a service¶
You can move one or more services into a permissive domain. The other services remain in enforcing mode.
To add a service to the permissive domain, run the following as root:
$ sudo semanage permissive -a mysqld_t
To list the current permissive domains, run the following command:
$ sudo semanage permissive -l
Expected output
...
Customized Permissive Types
mysqld_t
Builtin Permissive Types
...
To delete a service from the permissive domain, run the following:
$ sudo semanage permissive -d mysqld_t
The service returns to the system’s SELinux mode. Be sure to follow the steps to Relabel the entire file system.
Relabel the entire file system¶
Switching from disabled or permissive to enforcing requires additional steps. The enforcing mode requires the correct contexts, or labels, to function. The permissive mode allows users and processes to label files and system objects incorrectly. The disabled mode does not load the SELinux infrastructure and does not label resources or processes.
RHEL and compatible systems, use the fixfiles
application for relabeling. You can relabel the entire file system or the file contexts of an application.
For one application, run the following command:
$ fixfiles -R mysqld restore
To relabel the file system without rebooting the system, use the following command:
$ fixfiles -f -F relabel
Another option relabels the file system during a reboot. You can either add a touch file, read during the reboot operation, or configure a kernel boot parameter. The completion of the relabeling operation automatically removes the touch file.
Add the touch file as root:
$ touch /.autorelabel
To configure the kernel, add the autorelabel=1
kernel parameter to the boot parameter list. The parameter forces a system relabel. Reboot in permissive mode to allow the process to complete before changing to enforcing.
Note
Relabeling an entire filesystem takes time. When the relabeling is complete, the system reboots again.
Set a custom data directory¶
If you do not use the default settings, SELinux, in enforcing mode, prevents access to the system.
For example, during installation, you have used the following configuration:
datadir=/var/lib/mysqlcustom
socket=/var/lib/mysqlcustom/mysql.sock
Restart the service.
$ service mysqld restart
Expected output
Redirecting to /bin/systemctl restart mysqld.service
Job for mysqld.service failed because the control process exited with error code.
See "systemctl status mysqld.service" and "journalctl -xe" for details.
Check the journal log to see the error code.
$ journalctl -xe
Expected output
...
SELinux is preventing mysqld from getattr access to the file /var/lib/mysqlcustom/ibdata1.
...
Check the SELinux types in /var/lib/mysqlcustom
.
ls -1aZ /var/lib/mysqlcustom
Expected output
total 164288
drwxr-x--x. 6 mysql mysql system_u:object_r:var_lib_t:s0 4096 Dec 2 07:58 .
drwxr-xr-x. 38 root root system_u:object_r:var_lib_t:s0 4096 Dec 1 14:29 ..
...
-rw-r-----. 1 mysql mysql system_u:object_r:var_lib_t:s0 12582912 Dec 1 14:29 ibdata1
...
To solve the issue, use the following methods:
-
Set the proper labels for
mysqlcustom
files -
Change the mysqld SELinux policy to allow mysqld access to
var_lib_t
files.
The recommended solution is to set the proper labels. The following procedure assumes you have already created and set ownership to the custom data directory location:
-
To change the SELinux context, use
semanage fcontext
. In this step, you define how SELinux deals with the custom paths:$ semanage fcontext -a -e /var/lib/mysql /var/lib/mysqlcustom
SELinux applies the same labeling schema, defined in the mysqld policy, for the
/var/lib/mysql
directory to the custom directory. Files created within the custom directory are labeled as if they were in/var/lib/mysql
. -
To
restorecon
command applies the change.$ restorecon -R -v /var/lib/mysqlcustom
-
Restart the mysqld service:
$ service mysqld start
Set a custom log location¶
If you do not use the default settings, SELinux, in enforcing mode, prevents access to the location. Change the log location to a custom location in my.cnf:
log-error=/logs/mysqld.log
Verify the log location with the following command:
$ ls -laZ /
Expected output
...
drwxrwxrwx. 2 root root unconfined_u:object_r:default_t:s0 6 Dec 2 09:16 logs
...
Starting MySQL returns the following message:
$ service mysql start
Expected output
Redirecting to /bin/systemctl start mysql.service
Job for mysqld.service failed because the control process exited with error code.
See "systemctl status mysqld.service" and "journalctl -xe" for details.
$ journalctl -xe
...
SELinux is preventing mysqld from write access to the directory logs.
...
The default SELinux policy allows mysqld to write logs into a location tagged with var_log_t
, which is the /var/log
location. You can solve the issue with either of the following methods:
-
Tag the
/logs
location properly -
Edit the SELinux policy to allow mysqld access to all directories.
To tag the custom /logs
location is the recommended method since it locks down access. Run the following commands to tag the custom location:
$ semanage fcontext -a -t var_log_t /logs
$ restorecon -v /logs
You may not be able to change the /logs
directory label. For example, other applications, with their own rules, use the same directory.
To adjust the SELinux policy when a directory is shared, follow these steps:
-
Create a local policy:
ausearch -c 'mysqld' --raw | audit2allow -M my-mysqld
-
This command generates the my-mysqld.te and the my-mysqld.pp files. The mysqld.te is the type enforcement policy file. The my-mysqld.pp is the policy module loaded as a binary file into the SELinux subsystem.
An example of the my-myslqd.te file:
module my-mysqld 1.0; require { *type mysqld_t*; type var_lib_t; *type default_t*; class file getattr; *class dir write*; } ============= mysqld_t ============== *allow mysqld_t default_t:dir write*; allow mysqld_t var_lib_t:file getattr;
The policy contains rules for the custom data directory and the custom logs directory. We have set the proper labels for the data directory location, and applying this auto-generated policy would loosen our hardening by allowing mysqld to access
var_lib_t
tags. -
SELinux-generated events are converted to rules. A generated policy may contain rules for recent violations and include unrelated rules. Unrelated rules are generated from actions, such as changing the data directory location, that are not related to the logs directory. Add the
--start
parameter to use log events after a specific time to filter out the unwanted events. This parameter captures events when the time stamp is equal to the specified time or later. SELinux generates a policy for the current actions.$ ausearch --start 10:00:00 -c 'mysqld' --raw | audit2allow -M my-mysqld
-
This policy allows mysqld writing into the tagged directories. Open the my_mysqld file:
module my-mysqld 1.0; require { type mysqld_t; type default_t; class dir write; } ============= mysqld_t ============== allow mysqld_t default_t:dir write;
-
Install the SELinux policy module:
$ semodule -i my-mysqld.pp
Restart the service. If you have a failure, check the journal log and follow the same procedure.
If SELinux prevents mysql from creating a log file inside the directory. You can view all the violations by changing the SELinux mode to permissive
and then running mysqld. All violations are logged in the journal log. After this run, you can generate a local policy module, install it, and switch SELinux back to enforcing
mode. Follow this procedure:
-
Unload the current local my-mysqld policy module:
$ semodule -r my-mysqld
-
You can put a single domain into permissive mode. Other domains on the system to remain in enforcing mode. Use
semanage permissive
with the-a
parameter to change mysqld_t to permissive mode:$ semanage permissive -a mysqld_t
-
Verify the mode change:
$ semdule -l | grep permissive
Expected output
... permissive_mysqld_t ...
-
To make searching the log easier, return the time:
$ date
-
Start the service.
$ service mysqld start
-
MySQL starts, and SELinux logs the violations in the journal log. Check the journal log:
$ journalctl -xe
-
Stop the service:
$ service mysqld stop
-
Generate a local mysqld policy, using the time returned from step 4:
$ ausearch --start <date-c 'mysqld' --raw | audit2allow -M my-mysqld
-
Review the policy (the policy you generate may be different):
$ cat my-mysqld.te
Expected output
module my-mysqld 1.0; require { type default_t; type mysqld_t; class dir { add_name write }; class file { append create open }; } ============= mysqld_t ============== allow mysqld_t default_t:dir { add_name write }; allow mysqld_t default_t:file { append create open };
-
Install the policy:
$ semodule -i my-mysqld.pp
-
Use
semanage permissive
with the-d
parameter, which deletes the permissive domain for the service:$ semanage permissive -d mysqld_t
-
Restart the service:
$ service mysqld start
Note
Use this procedure to adjust the local mysqld policy module. You should review the changes which are generated to ensure the rules are not too tolerant.
Set secure_file_priv
directory¶
Update the SELinux tags for the /var/lib/mysql-files/
directory, used for SELECT ... INTO OUTFILE
or similar operations, if required. The server needs only read/write access to the destination directory.
To set secure_file_priv
to use this directory, run the following commands to set the context:
$ semanage fcontext -a -t mysqld_db_t "/var/lib/mysql-files/(/.*)?"
$ restorecon -Rv /var/lib/mysql-files
Edit the path for a different location, if needed.
Get expert help¶
If you need assistance, visit the community forum for comprehensive and free database knowledge, or contact our Percona Database Experts for professional support and services.