1# SELinux <a id="selinux"></a>
2
3## Introduction <a id="selinux-introduction"></a>
4
5SELinux is a mandatory access control (MAC) system on Linux which adds a fine-grained permission system for access to all system resources such as files, devices, networks and inter-process communication.
6
7The most important questions are answered briefly in the [FAQ of the SELinux Project](https://selinuxproject.org/page/FAQ). For more details on SELinux and how to actually use and administrate it on your system have a look at [Red Hat Enterprise Linux 7 - SELinux User's and Administrator's Guide](https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/SELinux_Users_and_Administrators_Guide/index.html). For a simplified (and funny) introduction download the [SELinux Coloring Book](https://github.com/mairin/selinux-coloring-book).
8
9This documentation will use a format similar to the SELinux User's and Administrator's Guide.
10
11### Policy <a id="selinux-policy"></a>
12
13Icinga 2 provides its own SELinux policy. Development target is a policy package for Red Hat Enterprise Linux 7 and derivatives running the targeted policy which confines Icinga 2 with all features and all checks executed. All other distributions will require some tweaks.
14
15### Installation <a id="selinux-policy-installation"></a>
16
17There are two ways of installing the SELinux Policy for Icinga 2 on Enterprise Linux 7. The preferred way is to install the package. The other option involves installing the SELinux policy manually which might be necessary if you need some fixes which haven't made their way into a release yet.
18
19If the system runs in enforcing mode and you encounter problems you can set Icinga 2's domain to permissive mode.
20
21```
22# sestatus
23SELinux status:                 enabled
24SELinuxfs mount:                /sys/fs/selinux
25SELinux root directory:         /etc/selinux
26Loaded policy name:             targeted
27Current mode:                   enforcing
28Mode from config file:          enforcing
29Policy MLS status:              enabled
30Policy deny_unknown status:     allowed
31Max kernel policy version:      28
32```
33
34You can change the configured mode by editing `/etc/selinux/config` and the current mode by executing `setenforce 0`.
35
36#### Package installation <a id="selinux-policy-installation-package"></a>
37
38Simply add the `icinga2-selinux` package to your installation.
39
40```bash
41yum install icinga2-selinux
42```
43
44Ensure that the `icinga2` process is running in its own `icinga2_t` domain after installing the policy package:
45
46```
47# systemctl restart icinga2.service
48# ps -eZ | grep icinga2
49system_u:system_r:icinga2_t:s0   2825 ?        00:00:00 icinga2
50```
51
52#### Manual installation <a id="selinux-policy-installation-manual"></a>
53
54This section describes the installation to support development and testing. It assumes that Icinga 2 is already installed from packages and running on the system.
55
56As a prerequisite install the `git`, `selinux-policy-devel` and `audit` packages. Enable and start the audit daemon afterwards:
57
58```bash
59yum install git selinux-policy-devel audit
60systemctl enable auditd.service
61systemctl start auditd.service
62```
63
64After that clone the icinga2 git repository:
65
66```bash
67git clone https://github.com/icinga/icinga2
68```
69
70To create and install the policy package run the installation script which also labels the resources. (The script assumes Icinga 2 was started once after system startup, the labeling of the port will only happen once and fail later on.)
71
72```bash
73cd tools/selinux/
74./icinga.sh
75```
76
77After that restart Icinga 2 and verify it running in its own domain `icinga2_t`.
78
79```
80# systemctl restart icinga2.service
81# ps -eZ | grep icinga2
82system_u:system_r:icinga2_t:s0   2825 ?        00:00:00 icinga2
83```
84
85### General <a id="selinux-policy-general"></a>
86
87When the SELinux policy package for Icinga 2 is installed, the Icinga 2 daemon (icinga2) runs in its own domain `icinga2_t` and is separated from other confined services.
88
89Files have to be labeled correctly in order for Icinga 2 to be able to access them. For example the Icinga 2 log files have to have the `icinga2_log_t` label. Also the API port is labeled with `icinga_port_t`. Furthermore Icinga 2 can open high ports and UNIX sockets to connect to databases and features like Graphite. It executes the Nagios plugins and transitions to their context if those are labeled for example `nagios_services_plugin_exec_t` or `nagios_system_plugin_exec_t`.
90
91Additionally the Apache web server is allowed to connect to Icinga 2's command pipe in order to allow web interfaces to send commands to icinga2. This will perhaps change later on while investigating Icinga Web 2 for SELinux!
92
93### Types <a id="selinux-policy-types"></a>
94
95The command pipe is labeled `icinga2_command_t` and other services can request access to it by using the interface `icinga2_send_commands`.
96
97The nagios plugins use their own contexts and icinga2 will transition to it. This means plugins have to be labeled correctly for their required permissions. The plugins installed from package should have set their permissions by the corresponding policy module and you can restore them using `restorecon -R -v /usr/lib64/nagios/plugins/`. To label your own plugins use `chcon -t type /path/to/plugin`, for the type have a look at table below.
98
99Type                              | Domain                       | Use case                                                         | Provided by policy package
100----------------------------------|------------------------------|------------------------------------------------------------------|---------------------------
101nagios_admin_plugin_exec_t        | nagios_admin_plugin_t        | Plugins which require require read access on all file attributes | nagios
102nagios_checkdisk_plugin_exec_t    | nagios_checkdisk_plugin_t    | Plugins which require read access to all filesystem attributes   | nagios
103nagios_mail_plugin_exec_t         | nagios_mail_plugin_t         | Plugins which access the local mail service                      | nagios
104nagios_services_plugin_exec_t     | nagios_services_plugin_t     | Plugins monitoring network services                              | nagios
105nagios_system_plugin_exec_t       | nagios_system_plugin_t       | Plugins checking local system state                              | nagios
106nagios_unconfined_plugin_exec_t   | nagios_unconfined_plugin_t   | Plugins running without confinement                              | nagios
107nagios_eventhandler_plugin_exec_t | nagios_eventhandler_plugin_t | Eventhandler (actually running unconfined)                       | nagios
108nagios_openshift_plugin_exec_t    | nagios_openshift_plugin_t    | Plugins monitoring openshift                                     | nagios
109nagios_notification_plugin_exec_t | nagios_notification_plugin_t | Notification commands                                            | icinga (will be moved later)
110
111If one of those plugin domains causes problems you can set it to permissive by executing `semanage permissive -a domain`.
112
113The policy provides a role `icinga2adm_r` for confining an user which enables an administrative user managing only Icinga 2 on the system. This user will also execute the plugins in their domain instead of the users one, so you can verify their execution with the same restrictions like they have when executed by icinga2.
114
115### Booleans <a id="selinux-policy-booleans"></a>
116
117SELinux is based on the least level of access required for a service to run. Using booleans you can grant more access in a defined way. The Icinga 2 policy package provides the following booleans.
118
119**icinga2_can_connect_all**
120
121Having this boolean enabled allows icinga2 to connect to all ports. This can be necessary if you use features which connect to unconfined services, for example the [influxdb writer](14-features.md#influxdb-writer).
122
123**icinga2_run_sudo**
124
125To allow Icinga 2 executing plugins via sudo you can toogle this boolean. It is disabled by default, resulting in error messages like `execvpe(sudo) failed: Permission denied`.
126
127**httpd_can_write_icinga2_command**
128
129To allow httpd to write to the command pipe of icinga2 this boolean has to be enabled. This is enabled by default, if not needed you can disable it for more security.
130
131**httpd_can_connect_icinga2_api**
132
133Enabling this boolean allows httpd to connect to the API of icinga2 (Ports labeled `icinga2_port_t`). This is enabled by default, if not needed you can disable it for more security.
134
135### Configuration Examples <a id="selinux-policy-examples"></a>
136
137#### Run the icinga2 service permissive <a id="selinux-policy-examples-permissive"></a>
138
139If problems occur while running the system in enforcing mode and those problems are only caused by the policy of the icinga2 domain, you can set this domain to permissive instead of the complete system. This can be done by executing `semanage permissive -a icinga2_t`.
140
141Make sure to report the bugs in the policy afterwards.
142
143#### Confining a plugin <a id="selinux-policy-examples-plugin"></a>
144
145Download and install a plugin, for example check_mysql_health.
146
147```bash
148wget https://labs.consol.de/download/shinken-nagios-plugins/check_mysql_health-2.1.9.2.tar.gz
149tar xvzf check_mysql_health-2.1.9.2.tar.gz
150cd check_mysql_health-2.1.9.2/
151./configure --libexecdir /usr/lib64/nagios/plugins
152make
153make install
154```
155
156It is labeled `nagios_unconfined_plugins_exec_t` by default, so it runs without restrictions.
157
158```
159# ls -lZ /usr/lib64/nagios/plugins/check_mysql_health
160-rwxr-xr-x. root root system_u:object_r:nagios_unconfined_plugin_exec_t:s0 /usr/lib64/nagios/plugins/check_mysql_health
161```
162
163In this case the plugin is monitoring a service, so it should be labeled `nagios_services_plugin_exec_t` to restrict its permissions.
164
165```
166# chcon -t nagios_services_plugin_exec_t /usr/lib64/nagios/plugins/check_mysql_health
167# ls -lZ /usr/lib64/nagios/plugins/check_mysql_health
168-rwxr-xr-x. root root system_u:object_r:nagios_services_plugin_exec_t:s0 /usr/lib64/nagios/plugins/check_mysql_health
169```
170
171The plugin still runs fine but if someone changes the script to do weird stuff it will fail to do so.
172
173#### Allow icinga to connect to all ports. <a id="selinux-policy-examples-connectall"></a>
174
175You are running graphite on a different port than `2003` and want `icinga2` to connect to it.
176
177Change the port value for the graphite feature according to your graphite installation before enabling it.
178
179```
180# cat /etc/icinga2/features-enabled/graphite.conf
181/**
182 * The GraphiteWriter type writes check result metrics and
183 * performance data to a graphite tcp socket.
184 */
185
186library "perfdata"
187
188object GraphiteWriter "graphite" {
189  //host = "127.0.0.1"
190  //port = 2003
191  port = 2004
192}
193# icinga2 feature enable graphite
194```
195
196Before you restart the icinga2 service allow it to connect to all ports by enabling the boolean `icinga2_can_connect_all` (now and permanent).
197
198```bash
199setsebool icinga2_can_connect_all true
200setsebool -P icinga2_can_connect_all true
201```
202
203If you restart the daemon now it will successfully connect to graphite.
204
205#### Running plugins requiring sudo  <a id="selinux-policy-examples-sudo"></a>
206
207Some plugins require privileged access to the system and are designied to be executed via `sudo` to get these privileges.
208
209In this case it is the CheckCommand [running_kernel](10-icinga-template-library.md#plugin-contrib-command-running_kernel) which is set to use `sudo`.
210
211    # cat /etc/icinga2/conf.d/services.conf
212    apply Service "kernel" {
213      import "generic-service"
214
215      check_command = "running_kernel"
216
217      vars.running_kernel_use_sudo = true
218
219      assign where host.name == NodeName
220    }
221
222Having this Service defined will result in a UNKNOWN state and the error message `execvpe(sudo) failed: Permission denied` because SELinux dening the execution.
223
224Switching the boolean `icinga2_run_sudo` to allow the execution will result in the check executed successfully.
225
226    # setsebool icinga2_run_sudo true
227    # setsebool -P icinga2_run_sudo true
228
229#### Confining a user <a id="selinux-policy-examples-user"></a>
230
231If you want to have an administrative account capable of only managing icinga2 and not the complete system, you can restrict the privileges by confining
232this user. This is completly optional!
233
234Start by adding the Icinga 2 administrator role `icinga2adm_r` to the administrative SELinux user `staff_u`.
235
236```bash
237semanage user -m -R "staff_r sysadm_r system_r unconfined_r icinga2adm_r" staff_u
238```
239
240Confine your user login and create a sudo rule.
241
242```bash
243semanage login -a dirk -s staff_u
244echo "dirk ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/dirk
245```
246
247Login to the system using ssh and verify your id.
248
249```
250$ id -Z
251staff_u:staff_r:staff_t:s0-s0:c0.c1023
252```
253
254Try to execute some commands as root using sudo.
255
256```
257$ sudo id -Z
258staff_u:staff_r:staff_t:s0-s0:c0.c1023
259$ sudo vi /etc/icinga2/icinga2.conf
260"/etc/icinga2/icinga2.conf" [Permission Denied]
261$ sudo cat /var/log/icinga2/icinga2.log
262cat: /var/log/icinga2/icinga2.log: Permission denied
263$ sudo systemctl reload icinga2.service
264Failed to get D-Bus connection: No connection to service manager.
265```
266
267Those commands fail because you only switch to root but do not change your SELinux role. Try again but tell sudo also to switch the SELinux role and type.
268
269```
270$ sudo -r icinga2adm_r -t icinga2adm_t id -Z
271staff_u:icinga2adm_r:icinga2adm_t:s0-s0:c0.c1023
272$ sudo -r icinga2adm_r -t icinga2adm_t vi /etc/icinga2/icinga2.conf
273"/etc/icinga2/icinga2.conf"
274$ sudo -r icinga2adm_r -t icinga2adm_t cat /var/log/icinga2/icinga2.log
275[2015-03-26 20:48:14 +0000] information/DynamicObject: Dumping program state to file '/var/lib/icinga2/icinga2.state'
276$ sudo -r icinga2adm_r -t icinga2adm_t systemctl reload icinga2.service
277```
278
279Now the commands will work, but you have always to remember to add the arguments, so change the sudo rule to set it by default.
280
281```bash
282echo "dirk ALL=(ALL) ROLE=icinga2adm_r TYPE=icinga2adm_t NOPASSWD: ALL" > /etc/sudoers.d/dirk
283```
284
285Now try the commands again without providing the role and type and they will work, but if you try to read apache logs or restart apache for example it will still fail.
286
287```
288$ sudo cat /var/log/httpd/error_log
289/bin/cat: /var/log/httpd/error_log: Keine Berechtigung
290$ sudo systemctl reload httpd.service
291Failed to issue method call: Access denied
292```
293
294## Bugreports <a id="selinux-bugreports"></a>
295
296If you experience any problems while running in enforcing mode try to reproduce it in permissive mode. If the problem persists it is not related to SELinux because in permissive mode SELinux will not deny anything.
297
298After some feedback Icinga 2 is now running in a enforced domain, but still adds also some rules for other necessary services so no problems should occure at all. But you can help to enhance the policy by testing Icinga 2 running confined by SELinux.
299
300Please add the following information to [bug reports](https://icinga.com/community/):
301
302* Versions, configuration snippets, etc.
303* Output of `semodule -l | grep -e icinga2 -e nagios -e apache`
304* Output of `ps -eZ | grep icinga2`
305* Output of `semanage port -l | grep icinga2`
306* Output of `audit2allow -li /var/log/audit/audit.log`
307
308If access to a file is blocked and you can tell which one please provided the output of `ls -lZ /path/to/file` (and perhaps the directory above).
309
310If asked for full audit.log add `-w /etc/shadow -p w` to `/etc/audit/rules.d/audit.rules`, restart the audit daemon, reproduce the problem and add `/var/log/audit/audit.log` to the bug report. With the added audit rule it will include the path of files access was denied to.
311
312If asked to provide full audit log with dontaudit rules disabled executed `semodule -DB` before reproducing the problem. After that enable the rules again to prevent auditd spamming your logfile by executing `semodule -B`.
313