- SELinux enforces mandatory access control based on policies and contexts, adding a critical layer of hardening over traditional Unix permissions.
- An effective configuration requires properly labeling the file system, choosing the appropriate mode (permissive/enforcing), and adjusting booleans and modules without weakening the base policy.
- The integration of SELinux with RHEL, Fedora, SUSE, and openSUSE allows mitigating the impact of many CVEs and confining services such as web servers, containers, and network daemons.
- Automating hardening and systematically using logs and tools like audit2allow makes it easier to keep SELinux operational in production without sacrificing stability.

When you set up a Linux server for production, its default configuration is usually quite open. It's designed to work perfectly out of the box, not to be a fortress . That's where SELinux comes in as a key hardening component: it adds a layer of control that continues to function even when typical defenses (file permissions, firewall, updates ) fail.
SELinux may seem daunting at first, but once you grasp its basics, it becomes an incredibly powerful tool for containing exploits, limiting damage, and meeting security benchmarks like CIS, PCI DSS, or other high-criticality standards. Instead of relying on applications to behave normally, the system forces each process to operate within very specific boundaries.
What is SELinux and why does it matter in Linux hardening?
Security-Enhanced Linux is a Linux kernel security extension based on Mandatory Access Control (MAC). Unlike classic Unix discretionary access control (DAC), where the file owner decides who can access a file, in SELinux the rules are dictated by a central policy that even root users cannot override without explicitly changing it.
This model ensures that access decisions are based on security labels (contexts) and predefined rules , not just rwx permissions. Even if a service has been compromised or has excessive permissions, SELinux can prevent it from accessing sensitive files, triggering other processes, or moving across the network beyond its authorized boundaries.
SELinux doesn't replace traditional DAC; it complements it. First, standard Unix permissions are checked, and only if DAC allows the operation does SELinux step in to validate its policy . If DAC already blocks access, SELinux neither intervenes nor logs anything, which helps reduce noise in the logs and maintains performance.
This layered approach is especially noticeable in enterprise environments such as Red Hat Enterprise Linux, Fedora, SUSE Linux Enterprise, or openSUSE Leap , where SELinux is integrated with the rest of the system's security mechanisms and with modern technologies such as containers and virtual machines.

Key concepts: SELinux policies, contexts, and domains
The foundation of SELinux is security policies that describe who can do what, against what, and how . In this language, processes are considered subjects and system resources (files, directories, sockets, ports, devices, etc.) are objects.
Instead of thinking of users as “root” or “www-data”, SELinux works with domains and typesAn Apache web server process, for example, runs in the domain httpd_t, while the files served to the client have a type like httpd_sys_content_tThe policy defines which domains can access which types, for which classes of objects (file, dir, socket, port…) and with which specific permissions (read, write, execute, getattr, append, etc.).
Each object has an associated SELinux context , a label of the form:
usuario:rol:tipo:nivel
For example, a file could be labeled as system_u:object_r:httpd_sys_content_t:s0Where The most important field for daily administration is usually the type (httpd_sys_content_t), which determines which process domains will be allowed access.
In practice, SELinux works with thousands of rules. To prevent this from becoming unmanageable, policies are divided into independent modules that can be enabled, disabled, or updated without having to recompile a giant monolithic block. This is crucial in RHEL, SUSE, and openSUSE, where each relevant service typically has its own policy module.
SELinux operating modes: enforcing, permissive, and disabled
SELinux can operate in three distinct modes, which determine the extent to which its rules are applied to the system in real time :
In enforcement mode , the kernel strictly enforces the policy. Any action that violates the rules is blocked and logged . This is the recommended mode for production when the policy is well-tuned, because this is where SELinux truly provides protection.
In permissive mode , SELinux continues to evaluate the policy but does not block anything . All violations are logged as warnings. This mode is ideal for testing, deploying new applications, or fine-tuning rules because it allows you to detect what would break the enforcement without interrupting services.
In disabled mode , SELinux is completely disabled. No policies are enforced, and no SELinux-related logs are generated. Switching between disabled and active mode (permissive or enforcing) requires a reboot because the kernel must boot with SELinux support initialized in order to tag the filesystem.
A very sensible practice in any distribution is to initially start with permissive settings , review and correct tagging and policy issues, and only switch to enforcing settings when everything is stable . Leaving it permanently disabled removes one of the most powerful layers of protection available to you.
Integrating SELinux into RHEL, Fedora, SUSE, and openSUSE
Distributions such as Red Hat Enterprise Linux, Fedora and derivatives enable SELinux by default , usually using a targeted policy that mainly confines system services started by systemd and some users.
In RHEL, in addition to the pre-configured policy, a series of tools are offered to prevent the administrator from having to constantly struggle with low-level rules. SELinux Troubleshooter stands out, analyzing denial events and suggesting specific changes (such as activating a boolean, correcting a context, or generating an additional module).
Furthermore, SELinux extends to containers (for example, with Podman) and virtualized environments. With appropriate tags, each container or VM is isolated from the others at the kernel level, even if a vulnerability in the runtime or hypervisor is compromised.
In the SUSE ecosystem, SUSE Linux Enterprise Server includes the SELinux framework in its kernel and tools , but not a comprehensive official policy. The recommended approach is to build a custom policy tailored to your environment, or use solutions like slemicro when you want a minimalist host for containers or virtualization with full SELinux support.
In openSUSE Leap it is common to rely on policies available in repositories such as security:/SELinux_legacy for testing, knowing that for a critical environment the ideal is still a policy reviewed and adjusted specifically to the deployment.
SELinux policy models: targeted, MLS, and minimum
SELinux can work with different policy models, which determine the scope and depth of control. The three most common are:
The targeted policy is designed for general environments. It focuses on confining specific services (especially network daemons) and leaves other processes in more permissive domains or even unconfined. It is the default option in most distributions because it strikes a good balance between security and compatibility.
La Multi-Level Security (MLS) policy Add the sensitivity level field to the context (s0, s1, s2, categories, etc.) and allows classify information and processes into levelsIt is designed for organizations with very strict requirements (defense, intelligence, classified environments) where it matters who can see or modify what level of data.
The minimum policy is a reduced variant, with fewer rules and controls. It is used in systems with limited security requirements or where minimal impact on compatibility is desired , sacrificing some of SELinux's confinement capabilities.
In real-world deployments, it is usually preferable to work with targeted modular policies , adjusting module by module what is protected and how, rather than trying to manage a single huge monolithic file, which is much harder to maintain.
Context management: viewing, changing, and restoring SELinux tags
One of the key tasks in SELinux administration is ensuring that files, directories, processes, and ports have the correct context according to the policy. An incorrectly assigned context can cause a service to stop working or leave a resource too exposed.
To inspect the SELinux context of files and directories, many standard commands accept the option -Z. For example, with ls -Z /ruta you can see user, role, type, and level of each entryAnd with ps Zaux You get the context of the active processes.
When a policy is installed and the file system is labeled (for example using setfiles o fixfiles with the files file_contexts), each route receives a default type according to policyIf you create a new file in an already labeled directory, it will inherit the directory's type, but if you move it from another location, it will retain its original label, which can cause inconsistencies.
If a file or directory tree has the wrong labels, you can correct them with restorecon, that restores contexts to the values defined in the policy. With options like -R (recursive) and -v (verbose) It's easy to see what's changing. It's an almost mandatory step before switching from permissive to enforcing mode on systems that have been in testing for a while.
To declare new labeling patterns, you use semanage fcontextWith this tool you write in the policy what The SELinux type must be assigned to specific paths or regular expressionsand then you apply those changes to the file system with restoreconFor example, you can label a new DocumentRoot from Apache with httpd_sys_content_t so that the web server can read it under its confined domain.
Basic configuration: enable SELinux and choose mode
The behavior of SELinux at a global level is controlled from /etc/selinux/config, where the mode is defined (enforcing, permissive o disabled) and the policy to be used (targeted, mls, minimum…).
In systems like RHEL or Fedora, the targeted policy usually comes enabled by default and in forcing modeWhereas in SUSE or openSUSE, kernel parameters in GRUB2 must be adjusted to load SELinux instead of AppArmor. This involves adding options such as security=selinux y selinux=1 to the boot line and regenerate the GRUB configuration.
After enabling SELinux at boot and selecting the policy, it is important to perform an initial full file system tag using setfiles or equivalent tools. This step It can take time and it's best to do it during a period of low demand.But it is the basis for the system to start without surprises in forcing mode.
In environments where you are migrating from AppArmor, it is critical review the files very carefully file_contexts and their local variantsbecause any serious inconsistency can prevent the system from booting. Make a backup beforehand and work with semanage fcontext Aligning policy with the reality of the system is almost mandatory.
SELinux and CVEs: how they help mitigate vulnerabilities
Vendors like Red Hat include SELinux as a factor in their CVEs impact assessment . Their severity model (Critical, Important, Moderate, Low) takes into account whether a vulnerability can be mitigated or at least contained by well-configured SELinux restrictions.
In a critical remote code execution vulnerability, type Log4Shell (CVE-2021-44228)An attacker could inject code into a service accessible from the internet. If that service runs under a highly restricted SELinux domain, the potential for harm is reduced, because will not have permission to read /etc/shadowmanipulate sensitive databases or pivot through the system outside of what is strictly necessary for its function.
In privilege escalation vulnerabilities like CVE-2023-4911 (Looney Tunables) , even if the exploit succeeds in granting a user access with higher privileges at the DAC level, the policy may still prevent key actions such as loading kernel modules, writing to system directories, or opening certain network sockets . The result is a limitation on what can be done with that newly gained access.
In cases of moderate vulnerabilities (for example, certain issues in Grafana) that require unusual configurations or are difficult to exploit, SELinux acts as an additional barrier, preventing a minor flaw from escalating into a serious incident. Often, the policy directly blocks the access that the exploit would need to compromise the system.
In low-impact vulnerabilities, such as bugs that cause crashes in user applications (for example in editors like vim) , SELinux is not usually decisive in preventing the problem itself, but it still maintains its containment role, ensuring that a faulty process does not leave its conceptual sandbox.
SELinux in action: a real-world example of web server confinement
Imagine a web server running RHEL or Fedora that exposes several applications and, despite being protected with patches, ends up being vulnerable to a remote execution exploit in one of its components. Without SELinux, an attacker executing code as the web server user could install backdoors, read credentials, or pivot to other systems.
With SELinux in enforcing mode and a well-tuned targeted policy, Apache, Nginx, or similar processes run under the domain httpd_t, what's wrong with it permissions limited to files labeled with types such as httpd_sys_content_t o httpd_sys_rw_content_t, and controlled access to defined ports also with appropriate context.
This means that, although the exploit allows commands to be executed, the compromised process It cannot read files like /etc/shadow nor touch database directories labeled with specific types (for example mysqld_db_t), nor open arbitrary connections to other internal services if the network policy restricts it.
Instead of a full system compromise, the intrusion is confined within the boundaries of the website domain . Yes, it will still be an incident to investigate, but the potential impact is much lower, and the attacker has a much harder time operating.
Booleans, modules, and tools for adjusting policies
Besides proper labeling, day-to-day work with SELinux usually revolves around tweaking the base policy for minor adjustments without having to rewrite it entirely . This is where booleans and custom modules come into play.
The booleans SELinux These are on/off switches that alter parts of the behavior of the already compiled policy. For example, a boolean can allow or prohibit the FTP server from writing to certain directories (in the case of allow_ftpd_anon_write), or that the web server initiates outgoing connections to the network.
With getsebool -a o semanage boolean -l You can list these switches and see their descriptions. To change them permanently, you use setsebool -P nombre_booleano on|offwhere the option -P ensures that the change is saved to disk and survives rebootsIt's a very convenient way to adapt the "official" policy to the specific needs of your server.
On the other hand, the use of policy modules It allows you to extend or modify rules without touching the base policy. You can view the active modules with semodule -lto disable one with semodule -d nombre or reactivate it with semodule -e nombreIn SUSE/openSUSE this is especially useful for fine-tuning which parts of the system you want to be under the focus of SELinux while you stabilize your deployment.
When you need to grant very specific additional permissions, the combination of audit2allow y semodule It makes life much easier. Based on the records of /var/log/audit/audit.log, audit2allow shows you which rule was blocked and generates a module which, if you install it, allows exactly what was previously denied.
Logs, auditing, and troubleshooting with SELinux
Each time SELinux prevents an action that the policy does not authorize, a AVC denial (Access Vector Cache denial) that is usually recorded in /var/log/audit/audit.logprovided that the service auditd is working.
These entries include a lot of information: what has been attempted to be done (avc: denied { append }, write, getattretc.), which process has requested it (pid, comm=), on which file or resource (name=, dev=, ino=), what context did the original process have (scontext) and what context the destination (tcontext)At first they seem like cryptic lines, but with some practice they are pure gold for understanding what is happening.
To avoid going crazy reading the log manually, tools like ausearch allow filtering by message type (for example, -m AVC) or by temporary window (-ts recent). And, above all, audit2allow and utilities such as sealert help to to translate these events into almost human language and show suggestions.
A typical troubleshooting workflow would be to use audit2allow -w -a To see explanations of the latest notices, then audit2allow -a o -i fichero to inspect specific rules, and finally decide if it's worthwhile to create a module that unlocks that permission Or if, on the contrary, the block is on the safe side and it's best not to touch it.
Whenever modules are generated with audit2allow -M nombre and are installed with semodule -iIt's worth reviewing these settings, because the tool tends to be generous and could grant more access than strictly necessary. SELinux offers a lot of flexibility for hardening access, but careless use can end up creating loopholes in the policy itself.
SELinux within a Linux hardening strategy
SELinux does not exist in a vacuum: it is integrated into a broader hardening strategy that includes limited privilege users, firewalls, SSH hardening, anti-brute-force mechanisms, and configuration automation.
A very common pattern after installing a server is to create a user with limited sudo privileges so as never to work as direct root, activate a network firewall (such as ufw or iptables/nftables) , install tools such as Fail2ban to block repeated access attempts and configure SSH with good practices (non-standard port, disable root access, key authentication, attempt limits, robust encryption, etc.).
Building on this foundation, SELinux adds the MAC layer: even if an attacker gains access to a user with misconfigured sudo privileges or an SSH password, the policy can still restrict which processes and files that user accesses . It's not foolproof, but it closes many of the vulnerabilities typically exploited by automated attacks described in matrices like MITRE ATT&CK.
As the number of servers grows, manually applying all these hardening measures becomes impractical. This is where automation and orchestration tools (Ansible, Puppet, Chef, commercial automated hardening solutions, etc.) come into play, allowing for the deployment of consistent SELinux policies, adjustment of booleans, path tagging, and maintenance of desired states without spending hours per machine.
In organizations with hundreds of nodes, this automation can be the difference between having a reasonably homogeneous and secure environment , or a jungle of inconsistent configurations where SELinux is disabled on half of the servers "so it doesn't bother anyone."
Ultimately, when SELinux is well implemented—with enforcing mode, consistent contexts, revised policies, fine-tuned modules, and monitored logs—it becomes a kind of safety net that keeps strange behavior at bay, contains intrusions, and helps demonstrate that robust access controls are being applied for audits, regulations, and security best practices.