I've got a server that will have several applications on it, one of which is proprietary code, and another with the ability to examine files on the server due to the nature of our needs. This will not do. I'm trying to achieve per-vhost privilege separation to prevent one from examining the other. There are several mitigating circumstances which have complicated this...
- CentOS8
- Must use SELinux
- Apache 2.4.37, PHP73, FCGI, PHP_FPM... using
mpm_event
- No
mod_permissions
,mod_itk/mpm_itk
,mod_selinux
modules out of the box on CentOS8
Since SELinux must be enabled in our case, and it also offers the best granularity for achieving our purposes, I've started down that path. In order to get it installed (from a Fedora Core 31 src) I followed these steps...
dnf install httpd-devel selinux-policy-devel
wget https://download.fedoraproject.org/pub/fedora/linux/releases/31/Everything/source/tree/Packages/m/mod_selinux-2.4.4-14.fc31.src.rpm
rpmbuild --rebuild mod_selinux-2.4.4-14.fc31.src.rpm --define "_rpmdir /tmp"
dnf install /tmp/x86_64/mod_selinux-2.4.4-14.el8.x86_64.rpm
This all went well, no errors, and everything was installed where it was supposed to be.
I have consolidated our serverwide settings into a single httpd.conf
file rather than using lots of different conf files in conf.d
(this is mostly due to simplicity when working with ansible templates and seeing everything in one place). NB: This does NOT include each of our vhost
conf files / declarations which are still separate and included individually.
The default declaration for the httpd contexts is...
selinuxServerDomain *:s0
I have 4x vhosts that I wish to compartmentalize, and I want to leave room for future expansion, so I adjusted that declaration to the following and added it to my httpd.conf
file...
selinuxServerDomain *:s0-s0:c0.c50
I then added the following to each of my vhost
declarations respectively...
selinuxDomainVal *:s0:c10
selinuxDomainVal *:s0:c20
selinuxDomainVal *:s0:c30
selinuxDomainVal *:s0:c40
Lastly, I changed the context of the document roots on each of the respective vhost sites as follows...
chcon -R -l s0:c10 /var/www/site1
chcon -R -l s0:c20 /var/www/site2
chcon -R -l s0:c30 /var/www/site3
chcon -R -l s0:c40 /var/www/site4
Prior to using the context-sites, I was already successfully running the websites using the standard httpd related contexts (unconfined_u:object_r:httpd_sys_content_t
, system_u:object_r:httpd_sys_rw_content_t
), so I left them as is.
So the problem is, using the original *:s0
context, systemctl start httpd
works fine, though none of the vhosts
are accessible for the obvious reason that none of the spawned handlers are using the correct context.
However, when I change the context declaration to *:s0-s0:c0.c50
, systemctl start httpd
fails. status
shows the following...
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
Drop-In: /usr/lib/systemd/system/httpd.service.d
└─php73-php-fpm.conf
Active: failed (Result: exit-code) since Fri 2020-01-10 09:56:45 EST; 7s ago
Docs: man:httpd.service(8)
Process: 19362 ExecStart=/usr/sbin/httpd $OPTIONS -DFOREGROUND (code=exited, status=1/FAILURE)
Main PID: 19362 (code=exited, status=1/FAILURE)
Status: "Reading configuration..."
Jan 10 09:56:45 myhost.tld systemd[1]: Stopped The Apache HTTP Server.
Jan 10 09:56:45 myhost.tld systemd[1]: Starting The Apache HTTP Server...
Jan 10 09:56:45 myhost.tld systemd[1]: httpd.service: Main process exited, code=exited, status=1/FAILURE
Jan 10 09:56:45 myhost.tld systemd[1]: httpd.service: Failed with result 'exit-code'.
Jan 10 09:56:45 myhost.tld systemd[1]: Failed to start The Apache HTTP Server.
There is no helpful info there I can see. Similarly journalctl -xe
shows the same message lines, no additional help. The only thing I could find was in the error.log
...
[Fri Jan 10 09:56:45.245476 2020] [core:notice] [pid 19362:tid 139989213628672] SELinux policy enabled; httpd running as context system_u:system_r:httpd_t:s0
[Fri Jan 10 09:56:45.253134 2020] [:error] [pid 19362:tid 139989213628672] (13)Permission denied: SELinux: setcon_raw("system_u:system_r:httpd_t:s0-s0:c0.c50") failed
AH00016: Configuration Failed
But due to my relative infancy when dealing with SEL policies, I'm not exactly sure what it's telling me. Can someone help shed some light on what I'm doing wrong here?
I've tried moving the context declaration up and down in the conf file just in case it was trying to set before another dependency but no change. I tried changing the context users from system_u
to unconfined_u
in the directory contexts and back again, no change. Not sure what else to try.
Thanks in advance for any help you can offer!
EDIT:
I've been able to get a little more specific info on the AVC Denial from the audit.log...
type=AVC msg=audit(1578928482.042:458750): avc: denied { setcurrent } for pid=11335 comm="httpd" scontext=system_u:system_r:httpd_t:s0 tcontext=system_u:system_r:httpd_t:s0 tclass=process permissive=0
type=SYSCALL msg=audit(1578928482.042:458750): arch=c000003e syscall=1 success=no exit=-13 a0=d a1=55e37564e5c0 a2=29 a3=0 items=0 ppid=1 pid=11335 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=(none) ses=4294967295 comm="httpd" exe="/usr/sbin/httpd" subj=system_u:system_r:httpd_t:s0 key=(null)^]ARCH=x86_64 SYSCALL=write AUID="unset" UID="root" GID="root" EUID="root" SUID="root" FSUID="root" EGID="root" SGID="root" FSGID="root"
type=PROCTITLE msg=audit(1578928482.042:458750): proctitle=2F7573722F7362696E2F6874747064002D44464F524547524F554E44
type=SERVICE_START msg=audit(1578928482.054:458751): pid=1 uid=0 auid=4294967295 ses=4294967295 subj=system_u:system_r:init_t:s0 msg='unit=httpd comm="systemd" exe="/usr/lib/systemd/systemd" hostname=? addr=? terminal=? res=failed'^]UID="root" AUID="unset"
Does that help at all?
I'm answering this because I found the solution, however I don't quite understand what I've done, so if you can comment to provide clarity, I'm sure others will appreciate it as much as I would...
In order to get a bit more help translating the cryptic notes in the
audit.log
, I installed two utilities: setroubleshoot and setoolsAfter they were in place, I ran the following to analyze the
audit.log
AVC errors...The response was in english (vs giberish) and provided a helpful list of instructions for fixing the problem...
The solution was to run the commands suggested...
After which I was able to finally restart Apache.
So it's pretty clear that in following the above, I created a custom policy for the httpd service, but that's about all I understand. The commands do not mention the
setcurrent
command/permission which was referenced in the error report, and there's no output from either command with any extra info. I'm assuming that theausearch
on the termhttpd
piped intoaudit2allow
essentially uses the error report to generate the custom policy, but would love to understand exactly what happened, and where that custom policy is now stored on the system.Hope this helps, and thanks if you can provide any helpful explanation as to why!