PNP4Nagios with SElinux on CentOS / RHEL 6

PNP4Nagios is commonly used to add performance graphs to a Nagios installation.

For additional security, SElinux is enabled on the monitoring host. There is no standard SElinux policy for applications like PNP4Nagios, so we need to develop a custom policy. This sounds harder than it actually is:

  • Run the software as you normally would (SElinux will interfere, so prepare for errors)
  • Extract audit messages and use them to create or update a local SElinux policy for the software
  • Repeat until everything works

In this example, I am running Nagios 3.2.3 with PNP4Nagios 0.6.16 on EL6, 64-bit.

After configuring Nagios and PNP4Nagios integration in Synchronous Mode (see documentation), I noticed that PNP4Nagios is not logging any performance data to /var/lib/pnp4nagios/.

Normally, PNP4Nagios should automatically create directories and files under /var/lib/pnp4nagios as performance data is received by Nagios. This smells of an SElinux issue, so check /var/log/audit/audit.log for suspicious messages. Sure enough, several audit messages have been logged. They look like this:

type=AVC msg=audit(1329129875.344:198212): avc:  denied  { getattr } for  pid=26692 comm="process_perfdat" \
    path="/var/lib/pnp4nagios/orac/Root_Partition.xml.26692" dev=dm-0 ino=1444378 \
    scontext=unconfined_u:system_r:nagios_t:s0 tcontext=unconfined_u:object_r:var_lib_t:s0 tclass=file
type=SYSCALL msg=audit(1329129875.344:198212): arch=c000003e syscall=5 success=no exit=-13 a0=3 a1=25440a0 \
    a2=25440a0 a3=0 items=0 ppid=26691 pid=26692 auid=0 uid=498 gid=498 euid=498 suid=498 fsuid=498 egid=498 \
    sgid=498 fsgid=498 tty=(none) ses=14942 comm="process_perfdat" exe="/usr/bin/perl" subj=unconfined_u:system_r:nagios_t:s0 key=(null)

Create a policy

You can run the “audit2allow” command (part of the policycoreutils-python RPM) to display suggested policy improvements based on the audit log:

audit2allow -a

The output can be saved in a file, for example local_nagios.te:

grep nagios_t /var/log/audit/audit.log | audit2allow -l -v -m local_nagios > local_nagios.te

This generates an output file suitable for compiling into a custom SElinux module.

Note: ALWAYS prefix the policy name with something like local_ to prevent overwriting system policies!

Test and refine the policy

Compile and load the SElinux policy module:

checkmodule -M -m -o local_nagios.mod local_nagios.te
semodule_package -o local_nagios.pp -m local_nagios.mod
semodule -v -i local_nagios.pp

Note: The above tools can be found in the checkpolicy and policycoreutils RPMs.

Re-run the software and check for SElinux audit messages. New issues can be captured and translated into a new policy:

grep nagios_t /var/log/audit/audit.log | audit2allow -l -v -m local_nagios > local_nagios.te_NEW

Merge the new results (in local_nagios.te_NEW) with your existing policy (in local_nagios.te). Compile and reload the module.

Lather, rinse, repeat ;-)

Results

After some iterations, your local_nagios.te file will look something like this:

module local_nagios 1.0;

require {
    type nagios_t;
    type var_log_t;
    type var_lib_t;
    class dir { write create add_name remove_name };
    class file { create getattr ioctl lock open read rename unlink write };
}

#============= nagios_t ==============
allow nagios_t var_lib_t:dir { add_name create remove_name write };
allow nagios_t var_lib_t:file { create getattr ioctl lock open read rename unlink write };
allow nagios_t var_log_t:file { read rename unlink };

If all is well, the audit.log should not show any new messages for nagios_t:

clear;tail -f /var/log/audit/audit.log |grep nagios_t

Note: The new SElinux policy will survive reboots; it is automatically copied to /etc/selinux/targeted/modules/active/modules/local_nagios.pp.

Enjoy!