SELinux — Making it a Little Easier for Web

A SELinux tutorial for your web site and web apps, the easy way — and why you shouldn’t disable SELinux.

What is SELinux, and why is it slowing me down?

Disclaimer: Use at your own risk.

Before We Start (Prerequisites & Gotchas)

Install The Tools

$> yum install -y policycoreutils-python setroubleshoot

Check SELinux Enforcement Status

# Bash prompt
$> getenforce
# The output here will be one of three values:
Enforcing
Permissive
Disabled

$> 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

Correcting SELinux Policies from a Disabled State

$> vi /etc/selinux/config# Change SELINUX=disabled to SELINUX=enforcing
# Save the file
:wq# Verify your change
$> 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
$> touch /.autorelabel
$> reboot

Reviewing Policy Options

$> getsebool -a | grep http
httpd_anon_write --> off
httpd_builtin_scripting --> on
httpd_can_check_spam --> off
httpd_can_connect_ftp --> off
httpd_can_connect_ldap --> off
httpd_can_connect_mythtv --> off
httpd_can_connect_zabbix --> off
httpd_can_network_connect --> off
httpd_can_network_connect_cobbler --> off
httpd_can_network_connect_db --> off
httpd_can_network_memcache --> off
httpd_can_network_relay --> off
httpd_can_sendmail --> off
httpd_dbus_avahi --> off
httpd_dbus_sssd --> off
httpd_dontaudit_search_dirs --> off
httpd_enable_cgi --> off
httpd_enable_ftp_server --> off
httpd_enable_homedirs --> off
httpd_execmem --> off
httpd_graceful_shutdown --> on
httpd_manage_ipa --> off
httpd_mod_auth_ntlm_winbind --> off
httpd_mod_auth_pam --> off
httpd_read_user_content --> off
httpd_run_ipa --> off
httpd_run_preupgrade --> off
httpd_run_stickshift --> off
httpd_serve_cobbler_files --> off
httpd_setrlimit --> off
httpd_ssi_exec --> off
httpd_sys_script_anon_write --> off
httpd_tmp_exec --> off
httpd_tty_comm --> off
httpd_unified --> off
httpd_use_cifs --> off
httpd_use_fusefs --> off
httpd_use_gpg --> off
httpd_use_nfs --> off
httpd_use_openstack --> off
httpd_use_sasl --> off
httpd_verify_dns --> off
named_tcp_bind_http_port --> off
prosody_bind_http_port --> off

Enabling Built-In Policies

$> setsebool -P httpd_can_network_connect=1
setsebool -P httpd_can_network_connect_db=1
setsebool -P httpd_can_network_memcache=1
setsebool -P httpd_can_network_relay=1
setsebool -P httpd_can_sendmail=1
setsebool -P httpd_enable_cgi=1
setsebool -P httpd_enable_homedirs=1

Install NGINX to For Testing

$> echo '[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=0
enabled=1' > /etc/yum.repos.d/nginx.repo
$> yum install -y nginx$> systemctl enable nginx
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.
$> systemctl start nginx

Simulating Common SELinux Web Server Conflicts

# Modify the default configuration for NGINX
# We'll change the web root, as shown in bold below
$> vi /etc/nginx/conf.d/default.confserver {
listen 80;
server_name localhost;
#charset koi8-r;
#access_log /var/log/nginx/host.access.log main;
location / {
#root /usr/share/nginx/html;
root /var/www/html;

index index.html index.htm;
}
...
# Reload NGINX config for our settings to take effect
$> nginx -s reload
$> mkdir -p /var/www/html
$> vi /var/www/html/index.html
<html>
<body>
<h1>Hello, World!</h1>
</body>
</html>
# Save the file
:wq
$> setenforce 0
$> setenforce 1

Reviewing the Audit Log

$> cd /var/log/audit
$> cat audit.log | grep fail
type=AVC msg=audit(1538439060.411:4960): avc:  denied  { open } for  pid=10007 comm="nginx" path="/var/www/html/index.html" dev="vda1" ino=25250737 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:var_t:s0 tclass=file
# Using audit2why$> grep nginx /var/log/audit/audit.log | audit2why type=AVC msg=audit(1538439060.411:4960): avc:  denied  { open } for  pid=10007 
comm="nginx" path="/var/www/html/index.html" dev="vda1"
ino=25250737 scontext=system_u:system_r:httpd_t:s0
tcontext=unconfined_u:object_r:var_t:s0 tclass=file

Was caused by:
Missing type enforcement (TE) allow rule.

You can use audit2allow to generate a loadable module to allow this access.
# Example output when SELinux policy exists for this issue$> grep nginx audit.log | audit2whytype=AVC msg=audit(1538439136.849:4963): avc:  denied  { open } for  pid=10007 comm="nginx" path="/var/www/html/index.html" dev="vda1" ino=25250737 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:var_t:s0 tclass=file          Was caused by:
Unknown - would be allowed by active policy
Possible mismatch between this policy and the one under which the audit message was generated.
Possible mismatch between current in-memory boolean settings vs. permanent ones.

Using audit2allow To Create a Custom Policy Module

# Let's review the command syntax
grep [keyword] audit.log | audit2allow -M [name of our policy]
| |
The keyword is what The name of our policy
we're searching the log for. can be whatever we want.
# Example using "nginx" as our keyword.
$> grep nginx audit.log | audit2allow -M nginxpolicy
$> grep nginx audit.log | audit2allow -M nginxpolicy
******************** IMPORTANT ***********************
To make this policy package active, execute:
semodule -i nginxpolicy.pp
semodule -i nginxpolicy.pp
$> tail -f /var/log/audit/audit.log

Not So Bad, Eh?

Chris Shaffer is an independent TypeScript and JavaScript developer and Linux admin. He loves talking tech and covers JavaScript, TypeScript and Linux.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store