Merge branch 'feature/selinux-8270'

resolves #8270
This commit is contained in:
Eric Lippmann 2016-12-13 12:31:51 +01:00
commit eed1d7ab68
6 changed files with 327 additions and 4 deletions

119
doc/90-SELinux.md Normal file
View File

@ -0,0 +1,119 @@
# <a id="selinux"></a> SELinux
## <a id="selinux-introduction"></a> Introduction
SELinux is a mandatory access control (MAC) system on Linux which adds a fine granular permission system for access
to all resources on the system such as files, devices, networks and inter-process communication.
The most important questions are answered briefly in the [FAQ of the SELinux Project](http://selinuxproject.org/page/FAQ).
For more details on SELinux and how to actually use and administrate it on your systems 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).
## <a id="selinux-policy"></a> Policy
Icinga Web 2 is providing its own SELinux policy for Red Hat Enterprise Linux 7 and its derivates running the targeted
policy which confines Icinga Web 2 with support for all its modules. All other distributions will require some tweaks.
It is not upstreamed to the reference policies yet.
The policy for Icinga Web 2 will also require the policy for Icinga 2 which provides access to its interfaces.
It covers only the scenario running Icinga Web 2 in Apache HTTP Server with mod_php.
## <a id="selinux-policy-installation"></a> Installation
There are two ways to install the SELinux Policy for Icinga Web 2 on Enterprise Linux 7.
Either install it from the provided package which is the preferred option or intall the policy manually, if you need
fixes which are not yet released.
Verify that the system runs in enforcing mode.
sestatus
# 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
# Max kernel policy version: 28
If problems occur, you can set icinga2 or httpd to run to run its domain in permissive mode.
You can change the configured mode by editing `/etc/selinux/config` and the current mode by executing `setenforce 0`.
### <a id="selinux-policy-installation-package"></a> Package installation
Simply add the `selinux` subpackage to your installation.
yum install icingaweb2-selinux
### <a id="selinux-policy-installation-manual"></a> Manual installation
This section describes the manual installation to support development and testing.
As a prerequisite install the `git`, `selinux-policy-devel` and `audit` package. Enable and start the audit daemon
afterwards.
yum install git selinux-policy-devel audit
systemctl enable auditd.service
systemctl start auditd.service
To create and install the policy package run the installation script from the Icinga Web 2 source which also labels the
resources.
cd packages/selinux/
./icingaweb2.sh
Verify that Apache runs in its own domain `httpd_t` and the Icinga Web 2 configuration has its own context
`icingaweb2_config_t`.
ps -eZ | grep http
# system_u:system_r:httpd_t:s0 9785 ? 00:00:00 httpd
ls -ldZ /etc/icingaweb2/
# drwxrws---. root icingaweb2 system_u:object_r:icingaweb2_config_t:s0 /etc/icingaweb2/
## <a id="selinux-policy-general"></a> General
When the SELinux policy package for Icinga Web 2 is installed, it creates its own type of apache content and labels its
configuration `icingaweb2_config_t` to allow confining access to it.
## <a id="selinux-policy-types"></a> Types
The configuration is labeled `icingaweb2_config_t` and other services can request access to it by using the interfaces
`icingaweb2_read_config` and `icingaweb2_manage_config`.
Files requiring read access are labeled `icingaweb2_content_t`. Files requiring write access are labeled
`icingaweb2_rw_content_t`.
## <a id="selinux-policy-booleans"></a> Booleans
SELinux 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 Web 2 policy package provides the following booleans.
**httpd_can_manage_icingaweb2_config**
Having this boolean enabled allows httpd to write to the configuration labeled `icingaweb2_config_t`. This is enabled by
default. If not needed, you can disable it for more security. But this will disable all web based configuration of
Icinga Web 2.
## <a id="selinux-bugreports"></a> Bugreports
If you experience any problems while running SELinux 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.
When filing a bug report please add the following information additionally to the
[common ones](https://www.icinga.org/icinga/faq/):
* Output of `semodule -l | grep -e icinga2 -e icingaweb2 -e nagios -e apache`
* Output of `semanage boolean -l | grep icinga`
* Output of `ps -eZ | grep httpd`
* Output of `audit2allow -li /var/log/audit/audit.log`
If access to a file is blocked and you can tell which one, please provided the output of `ls -lZ /path/to/file` and the
directory above.
If asked for full audit.log, add `-w /etc/shadow -p w` to `/etc/audit/rules.d/audit.rules` and restart the audit daemon.
Reproduce the problem and add `/var/log/audit/audit.log` to the bug report. The added audit rule includes
the path of files where access was denied.
If asked to provide full audit log with dontaudit rules disabled, execute `semodule -DB` before reproducing the problem.
After that enable the rules again to prevent auditd spamming your logfile by executing `semodule -B`.

View File

@ -45,10 +45,11 @@ Requires: %{name}-vendor-JShrink = 1.1.0-1%{?dist}
Requires: %{name}-vendor-lessphp = 0.4.0-1%{?dist}
Requires: %{name}-vendor-Parsedown = 1.6.0-1%{?dist}
%description
Icinga Web 2
%if "%{_vendor}" == "redhat" && !(0%{?el5} || 0%{?rhel} == 5 || "%{?dist}" == ".el5" || 0%{?el6} || 0%{?rhel} == 6 || "%{?dist}" == ".el6")
%define selinux 1
%define selinux_variants mls targeted
%{!?_selinux_policy_version: %define _selinux_policy_version %(sed -e 's,.*selinux-policy-\\([^/]*\\)/.*,\\1,' /usr/share/selinux/devel/policyhelp 2>/dev/null)}
%endif
%define basedir %{_datadir}/%{name}
%define bindir %{_bindir}
@ -59,6 +60,10 @@ Icinga Web 2
%define docsdir %{_datadir}/doc/%{name}
%description
Icinga Web 2
%package common
Summary: Common files for Icinga Web 2 and the Icinga CLI
Group: Applications/System
@ -100,6 +105,20 @@ Requires: php-Icinga = %{version}-%{release}
Icinga CLI
%if 0%{selinux}
%package selinux
Summary: SELinux policy for Icinga Web 2
BuildRequires: checkpolicy, selinux-policy-devel, /usr/share/selinux/devel/policyhelp, hardlink
%if "%{_selinux_policy_version}" != ""
Requires: selinux-policy >= %{_selinux_policy_version}
%endif
Requires: %{name} = %{version}-%{release}
%description selinux
SELinux policy for Icinga Web 2
%endif
%package vendor-dompdf
Version: 0.7.0
Release: 1%{?dist}
@ -175,8 +194,22 @@ Icinga Web 2's fork of Zend Framework 1
%prep
%setup -q
%if 0%{selinux}
mkdir selinux
cp -p packages/selinux/icingaweb2.{fc,if,te} selinux
%endif
%build
%if 0%{selinux}
cd selinux
for selinuxvariant in %{selinux_variants}
do
make NAME=${selinuxvariant} -f /usr/share/selinux/devel/Makefile
mv icingaweb2.pp icingaweb2.pp.${selinuxvariant}
make NAME=${selinuxvariant} -f /usr/share/selinux/devel/Makefile clean
done
cd -
%endif
%install
rm -rf %{buildroot}
@ -192,6 +225,16 @@ cp -pv packages/files/bin/icingacli %{buildroot}/%{bindir}
cp -pv packages/files/public/index.php %{buildroot}/%{basedir}/public
cp -prv etc/schema %{buildroot}/%{docsdir}
cp -prv packages/files/config/modules/{setup,translation} %{buildroot}/%{configdir}/modules
%if 0%{selinux}
cd selinux
for selinuxvariant in %{selinux_variants}
do
install -d %{buildroot}%{_datadir}/selinux/${selinuxvariant}
install -p -m 644 icingaweb2.pp.${selinuxvariant} %{buildroot}%{_datadir}/selinux/${selinuxvariant}/icingaweb2.pp
done
cd -
/usr/sbin/hardlink -cv %{buildroot}%{_datadir}/selinux
%endif
%pre
getent group icingacmd >/dev/null || groupadd -r icingacmd
@ -250,6 +293,34 @@ exit 0
%attr(0755,root,root) %{bindir}/icingacli
%if 0%{selinux}
%post selinux
for selinuxvariant in %{selinux_variants}
do
/usr/sbin/semodule -s ${selinuxvariant} -i %{_datadir}/selinux/${selinuxvariant}/icingaweb2.pp &> /dev/null || :
done
/sbin/restorecon -R %{basedir} || :
/sbin/restorecon -R %{configdir} || :
/sbin/restorecon -R %{logdir} || :
%postun selinux
if [ $1 -eq 0 ] ; then
for selinuxvariant in %{selinux_variants}
do
/usr/sbin/semodule -s ${selinuxvariant} -r icingaweb2 &> /dev/null || :
done
[ -d %{basedir} ] && /sbin/restorecon -R %{basedir} &> /dev/null || :
[ -d %{configdir} ] && /sbin/restorecon -R %{configdir} &> /dev/null || :
[ -d %{logdir} ] && /sbin/restorecon -R %{logdir} &> /dev/null || :
fi
%files selinux
%defattr(-,root,root,0755)
%doc selinux/*
%{_datadir}/selinux/*/icingaweb2.pp
%endif
%files vendor-dompdf
%defattr(-,root,root)
%{basedir}/library/vendor/dompdf

View File

@ -0,0 +1,7 @@
/etc/icingaweb2(/.*)? gen_context(system_u:object_r:icingaweb2_config_t,s0)
/usr/share/icingaweb2(/.*)? gen_context(system_u:object_r:icingaweb2_content_t,s0)
/var/log/icingaweb2(/.*)? gen_context(system_u:object_r:icingaweb2_rw_content_t,s0)
/var/cache/icingaweb2(/.*)? gen_context(system_u:object_r:icingaweb2_rw_content_t,s0)
/var/lib/icingaweb2(/.*)? gen_context(system_u:object_r:icingaweb2_rw_content_t,s0)

View File

@ -0,0 +1,45 @@
########################################
## <summary>
## Allow the specified domain to read
## icingaweb2 configuration files.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
## <rolecap/>
#
interface(`icingaweb2_read_config',`
gen_require(`
type icingaweb2_config_t;
')
files_search_etc($1)
list_dirs_pattern($1, icingaweb2_config_t, icingaweb2_config_t)
read_files_pattern($1, icingaweb2_config_t, icingaweb2_config_t)
read_lnk_files_pattern($1, icingaweb2_config_t, icingaweb2_config_t)
')
########################################
## <summary>
## Allow the specified domain to read
## and write icingaweb2 configuration files.
## </summary>
## <param name="domain">
## <summary>
## Domain allowed access.
## </summary>
## </param>
## <rolecap/>
#
interface(`icingaweb2_manage_config',`
gen_require(`
type icingaweb2_config_t;
')
files_search_etc($1)
manage_dirs_pattern($1, icingaweb2_config_t, icingaweb2_config_t)
manage_files_pattern($1, icingaweb2_config_t, icingaweb2_config_t)
manage_lnk_files_pattern($1, icingaweb2_config_t, icingaweb2_config_t)
')

52
packages/selinux/icingaweb2.sh Executable file
View File

@ -0,0 +1,52 @@
#!/bin/sh -e
DIRNAME=`dirname $0`
cd $DIRNAME
USAGE="$0 [ --update ]"
if [ `id -u` != 0 ]; then
echo 'You must be root to run this script'
exit 1
fi
if [ $# -eq 1 ]; then
if [ "$1" = "--update" ] ; then
time=`ls -l --time-style="+%x %X" icingaweb2.te | awk '{ printf "%s %s", $6, $7 }'`
rules=`ausearch --start $time -m avc --raw -se icinga2`
if [ x"$rules" != "x" ] ; then
echo "Found avc's to update policy with"
echo -e "$rules" | audit2allow -R
echo "Do you want these changes added to policy [y/n]?"
read ANS
if [ "$ANS" = "y" -o "$ANS" = "Y" ] ; then
echo "Updating policy"
echo -e "$rules" | audit2allow -R >> icingaweb2.te
# Fall though and rebuild policy
else
exit 0
fi
else
echo "No new avcs found"
exit 0
fi
else
echo -e $USAGE
exit 1
fi
elif [ $# -ge 2 ] ; then
echo -e $USAGE
exit 1
fi
echo "Building and Loading Policy"
set -x
make -f /usr/share/selinux/devel/Makefile icingaweb2.pp || exit
/usr/sbin/semodule -i icingaweb2.pp
# Generate a man page off the installed module
#sepolicy manpage -p . -d icingaweb2_t
# Fixing the file context on /etc/icingaweb2
/sbin/restorecon -F -R -v /etc/icingaweb2
# Fixing the file context on /var/log/icingaweb2
/sbin/restorecon -F -R -v /var/log/icingaweb2
# Fixing the file context on /usr/share/icingaweb2
/sbin/restorecon -F -R -v /usr/share/icingaweb2

View File

@ -0,0 +1,29 @@
policy_module(icingaweb2, 0.0.1)
########################################
#
# Declarations
#
require {
type httpd_t;
}
## <desc>
## <p>
## Allow Apache to manage icingaweb2 configuration
## </p>
## </desc>
gen_tunable(httpd_can_manage_icingaweb2_config, true)
type icingaweb2_config_t;
files_config_file(icingaweb2_config_t)
optional_policy(`
apache_content_template(icingaweb2)
icingaweb2_read_config(httpd_t)
tunable_policy(`httpd_can_manage_icingaweb2_config',`
icingaweb2_manage_config(httpd_t)
')
')