Using syslog-ng with SELinux in enforcing mode

Security-Enhanced Linux (SELinux) is a set of kernel and user-space tools enforcing strict access control policies. It is also the tool behind at least half of the syslog-ng problem reports. SELinux rules in Linux distributions cover all aspects of the syslog-ng configuration coming in the syslog-ng package available in the distribution. But as soon as an unusual port number or directory name is specified in the configuration, syslog-ng fails to work even with a perfectly legitimate configuration. While preventing unusual access is the main feature of SELinux, it also causes lots of headaches for unsuspecting administrators. Learn how you can use syslog-ng with SELinux in enforcing mode.

 

SELinux basics

Even the basics of SELinux would require writing several pages. If you want to learn about SELinux in depth, check the “Further reading” section at the end of my blog. Here, I only focus on some practical information.

First of all, make sure that SELinux is in enforcing mode on your machine. It is often disabled during installation, or a debugging session, and it is usually never turned on again. The following example is from CentOS 7.3, but it should look similar on any other distributions. First we list the configuration file and check if SELinux is in enforcing mode using the getenforce command.

[root@selinux ~]# cat /etc/selinux/config 
 
# This file controls the state of SELinux on the system.
 
# SELINUX= can take one of these three values:
 
# enforcing - SELinux security policy is enforced.
 
# permissive - SELinux prints warnings instead of enforcing.
 
# disabled - No SELinux policy is loaded.
 
SELINUX=enforcing
 
# SELINUXTYPE= can take one of three two values:
 
# targeted - Targeted processes are protected,
 
# minimum - Modification of targeted policy. Only selected processes are protected. 
 
# mls - Multi Level Security protection.
 
SELINUXTYPE=targeted 
 
[root@selinux ~]# getenforce 
 
Enforcing
 
[root@selinux ~]#

If it is not set to enforcing mode, change the configuration file and reboot. Disabling SELinux completely is not recommended. When SELinux is re-enabled, you also need to relabel the file system using restorecon. You can temporarily disable SELinux using the setenforce command and check the results using getenforce:

[root@selinux ~]# setenforce 0
 
[root@selinux ~]# getenforce 
 
Permissive
 
[root@selinux ~]# setenforce 1
 
[root@selinux ~]# getenforce 
 
Enforcing
 
[root@selinux ~]# 

In permissive mode, SELinux detects policy violations and logs them, but does not enforce the rules. It can be used for debugging purposes. If you use setenforce 0, you can be sure that SELinux will not stay disabled accidentally.

 

Logging

SELinux logs are collected by auditd to the /var/log/audit/audit.log file. When you start syslog-ng with a default distro configuration, the only line you will see in the logs is that a new service was started:

[root@selinux ~]# grep syslog-ng /var/log/audit/audit.log 
 
type=SERVICE_START msg=audit(1494923144.043:303): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=syslog-ng comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=success'
[root@selinux ~]# 

You can parse the content of this file using the linux-audit-parser() feature of recent syslog-ng releases. Read more about it in the documentation at https://syslog-ng.com/documents/html/syslog-ng-ose-latest-guides/en/syslog-ng-ose-guide-admin/html/linux-audit-parser.html

In SELinux access is granted based on labels. You can list these labels for files and processes as well, usually by using capital Z as an option in the command.

[root@selinux ~]# ls -dZ /var/log/
 
drwxr-xr-x. root root system_u:object_r:var_log_t:s0 /var/log/
 
[root@selinux ~]# ps Zx | grep syslog-ng
 
system_u:system_r:syslogd_t:s0 47809 ? Ssl 0:00 /usr/sbin/syslog-ng -F -p /var/run/syslogd.pid
 
[root@selinux ~]# 


Using a different storage directory

You save your local log messages under the /var/log directory. But logs of a central syslog-ng server are often saved to a separate partition, for example to the /data/logs directory.

You modify your syslog-ng.conf, restart syslog-ng and cannot see any logs in the directory. What happened?

In /var/log/audit/audit.log you will find that syslog-ng was denied access to the directory called “logs”:

type=AVC msg=audit(1494927489.413:407): avc: denied { write } for pid=50082 comm="syslog-ng" name="logs" dev="dm-0" ino=35096600 scontext=system_u:system_r:syslogd_t:s0 tcontext=unconfined_u:object_r:default_t:s0 tclass=dir

If you take a look at /var/log/messages, you can find a similar message:

May 16 11:40:44 selinux syslog-ng[50082]: Error opening file for writing; filename='/data/logs/file', error='No such file or directory (2)'

It might even suggest that the problem is SELinux and you should use the audit2allow command to resolve permission problems. As usual, life is not this easy, as audit2allow would change permissions in a way so that syslog-ng receives too much access. You should rather do the changes yourself.

As you can see from the above directory listing the /var/log directory has the var_log_t label. When you list the freshly created directory, it has something different:

[root@selinux conf.d]# ls -ldZ /data/logs/
 
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /data/logs/
 
[root@selinux conf.d]#

You can change it the label to var_log_t using the chcon command and check the results using the Z option of the ls command:

[root@selinux conf.d]# chcon -t var_log_t /data/logs/
 
[root@selinux conf.d]# ls -ldZ /data/logs/
 
drwxr-xr-x. root root unconfined_u:object_r:var_log_t:s0 /data/logs/
 
[root@selinux conf.d]# 

The problem with this approach is, that the change is temporary. It will be lost when you reboot the machine or restore SELinux labels using the restorecon command.

[root@selinux conf.d]# restorecon -v /data/logs/
 
restorecon reset /data/logs context unconfined_u:object_r:var_log_t:s0->unconfined_u:object_r:default_t:s0
 
[root@selinux conf.d]# ls -ldZ /data/logs/
 
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 /data/logs/
 
[root@selinux conf.d]#

Using the following semanage command, you can make the changes permanent:

[root@selinux conf.d]# semanage fcontext -a -t var_log_t '/data/logs(./*)?'
 
[root@selinux conf.d]# restorecon -v /data/logs/
 
restorecon reset /data/logs context unconfined_u:object_r:default_t:s0->unconfined_u:object_r:var_log_t:s0
 
[root@selinux conf.d]# ls -ldZ /data/logs/
 
drwxr-xr-x. root root unconfined_u:object_r:var_log_t:s0 /data/logs/

Now your logs should appear in the directory.

 

Using a different port

By default, SELinux only allows connections to the default syslog ports. Here we list syslog-related ports as known by SELinux:

[root@selinux conf.d]# semanage port --list | grep syslog
 
syslog_tls_port_t tcp 6514
 
syslog_tls_port_t udp 6514
 
syslogd_port_t tcp 601
 
syslogd_port_t udp 514, 601
 
[root@selinux conf.d]# 

This can be problematic, if you have to use another port for any reason. A common scenario is to enable port 514 also for TCP log messages. You can also learn about Life, the Universe and Everything by collecting some logs on port 42. Or more seriously: use different port numbers for different log message types to make parsing of logs easier.

If you add port 42 (or any other ports, 42 is just an example) and restart syslog-ng without configuring SELinux, it will fail to start. You can check the error message in the journal using journalctl. You will find the following:

May 17 09:55:35 selinux.localdomain setroubleshoot[3640]: SELinux is preventing /usr/sbin/syslog-ng from name_bind access on the tcp_socket port 42. For complete SELinux messages. run sealert -l ff7a7f22-128e-4b
 
May 17 09:55:35 selinux.localdomain python[3640]: SELinux is preventing /usr/sbin/syslog-ng from name_bind access on the tcp_socket port 42.

You can add the TCP port 42 to syslogd_port_t using the following commands, and check it with a port listing to make sure that it is really added:

[root@selinux ~]# semanage port -a -t syslogd_port_t -p tcp 42
 
[root@selinux ~]# semanage port --list | grep sysl
 
syslog_tls_port_t tcp 6514
 
syslog_tls_port_t udp 6514
 
syslogd_port_t tcp 42, 601
 
syslogd_port_t udp 514, 601

After this syslog-ng starts fine and netstat shows that it is listening on port 42. The quest is still not over, as sending logs to port 42 from the outside world still does not work. The culprit in this case is firewalld, which makes sure that no connection is made to an unexpected port. Here we open up TCP port 42, reload the firewall rules to enable the configuration and finally we list ports opened on the firewall.

[root@selinux conf.d]# firewall-cmd --permanent --add-port=42/tcp
 
success
 
[root@selinux conf.d]# firewall-cmd --reload
 
success
 
[root@selinux conf.d]# firewall-cmd --list-ports
 
42/tcp

Now syslog-ng is able to receive those log messages about Life, the Universe and Everything on port 42.

 

Further reading

Here, I provided some basic information how to use non-default directories or ports for logging. For more in-depth knowledge about SELinux and firewalld, these websites provide useful information:

Related Content