Configuring SELinux to Allow Nginx Access to Unix Sockets: A Production-Ready Approach Without audit2allow


13 views

When integrating Nginx with Gunicorn via Unix sockets (/run/gunicorn/socket), SELinux typically blocks access attempts with two distinct denials:

# First denial: Socket file write permission
type=AVC msg=audit(1454360194.623:7324): avc: denied { write } for pid=9128 comm="nginx"

# Second denial: Stream socket connection
type=AVC msg=audit(1454361591.701:13343): avc: denied { connectto } for pid=9128 comm="nginx"

First verify current context labeling:

ls -Z /run/gunicorn/socket
# Output shows incorrect httpd_sys_content_t context
system_u:object_r:httpd_sys_content_t:s0 /run/gunicorn/socket

Apply the correct context permanently:

semanage fcontext -a -t httpd_var_run_t "/run/gunicorn/socket(/.*)?"
restorecon -Rv /run/gunicorn/socket

For immediate testing, enable the HTTPD connection boolean:

setsebool -P httpd_connect_unixsocket 1

Create a persistent policy without relying on denials:

# Create .te policy file
cat << EOF > nginx_gunicorn.te
module nginx_gunicorn 1.0;

require {
    type httpd_t;
    type initrc_t;
    class unix_stream_socket connectto;
    class sock_file write;
}

# Allow socket connection
allow httpd_t initrc_t:unix_stream_socket connectto;

# Allow socket file write
allow httpd_t httpd_var_run_t:sock_file write;
EOF

# Compile and install
checkmodule -M -m -o nginx_gunicorn.mod nginx_gunicorn.te
semodule_package -o nginx_gunicorn.pp -m nginx_gunicorn.mod
semodule -i nginx_gunicorn.pp

Confirm the changes took effect:

# Check socket context
ls -Z /run/gunicorn/socket
# Should show: system_u:object_r:httpd_var_run_t:s0

# Verify boolean
getsebool httpd_connect_unixsocket
# Should return "on"

# Check custom module
semodule -l | grep nginx_gunicorn

If using systemd socket activation, add SELinux context directives:

[Unit]
Description=Gunicorn Socket

[Socket]
ListenStream=/run/gunicorn/socket
SocketUser=nginx
SocketGroup=nginx
SocketMode=0660

# SELinux context
SELinuxContext=system_u:object_r:httpd_var_run_t:s0

[Install]
WantedBy=sockets.target

When setting up Nginx to communicate with Gunicorn via Unix sockets (/run/gunicorn/socket), SELinux typically blocks the connection attempts. The audit logs reveal two critical denials:

avc: denied { write } for comm="nginx" name="socket" dev="tmpfs" ino=76151
avc: denied { connectto } for comm="nginx" path="/run/gunicorn/socket"

Instead of relying on audit2allow, we can manually configure the security contexts:

# First, verify current context of the socket
ls -Z /run/gunicorn/socket

# Set proper context for the socket directory
sudo semanage fcontext -a -t httpd_var_run_t "/run/gunicorn(/.*)?"
sudo restorecon -Rv /run/gunicorn

# Alternatively for temporary testing (not recommended for production)
sudo chcon -t httpd_var_run_t /run/gunicorn/socket

For production systems, create a custom policy module:

# Create a .te file with the necessary rules
cat > nginx_gunicorn.te <

After applying these changes, test the connection:

# Check if Nginx can now access the socket
sudo -u nginx curl --unix-socket /run/gunicorn/socket http://localhost

# Verify SELinux is no longer blocking
sudo ausearch -m avc -c nginx | grep denied

Some systems may benefit from using SELinux booleans:

# Check relevant booleans
getsebool -a | grep httpd

# Enable httpd_can_network_connect if needed
sudo setsebool -P httpd_can_network_connect on

For automated deployments, include these commands in your provisioning scripts:

#!/bin/bash
# Ensure directory exists
mkdir -p /run/gunicorn
chown nginx:nginx /run/gunicorn

# Set SELinux context
semanage fcontext -a -t httpd_var_run_t "/run/gunicorn(/.*)?"
restorecon -Rv /run/gunicorn

# Load custom policy if created earlier
semodule -i /path/to/nginx_gunicorn.pp