3

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

2 Answers2

2

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

musbur
  • 193
  • 12
  • As said, it does take quite a bit of research. You probably noted I used 'httpd_modules_t:' for my *.so modules. When say SElinux will eventually overwrite your changes. Do you know when? I've had several reboots on this server and the changes seem to hold so I'd like to know when/how the resets occur. Also I'd love to know how 'httpd_modules_t:' and 'httpd_exec_t' differ when it comes to holding the settings in a permanent manner, or just in general. They feel similar. I used 'httpd_modules_t:' because it seemed logical for the functionality and it appeared to work for me. Thanks in advance. – Evolutionary May 23 '19 at 06:42
  • I don't know if SELinux will eventually overwrite labels on its own, I just went by the docs (see link in my edited original answer). I couldn't find any comprehensive documentation on which labels is the right one for which purpose. For httpd it seems to be [this](https://linux.die.net/man/8/httpd_selinux), but I don't know what entity is in charge of inventing labels. – musbur May 27 '19 at 09:12
1

Okay, I seem to have figured this out and it may be helpful to others (correct me where applicable):

The key I believe is functionality file context:

For scripts similar to apache script that are executed I treated like a variation of CGI's (php scripts seem to be treated in a similar fashion by default) so I set my django core install locations this way:

sudo chcon system_u:object_r:httpd_sys_script_exec_t:s0 (your folder name)

I didn't do this recursively because I had some static content and upload directories grouped by app, so after I did the django_root I went in and applied the command recursively for my apps_directories (apps, not site directories as they contain static and possibly upload directories) If for speed sake you want to do this using the "-R" recursive option:

sudo chcon -R system_u:object_r:httpd_sys_script_exec_t:s0 (your folder name)

be sure you check each of your site file upload directories and any read/write files (like sqlite3 files for example) and apply this setting:

sudo chcon system_u:object_r:httpd_sys_rw_content_t:s0 (upload folder name)
sudo chcon system_u:object_r:httpd_sys_rw_content_t:s0 (sqlite3 file name)

And static file directories (containing css, javascript, images, django template files (*.html with template code)) should be given this setting with the recursive option:

sudo chcon -R -t httpd_sys_content_t (folder name)

Note: This leaves those folders/files on their initial unconfined_u:object_r classification, which seems to be okay.

in the directory I installed my virtual environment(s) I apply this context:

sudo chcon -R system_u:object_r:httpd_sys_script_exec_t:s0 (virtual environment directory name)

This seemed to be the key part in getting my mod_wsgi to fully run. The errors I got in my error_log previous don't give intuitive clues, basically it can't access key library files due to selinux restrictions which we remove by setting sys_script_exec context.

If you have compiled *.so libraries (like I did with my mod_wsgi) you need to do this step last in the directories with *.so files (in my case my compiled mod_wsgi.so located in (django app folder)/(category folder)/(virtual_env)/lib/python3.6/site-packages/mod_wsgi/server/mod_wsgi-py36.cpython-36m-x86_64-linux-gnu.so using this command:

sudo chcon system_u:object_r:httpd_modules_t:s0 (module filename)

when done your *.so file should read like this when you confirm with a ls -Z in your *.so directory:

-rwxrwx-x. root apache system_u:object_r:httpd_modules_t:s0 (your module)

I set root|apache just to be safe for permissions.

I set all my django files to the apache group except the manage.py file. That I keep as root|root.

Now I keep my selinux on enforce mode and my django apps run with my compiled mod_wsgi module in a custom location.

Hope that helps everyone. Please feel free to comment and further educate us. I got a fair amount of help by looking at the configurations on selinux by running this command:

grep httpd /etc/selinux/targeted/contexts/files/file_contexts | less

You can see the preconfigured options in relation to httpd.

This article was very helpful:

Managing Confined Services, The Apache Http Server Types