Advanced Linux Tips




Pay Notebook Creator: Roy Hyunjin Han0
Set Container: Numerical CPU with TINY Memory for 10 Minutes 0
Total0

Create an SELinux Policy for Your Web Service

SELinux errors can be bewildering and it is tempting to disable SELinux entirely. However, with a couple of simple commands, you can customize an SELinux policy for your web service.

This mini-tutorial deals strictly with policy-based errors (audit2allow, semodule). We will not go into file-based selinux context errors (semanage, restorecon) or selinux flag errors (setsebool) because their solution is well-known.

Prepare Environment

This tutorial assumes that you are running Fedora 26 on DigitalOcean. Unfortunately, you won't be able to work through this tutorial on our website because some commands are unavailable in our terminal configuration.

Install packages.

dnf -y update vim-minimal
dnf -y install git tmux vim-enhanced
pip3 install virtualenv

Setup user with sudo privileges.

adduser user
echo "user ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/user
su user
tmux  # CTRL-b " to split window into top and bottom

Configure user environment.

pushd /tmp
git clone https://github.com/invisibleroads/scripts
cd scripts
bash setup
popd

virtualenv ~/.virtualenvs/crosscompute
source ~/.virtualenvs/crosscompute/bin/activate
pip install pyramid    

Prepare Service

Setup app.

X=~/Experiments/xyz; mkdir $X -p; cd $X
vim app.py
    from pyramid.config import Configurator
    from pyramid.response import Response
    from wsgiref.simple_server import make_server

    if __name__ == '__main__':
        with Configurator() as config:
            config.add_view(lambda request: Response('whee\n'))
            app = config.make_wsgi_app()
        server = make_server('0.0.0.0', 3000, app)
        server.serve_forever()

source ~/.virtualenvs/crosscompute/bin/activate
python app.py
curl http://127.0.0.1:3000
    whee

Setup service.

sudo vim /etc/systemd/system/app.service
    [Unit]
    Description=App

    [Service]
    ExecStart=/home/user/.virtualenvs/crosscompute/bin/python app.py
    WorkingDirectory=/home/user/Experiments/xyz
    User=user
    Group=user
    Restart=on-abnormal

    [Install]
    WantedBy=multi-user.target
sudo systemctl start app
sudo systemctl status app
curl http://127.0.0.1:3000
    whee        

Toggle SELinux

Activate selinux.

sudo setenforce 1
sudo getenforce
    Enforcing

Check that the app service fails.

sudo systemctl restart app
sudo systemctl status app
    app.service: Failed with result 'exit-code'.

Deactivate selinux.

sudo setenforce 0
sudo getenforce
    Permissive

Check that the app service works.

sudo systemctl restart app
sudo systemctl status app
curl http://127.0.0.1:3000
    whee

Generate Custom SELinux Policy

Install relevant packages.

sudo dnf provides audit2allow
sudo dnf install -y policycoreutils-python-utils

Review the proposed policy rules. Running audit2allow -a will automatically generate SELinux policy rules based on error messages logged in /var/log/audit/audit.log*.

sudo audit2allow -a

It is a good idea to review the generated SELinux policy rules because some error messages in audit.log might have been the result of unsafe activity on your machine. Many of the SELinux restrictions are in place for a reason and you do not want to disable them unnecessarily.

Install Custom SELinux Policy

Once you are satisfied with your custom SELinux policy, it is time to install it.

Install our custom SELinux policy.

X=/tmp/selinux; mkdir $X -p; cd $X
MODULE_NAME=xyz
sudo audit2allow -a -m $MODULE_NAME > $MODULE_NAME.te
sudo checkmodule -M -m -o $MODULE_NAME.mod $MODULE_NAME.te
sudo semodule_package -o $MODULE_NAME.pp $MODULE_NAME.mod
sudo semodule -i $MODULE_NAME.pp

Automate SELinux Configuration

Suppose you have a pre-generated SELinux policy named xyz.te. We can automatically compile, build and install our policy with Ansible.

Suppose we have the following file structure.

roles/server-configuration/files/xyz.te
roles/server-configuration/tasks/main.yml
roles/server-configuration/tasks/selinux.yml    

Then you can automatically install xyz.te with this task in main.yml:

---
- include: selinux.yml
  with_items:
    - xyz
  loop_control:
    loop_var: module_name
  become: true
  tags: selinux

Here are the contents of selinux.yml:

---
- name: make temporary folder
  tempfile: state=directory suffix=selinux
  register: x_register

- name: upload selinux modules
  copy:
    dest: '{{ x_register.path }}/{{ module_name }}.te'
    src: '{{ module_name }}.te'

- name: compile selinux modules
  command: checkmodule -M -m -o {{ module_name }}.mod {{ module_name }}.te
  args:
    chdir: '{{ x_register.path }}'
  changed_when: False

- name: build selinux modules
  command: semodule_package -o {{ module_name }}.pp -m {{ module_name }}.mod
  args:
    chdir: '{{ x_register.path }}'
  changed_when: False

- name: install selinux modules
  command: semodule -i {{ module_name }}.pp
  args:
    chdir: '{{ x_register.path }}'
  changed_when: False