What is SELinux and why is it important?
SELinux, Security Enhanced Linux, is a security architecture for Linux. It controls access to applications, files and processes in a Linux system. It uses security policies that define what can or cannot be accessed. For example, if a process or application (termed as a subject) wants to access an object such as a file, SELinux checks against the corresponding rule and determine whether to allow or to deny access.
The traditional Linux security used discretionary access control which defined what users, group and others can own and manipulate and users can change these permissions whenever they like. However, SELinux uses what is called Mandatory access control. Even if some permissions are defined through discretionary access control, if the same permission is not allowed by SELinux, it is not going to be permitted. This is because the policies are administratively set and fixed. This means that if an external user tries to change permissions to access files, the settings of SELinux that prevents such access will forbid the access, making your system generally save. That being said, it is important to keep SElinux in enforcing mode but learn how to manage various policies.
How does SELinux Works?
By default, SELinux uses ‘targeted policy’ and is always ‘enforcing’. Targeted means that only specific (targeted) processes are protected by SELinux. Enforcing status means that SELinux policies are applied accordingly. You can change these settings under /etc/selinux/config file. Other status options are:
- Permissive – SElinux rules are not applied but operations are logged in case there is a breach
- Disabled – SELinux policies not applicable
SElinux uses labelling and enforcement. Processes, files etc are labelled with a SELinux context. Files and directories have their labels stored as extended attributes on the filesystem while processes and ports labels are managed by the kernel. Labelling group the resources together such that those with the same labels access each other but are not allowed to access those with different labels. You can work around enabling access for example by changing the SELinux context of the file or process or changing the Boolean status. Booleans are basically the on/off settings of SELinux.
Managing SELinux
You can manually manage SELinux on your Linux System by running the appropriate commands directly on your terminal. Most Linux packages needed for SELinux management are installed by default, but you may need to manually install others for your use. Some packages installed by default include:
- policycoreutils provides utilities such as restorecon, secon, setfiles, semodule, load_policy, and setsebool, for operating and managing SELinux.
- selinux-policy provides a basic directory structure, the selinux-policy.conf file, and RPM macros.
- selinux-policy-targeted provides the SELinux targeted policy.
- libselinux – provides an API for SELinux applications.
- libselinux-utils provides the avcstat, getenforce, getsebool, matchpathcon, selinuxconlist, selinuxdefcon, selinuxenabled, and setenforce utilities.
- libselinux-python provides Python bindings for developing SELinux applications.
Some optional packages that you may need to manually install are as below. Simply run ‘ sudo yum install <package-name>’
- selinux-policy-devel provides utilities for creating a custom SELinux policy and policy modules.
- selinux-policy-doc provides manual pages that describe how to configure SELinux altogether with various services.
- selinux-policy-mls provides the MLS (Multi-Level Security) SELinux policy.
- Settroubleshot and setroubleshoot-server translates denial messages, produced when access is denied by SELinux, into detailed descriptions that can be viewed with the sealert utility, also provided in this package.
- mcstrans translates levels, such as s0-s0:c0.c1023, to a form that is easier to read, such as SystemLow-SystemHigh.
- policycoreutils-python provides utilities such as semanage, audit2allow, audit2why, and chcat, for operating and managing SELinux.
- policycoreutils-gui provides system-config-selinux, a graphical utility for managing SELinux.
Some of the things you can do include: change SELinux configuration settings, set Boolen on or off, change context of a file/directory and so on. Some of the useful commands include:
# Edit SELinux Configuration file
sudo vim /etc/selinux/config
# List all Booleans
getsebool -a
# Get a specific Boolean
getsebool <Boolean>
# Set a Boolean on or off
setsebool <Boolean> <on|off>
setsebool -P <Boolean> <1|0>
# Get SELinux contect of a file
ls -lZ <path-to-file>
# Change context of a file
chcon -t <context-type> <path-to-file>
# Or simply reference a known good file
chcon –reference <path-to-good-file> <path-to-ile-to-be-changed>
#Restore a directory and all its content to the default context
restorecon -vR <directory-path>
# Set the file context of a file/directory by telling SELinux what it needs to do with the file before enabling the setting with restorecon
semanage fcontext -a -e <existing-directory> <new-directory>
Managing SELinux with Ansible
Ansible is an IT management tool that is useful when working on a number of remote hosts at ago. With Ansible, you can create a single file that defines all the remote hosts you wish to manage and playbooks that contain commands to be executed on the hosts. Ansible uses ssh to access the remote hosts. Let us look at various playbooks that can help us manage SELinux using Ansible.
Changing SELinux States With Ansible
To be able to change SElinux state and policies, we need to install ansible.posix.selinux plugin on the Ansible server. The plugin is part of ansible.posix collection.
$ ansible-galaxy collection install ansible.posix
Process install dependency map
Starting collection install process
Installing 'ansible.posix:1.2.0' to '/home/lorna/.ansible/collections/ansible_collections/ansible/posix'
Now write the playbook to set SELinux in Permissive mode. Am assuming that you already have a host file for the remote hosts to be managed
---
- hosts: all
tasks:
- name: Set SELinux to Permissive mode
ansible.posix.selinux:
policy: targeted
state: permissive
Run the playbook
$ ansible-playbook playbook.yml
PLAY [all] ***********************************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************
ok: [192.168.100.161]
TASK [Set SELinux to Permissive mode] ***********************************************************************************************************************************************************************************************************************
changed: [192.168.100.161]
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************
192.168.100.161 : ok=2 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
To change back to enforcing mode;
---
- hosts: all
tasks:
- name: Set SELinux to Enforcing Mode
ansible.posix.selinux:
policy: targeted
state: enforcing
To disable SELinux using Ansible:
---
- hosts: all
tasks:
- name: Disable SELinux
ansible.posix.selinux:
state: disabled
Managing SELinux File Context with Ansible
File context can be updated with chcon, restorecon and semanage. Semanage, however, just tells SElinux what it is required to do with the file/directory anytime there is a change to the file/directory but restorecon does the actual change. When updating manually, use semanage fcontext followed by restorecon to apply the changes. When using targeted policy, file context changes are written to /etc/selinux/targeted/files We require libselinux-python and policycoreutils-python installed on our remote hosts to be able to use ‘semanage’. On the Ansible server, install community.general.sefcontext plugin
$ ansible-galaxy collection install community.general
Process install dependency map
Starting collection install process
Installing 'community.general:3.4.0' to '/home/lorna/.ansible/collections/ansible_collections/community/general'
In our playbook we are going to install the packages needed and look at an example to allow Apache to modify files in /srv/git_repos
---
- hosts: all
become: yes
tasks:
- name: install Required Packages
yum:
name:
- "python3-libselinux"
- "policycoreutils-python-utils"
state: present
- name: Allow Apache to modify files in /srv/git_repos/
community.general.sefcontext:
target: '/srv/git_repos(/.*)?'
setype: httpd_sys_rw_content_t
state: present
- name: Apply SELinux file context
ansible.builtin.command: restorecon -irv /srv/git_repos
Now run the playbook
$ ansible-playbook playbook.yml
PLAY [all] ***********************************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************
ok: [192.168.100.161]
TASK [install Required Packages] *************************************************************************************************************************************************************************************************************
changed: [192.168.100.161]
TASK [Allow Apache to modify files in /srv/git_repos/] ***************************************************************************************************************************************************************************************
changed: [192.168.100.161]
TASK [Apply SELinux file context] ************************************************************************************************************************************************************************************************************
changed: [192.168.100.161]
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************
192.168.100.161 : ok=4 changed=3 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Managing SELinux Network Port Type Definitions Using Ansible
To be able to change manage port definitions, we require community.general.seport plugin which is part of community.general collection. I have already shown how to install community.general collection using ansible-galaxy. We also need to install libselinux-python and policycoreutils python modules. Below is a playbook showing various examples of enabling ports.
---
- hosts: all
become: yes
tasks:
- name: install Required Packages
yum:
name:
- "python3-libselinux"
- "policycoreutils-python-utils"
state: present
- name: Allow sshd to listen on tcp port 20222
community.general.seport:
ports: 20222
proto: tcp
setype: ssh_port_t
state: present
- name: Allow memcached to listen on a range of ports
community.general.seport:
ports: 10000-10100,10112
proto: tcp
setype: memcache_port_t
state: present
Go ahead and run the playbook
$ ansible-playbook playbook.yml
PLAY [all] ***********************************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************
ok: [192.168.100.161]
TASK [install Required Packages] *************************************************************************************************************************************************************************************************************
ok: [192.168.100.161]
TASK [Allow sshd to listen on tcp port 20222] ************************************************************************************************************************************************************************************************
changed: [192.168.100.161]
TASK [Allow memcached to listen on a range of ports] *****************************************************************************************************************************************************************************************
changed: [192.168.100.161]
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************
192.168.100.161 : ok=4 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
Managing SELinux Booleans Using Ansible
Booleans are on|off settings of SELinux policies. You can manually display all Booleans and their statuses using getsebool -a command. Once you identify the Boolean that you need to change status you can manually use the command setsebool <Boolean> <on|off>. To manage SELinux Booleans with Ansible, below is a playbook example. Note that we require ansible.posix.seboolean module which is part of ansible.posix collection. Let’s first install the collection.
$ ansible-galaxy collection install ansible.posix
Process install dependency map
Starting collection install process
Skipping 'ansible.posix' as it is already installed
We also need to install libselinux-python and libsemanage-python. The below playbook installs the required packages and sets the boolean httpd_can_connect_ftp to ‘ON’ and enable it persist on reboot.
---
- hosts: all
become: yes
tasks:
- name: Install Required Packages
yum:
name:
- "python3-libselinux"
- "python3-libsemanage"
state: present
- name: Set httpd_can_connect_ftp flag ON and enable it to persist on reboot
ansible.posix.seboolean:
name: httpd_can_connect_ftp
state: yes
persistent: yes
Upon running the playbook:
$ ansible-playbook playbook.yml
PLAY [all] ***********************************************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ***********************************************************************************************************************************************************************************************************************
ok: [192.168.100.161]
TASK [install Required Packages] *************************************************************************************************************************************************************************************************************
ok: [192.168.100.161]
TASK [Set httpd_can_connect_ftp flag ON and enable it to persist on reboot] ******************************************************************************************************************************************************************
changed: [192.168.100.161]
PLAY RECAP ***********************************************************************************************************************************************************************************************************************************
192.168.100.161 : ok=3 changed=1 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
In this guide, we have learnt what SELinux is and why it is important to keep it enforcing and we have also seen how SELinux works. Most of the time during our operations, we disable SELinux to prevent it from interfering with our Linux operations little do we know that it is actually an important security aspect in Linux. It is important to understand how to manage SElinx instead of totally disabling it.
Best Courses to Learn Ansible Automation:
- Dive Into Ansible – From Beginner to Expert in Ansible
- Ansible Essentials with Hands-on Labs
- Mastering Ansible
- Ansible Advanced – Hands-On – DevOps
- Ansible for the Absolute Beginner – Hands-On – DevOps
- Ansible for the DevOps Beginners & System Admins
I hope this guide has helped you to appreciate the importance of SELinux and has taught you how to play around SELinux policies to suit your setup needs. Check more interesting guides below: