{"id":151,"date":"2019-12-12T19:25:59","date_gmt":"2019-12-12T19:25:59","guid":{"rendered":"http:\/\/www.martin-rdz.de\/?p=151"},"modified":"2021-12-23T10:36:07","modified_gmt":"2021-12-23T10:36:07","slug":"selinux-systemd-and-python-virtual-environments","status":"publish","type":"post","link":"http:\/\/www.martin-rdz.de\/index.php\/2019\/12\/12\/selinux-systemd-and-python-virtual-environments\/","title":{"rendered":"SELinux, systemd and python virtual environments"},"content":{"rendered":"\r\n<p>Recently I wanted to configure a <a href=\"https:\/\/gunicorn.org\/\">gunicorn<\/a> backend at our newest server. The aim was to run a flask-based python application using a <a href=\"https:\/\/docs.python.org\/3\/tutorial\/venv.html\">virtual environment<\/a> in a users home. The machine is running recent <a href=\"https:\/\/www.redhat.com\/de\/enterprise-linux-8\">Red Hat 8<\/a> and the setup of systemd was straightforward and well documented in the internet (e.g. <a href=\"https:\/\/bartsimons.me\/gunicorn-as-a-systemd-service\/\">here<\/a>). However, after<\/p>\r\n\r\n\r\n\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-linenumbers=\"false\" data-enlighter-theme=\"wpcustom\">systemctl daemon-reload\r\nsystemctl enable ourservice\r\nsystemctl start ourservice<\/pre>\r\n\r\n\r\n\r\n<p>a strange permission denied error occurred (also <code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"wpcustom\">journalctl<\/code>\u00a0helps in that context).<\/p>\r\n\r\n\r\n\r\n<p>After rechecking the file permission several times I finally remembered, that Red Hat now runs runs <a href=\"http:\/\/www.selinuxproject.org\/page\/Main_Page\">SELinux<\/a>. It allows even finer access control for files, resources and actions using policies. The current status of SELinux can be shown with <code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"wpcustom\">sudo sestatus<\/code>. For testing reasons, all policies can be set to permissive using <code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"wpcustom\">sudo setenforce permissive<\/code>. The contexts of a file can be inspected with <code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"wpcustom\">ls -Z file1<\/code>.<\/p>\r\n<p>To debug an process that fails, the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"wpcustom\">\/var\/log\/audit\/audit.log<\/code> file is the first place to look at. The <code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"wpcustom\">audit2why<\/code> tool translates the error messages to a more understandable format:<\/p>\r\n\r\n\r\n\r\n\r\n\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"wpcustom\" data-enlighter-linenumbers=\"false\">&gt;\r\nsudo cat \/var\/log\/audit\/audit.log | grep gunicorn | audit2why<\/pre>\r\n\r\n\r\n\r\n<p>Afterwards the <code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"wpcustom\">audit2allow<\/code> utility can generate rules, that would allow the denied operations:<\/p>\r\n\r\n\r\n\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"wpcustom\" data-enlighter-linenumbers=\"false\">&gt;\r\nsudo cat \/var\/log\/audit\/audit.log | grep gunicorn | audit2allow -M custom_rule<\/pre>\r\n\r\n\r\n\r\n<p>These rules are now stored in the format of an type enforcement (<code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"wpcustom\">custom_rule.te<\/code>) file and a policy package which can be activated using <code class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"wpcustom\">semodule -i custom_rule.pp<\/code>.<\/p>\r\n\r\n\r\n\r\n<p>Likely this process has to be repeated, as different kinds of operations might be denied.<\/p>\r\n\r\n\r\n\r\n<p>For our setup the final type enforcement file looked like<\/p>\r\n\r\n\r\n\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"wpcustom\" data-enlighter-linenumbers=\"false\">module custom_rule 1.0;\r\n \r\nrequire {\r\n        type init_t;\r\n        type unconfined_exec_t;\r\n        type user_home_t;\r\n        class file { append execute execute_no_trans ioctl map open read setattr };\r\n        class lnk_file { getattr read };\r\n}\r\n \r\n#============= init_t ==============\r\n#!!!! This avc is allowed in the current policy\r\nallow init_t unconfined_exec_t:file { execute open read };\r\nallow init_t user_home_t:file setattr;\r\n \r\n#!!!! This avc can be allowed using the boolean 'domain_can_mmap_files'\r\nallow init_t user_home_t:file map;\r\n \r\n#!!!! This avc is allowed in the current policy\r\n#!!!! This av rule may have been overridden by an extended permission av rule\r\nallow init_t user_home_t:file { append execute execute_no_trans ioctl open read };\r\n \r\n#!!!! This avc is allowed in the current policy\r\nallow init_t user_home_t:lnk_file { getattr read };<\/pre>\r\n\r\n\r\n\r\n<p>The type enforcement rule can be compiled manually<\/p>\r\n\r\n\r\n\r\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"generic\" data-enlighter-theme=\"wpcustom\" data-enlighter-linenumbers=\"false\">checkmodule -M -m -o custom_rule.mod custom_rule.te\r\nsemodule_package -o custom_rule.pp -m custom_rule.mod\r\nsudo semodule -i custom_rule.pp<\/pre>\r\n\r\n\r\n\r\n<h5 class=\"wp-block-heading\">Further useful resources<\/h5>\r\n\r\n\r\n\r\n<ul>\r\n<li><a href=\"https:\/\/opensource.com\/article\/18\/7\/sysadmin-guide-selinux\">A sysadmin&#8217;s guide to SELinux: 42 answers to the big questions<\/a><\/li>\r\n<li><a href=\"https:\/\/access.redhat.com\/documentation\/en-us\/red_hat_enterprise_linux\/6\/html\/security-enhanced_linux\/sect-security-enhanced_linux-fixing_problems-allowing_access_audit2allow\">Red Hat documentation on SELinux<\/a><\/li>\r\n<li><a href=\"https:\/\/github.com\/ansible-community\/ara\/commit\/9df768c413029870475a4571b21db886b3291c75\">Similar fix for ansible<\/a><\/li>\r\n<li><a href=\"https:\/\/stackoverflow.com\/questions\/49647277\/gunicorn-nginx-permission-denied-while-connecting-to-upstream\">Related problems with socket permissions (stackoverflow)<\/a><\/li>\r\n<\/ul>\r\n\r\n\r\n\r\n<h5>\u00a0<\/h5>\r\n<h5>Disclaimer<\/h5>\r\n<p>When used correctly, SELinux adds a lot to your server&#8217;s security. When you run into problems with certain commands being denied, you should first make sure that you truly understand what causes the error. Chances are very high that SELinux complains for a reason. Often you can avoid the problem altogether by rethinking where you put which files. When you are absolutely sure that you need to build a new policy package, do yourself a favor and research thoroughly what each added rule does \u2013 it is only too easy to create security holes which would defeat SELinux&#8217; purpose.<\/p>\r\n<p style=\"text-align: right;\"><cite> Michael Trojanek: <a href=\"https:\/\/relativkreativ.at\/articles\/how-to-compile-a-selinux-policy-package\">How to compile a SELinux policy package <\/a><\/cite><\/p>\r\n\r\n\r\n\r\n<h5>UPDATE<\/h5>\r\n<ul>\r\n<li><a href=\"https:\/\/www.youtube.com\/watch?v=MxjenQ31b70\">2012 Red Hat Summit: SELinux For Mere Mortals (Talk by Thomas Cameron)<\/a><\/li>\r\n<\/ul>\r\n","protected":false},"excerpt":{"rendered":"<p>Recently I wanted to configure a gunicorn backend at our newest server. The aim was to run a flask-based python application using a virtual environment in a users home. The machine is running recent Red Hat 8 and the setup of systemd was straightforward and well documented in the internet (e.g. here). However, after a &hellip;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"http:\/\/www.martin-rdz.de\/index.php\/wp-json\/wp\/v2\/posts\/151"}],"collection":[{"href":"http:\/\/www.martin-rdz.de\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.martin-rdz.de\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.martin-rdz.de\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/www.martin-rdz.de\/index.php\/wp-json\/wp\/v2\/comments?post=151"}],"version-history":[{"count":36,"href":"http:\/\/www.martin-rdz.de\/index.php\/wp-json\/wp\/v2\/posts\/151\/revisions"}],"predecessor-version":[{"id":257,"href":"http:\/\/www.martin-rdz.de\/index.php\/wp-json\/wp\/v2\/posts\/151\/revisions\/257"}],"wp:attachment":[{"href":"http:\/\/www.martin-rdz.de\/index.php\/wp-json\/wp\/v2\/media?parent=151"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.martin-rdz.de\/index.php\/wp-json\/wp\/v2\/categories?post=151"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.martin-rdz.de\/index.php\/wp-json\/wp\/v2\/tags?post=151"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}