SELinux hardening with Ansible
Table of Contents
In the article SELinux as a security pillar of an operating system - Real-world benefits and examples, we demonstrated real-world examples of SELinux protecting the systems. By default, RHEL provides SELinux in a configuration that does not require further adjustments in the most common scenarios. But, usability comes at the expense of security. On one hand, SELinux has a lot of security features and protections you can use to harden security, without limitations. On the other hand, configuring SELinux can be a complex and time-consuming task.
This article demonstrates how to quickly and easily harden your system with SELinux using an Ansible playbook. On top of that, with the Ansible automation tool, you can manage multiple hosts at once.
selinux System Role and selinux-playbooks
On RHEL-compatible systems, you can configure SELinux using System Roles, which is a collection of Ansible roles and modules providing a consistent configuration interface to remotely manage multiple RHEL systems. With the selinux
System Role, you can:
- set enforcing or permissive mode
- restoring file contexts on specified files or directories
- set and get booleans
- set and get file contexts
- manage logins
- manage ports
- manage SELinux modules
- save or clean local policy modifications
- lock down a system
The selinux-playbooks Github repository contains preconfigured SELinux booleans, which prevent processes from memory execution, sharing files, and connecting to ports. You can disable unconfined and permissive domains by applying the playbook from this repository. Moreover, an option for user mapping simplifies confining users. You can also use two additional playbooks for reverting SELinux configuration and locking down a system with SELinux.
Installation
You must install the Ansible tool to configure and apply playbooks. For the SELinux configuration, install also the following packages providing system roles.
RHEL 9:
# dnf install rhel-system-roles
Fedora:
# dnf install linux-system-roles
Download the configurable Ansible playbooks from the fedora-selinux Github project:
$ git clone https://github.com/fedora-selinux/selinux-playbooks.git
Move to the SELinux hardening directory:
$ cd selinux-playbooks/selinux-hardening/
Configuration
You can manage the main SELinux configuration through the selinux-playbook.yml
file. The playbook includes variables for defining where SELinux is targeted and enforced, the file with hosts, tasks, SELinux roles, files for configuring SELinux booleans, and the file where users are mapped into SELinux users.
Hosts
By default, the configuration is targeted on localhost
. Through the hosts.yaml
file in the inventory/
directory , you can define the hosts you want to configure with the SELinux playbook. For example:
[webserver]
192.168.122.164
When you manage multiple hosts, you must define them in the main configuration file, selinux-playbook.yml
. Make sure to use the -i inventory/hosts
option when you run the playbook.
Users
Linux users, who are not mapped into SELinux users, are by default assigned to the SELinux user unconfined_u
. This is the least restrictive user role. By mapping users to the SELinux policy, the configuration is more strict. SELinux controls user access through the defined SELinux users:
SELinux user | Description |
---|---|
unconfined | unconfined user role |
sysadm | general system administration role |
staff | administrator’s unprivileged user |
user | generic unprivileged user |
guest | least privileged terminal user |
xguest | least privileged X user |
Linux users are mapped to the SELinux policy in the users/user_mapping.yml
file.
- The
login
parameter contains a user name of a user that is confined as an SELinux user. - The SELinux user is defined in the
seuser
parameter. - The
state
parameter can contain one of the following values:
**present
- the user is mapped to SELinux users
**absent
- the user is removed from the policy
Usage:
user_mapping:
- { login: '<username>', seuser: '<selinux_user>', state: '<absent/present>'}
For example:
user_mapping:
- { login: '__default__', seuser: 'unconfined_u', state: 'present' }
- { login: 'niki', seuser: 'staff_u', state: 'present'}
SELinux booleans
SELinux booleans provide a quick way to configure parts of the SELinux policy. The following YAML files use booleans to prevent or mitigate various attacks:
files/execmem.yml
- booleans to prevent execution of memory, stack, and heap and process tracing.files/cant_connect.yml
- booleans to prevent processes from connecting to port.files/deny_export.yml
- booleans to prevent Samba, GlusterFS, or NFS from sharing files.
You can customize the SELinux policy by enabling or disabling them, by changing its state to on or off. For example:
# Allow cluster administrative domains to connect to the network using TCP.
- { name: 'cluster_can_network_connect', state: 'off', persistent: 'yes' }
Running the playbook
After you customize the configuration files, you can run selinux-playbook
by using the following command:
# ansible-playbook selinux-playbook.yml -i inventory/hosts
If you run the playbook without any customization, SELinux booleans block domains from connecting to the port, exporting files, or executing in memory, heap, and stack. Default Linux users are assigned to staff_u
. Permissive and unconfined domains are deactivated.
Reverting the configuration changes
To restore the SELinux configuration to the state before applying selinux-playbook
, use the revert/revert-playbook.yml
file. You can specify hosts through the inventory/hosts.yaml
file if different than localhost
.
Use the following command to revert the configuration changes by selinux-playbook.yml
:
# ansible-playbook revert/revert-playbook.yml -i inventory/hosts
System lockdown
The system-lockdown/selinux-lockdown-playbook.yml
playbook utilizes three powerful SELinux booleans, which prevent processes from transitioning to privileged user domains, restrict confined users from inserting Linux kernel modules (for example, an SELinux policy module), and manage the SELinux policy:
Boolean | Description | State |
---|---|---|
secure_mode | Do not allow transition to sysadm_t , sudo and su |
on |
secure_mode_insmod | Do not allow any processes to load kernel modules | on |
secure_mode_policyload | Do not allow any processes to modify kernel SELinux policy | on |
If you enable the secure_mode_policyload
boolean, the system restricts any management of SELinux policy, modules, booleans, and the SELinux state. You can change this configuration only by rebooting the system and adjusting the SELinux state during the boot time by using the enforcing=0
kernel parameter. This switches SELinux to permissive mode.
IMPORTANT: Use this playbook only if you have a clear understanding of the changes it makes. If you run this playbook with all secure booleans enabled, keep in mind that users won't be able to revert the system lockdown using the revert playbook. Additionally, users will lose the ability to perform any operations related to SELinux.
Run the system-lockdown
playbook:
# ansible-playbook system-lockdown/selinux-lockdown-playbook.yml -i inventory/hosts
Conclusion
Ansible playbooks provide an efficient way to configure SELinux on one or multiple systems. The selinux-playbooks
project contains a set of playbooks you can use for additional security hardening of your systems depending on your scenario.
You can configure SELinux to block processes from sharing files, connecting to ports, and accessing memory. You can also confine Linux users by mapping them to SELinux users. You can also revert changes to the SELinux configuration back to its original state and lock down the SELinux system to prevent any further modifications.
Additional resources
For details on managing SELinux with Ansible and more information about the SELinux role, see the linux-system-roles/selinux Github repository and the Using the selinux System Role section in the Using SELinux document. The Automating system administration by using RHEL System Roles document provides comprehensive guidance for installing, configuring, and using RHEL System Roles.
Comments