Redhat – Getting compiled Python mod_wsgi module working on Apache server with SElinux enforcing mode

httpdredhatselinuxwsgi

Trying to get my Python/Django app working on a RedHat Server in an ideal setting. Could not use the mod_wsgi from the package as it has some dependency issue when checking for modules in my virtual environment which uses python 3.6 (some dependency checking bug on > python 2.x it seems between numpy and pandas) so I was forced to compile my mod_wsgi using PIP which worked perfectly. Because I am not using one of the recognized directory (i have a custom directory for clean install + security reasons). If I set SELinux to permissive everything work great, but I want my application to work with SELinux on enforcing mode. I have researched the SELinux file contexts and attempted to apply them, but it only seems to partially work:

When I set the file context of my mod_wsgi module in my virtual environment:

sudo chcon -t httpd_modules_t (special location)/(virtual_env)/lib/python(version)/site-packages/mod_wsgi_server/mod_wsgi-py36/cpython-36m-x86_64-linux-gun.so

The httpd startup errors I got before setting the new file context when selinux was on enforcing would disappear and the service would start properly, or so it seemed…when I access my pages after httpd start I get:

Error 500

when selinux is in enforcing mode. I've checked the audit.log and am not seeing anything.

Does anyone have any ideas on that. My mod_wsgi file currently has the following settings:

-rwxrwxr-x. root root system_u:object_r:httpd_exec_t:s0 mod_wsgi-py(version).cpython-(version)m-x86_64-linux-gnu.so

This feels correct as anyone can read and execute the module and httpd starts without complaint. If I set Selinux to enforcing after I've started the apache web server, everything is still okay until the next apache web server restart which suggests everything is loaded into memory initially for the mod_wsgi operations.

I've looked up what appears to be a complete list of File Contexts for SELinux here:

https://linux.die.net/man/8/httpd_selinux

Any ideas on that folks? What am I missing? Thanks!

To Add info to those seeing to help:

I am getting no additional logs in my audit.log file from my web pages upon running httpd or accessing pages (and getting error 500). When I go to a http request (my settings.py forwards to 443) I get this entry in my Apache error_log:

[Fri Apr 26 18:10:58.313753 2019] [wsgi:error] [pid 6294] [remote 142.150.251.220:51864] mod_wsgi (pid=6294): Failed to exec Python script file '/var/www/(custom_django_dir)/(custom_section)/(site)/(app)/wsgi.py'.
[Fri Apr 26 18:10:58.313840 2019] [wsgi:error] [pid 6294] [remote 142.150.251.220:51864] mod_wsgi (pid=6294): Exception occurred processing WSGI script '/var/www/(custom_django_dir)/(custom_section)/(site)/(app)/wsgi.py'.
[Fri Apr 26 18:10:58.314117 2019] [wsgi:error] [pid 6294] [remote 142.150.251.220:51864] Traceback (most recent call last):
[Fri Apr 26 18:10:58.314191 2019] [wsgi:error] [pid 6294] [remote 142.150.251.220:51864]   File "/var/www/(custom_django_dir)/(custom_section)/(site)/(app)/wsgi.py", line 18, in <module>
[Fri Apr 26 18:10:58.314206 2019] [wsgi:error] [pid 6294] [remote 142.150.251.220:51864]     application = get_wsgi_application()
[Fri Apr 26 18:10:58.314231 2019] [wsgi:error] [pid 6294] [remote 142.150.251.220:51864]   File "/var/www/(custom_django_dir)/(custom_section)/virtual_env/lib64/python3.6/site-packages/django/core/wsgi.py", line 12, in get_wsgi_application
[Fri Apr 26 18:10:58.314250 2019] [wsgi:error] [pid 6294] [remote 142.150.251.220:51864]     django.setup(set_prefix=False)
[Fri Apr 26 18:10:58.314275 2019] [wsgi:error] [pid 6294] [remote 142.150.251.220:51864]   File "/var/www/(custom_django_dir)/(custom_section)/virtual_env/lib64/python3.6/site-packages/django/__init__.py", line 24, in setup
[Fri Apr 26 18:10:58.314285 2019] [wsgi:error] [pid 6294] [remote 142.150.251.220:51864]     apps.populate(settings.INSTALLED_APPS)
[Fri Apr 26 18:10:58.314307 2019] [wsgi:error] [pid 6294] [remote 142.150.251.220:51864]   File "/var/www/(custom_django_dir)/(custom_section)/virtual_env/lib64/python3.6/site-packages/django/apps/registry.py", line 81, in populate
[Fri Apr 26 18:10:58.314317 2019] [wsgi:error] [pid 6294] [remote 142.150.251.220:51864]     raise RuntimeError("populate() isn't reentrant")
[Fri Apr 26 18:10:58.314350 2019] [wsgi:error] [pid 6294] [remote 142.150.251.220:51864] RuntimeError: populate() isn't reentrant

Best Answer

I was in a similar situation and found that chcon is only half the truth. The problem is that the changes done with chcon are not permanent and will be overwritten by SELinux eventually.

In my case most files were labelled correctly bacuse my virtualenv lives under /var/www. But shared objects need to be httpd_exec_t, and this does the trick:

$ semanage fcontext -a -t httpd_exec_t '/var/www/wsgi/env/.*\.so(\..*)?'
$ restorecon -r /var/www/wsgi/env

You will find these changes in /etc/selinux/targeted/contexts/files/file_contexts.local.

It takes quite a bit of research to come up with this stuff. Most people, including WSGI framework providers, seem to suggest to simply deactivate SELinux.

[EDIT] Relevant information at RedHat SELinux documentation

Related Topic