dotlinux guide

Guide to Configuring SELinux for Beginners

Security-Enhanced Linux (SELinux) is a mandatory access control (MAC) system built into the Linux kernel, designed to provide an additional layer of security beyond the standard discretionary access control (DAC) model. Unlike DAC, which relies on user and group permissions (e.g., chmod, chown), SELinux enforces fine-grained policies that restrict process actions based on predefined rules. For beginners, SELinux can seem intimidating due to its complexity, but mastering its basics is critical for securing Linux systems. This guide will break down SELinux fundamentals, walk through configuration steps, and provide practical examples to help you confidently manage SELinux on your systems.

Table of Contents

  1. Understanding SELinux Fundamentals

    • 1.1 What is SELinux?
    • 1.2 DAC vs. MAC
    • 1.3 SELinux Architecture
  2. SELinux Modes

    • 2.1 Enforcing
    • 2.2 Permissive
    • 2.3 Disabled
  3. Basic SELinux Configuration Tools

    • 3.1 Checking SELinux Status
    • 3.2 Temporarily Changing Modes
    • 3.3 Permanently Changing Modes
  4. Managing SELinux Contexts

    • 4.1 What Are SELinux Contexts?
    • 4.2 Viewing Contexts
    • 4.3 Modifying Contexts
  5. Common SELinux Scenarios for Beginners

    • 5.1 Web Server (Apache/Nginx) with Custom Directories
    • 5.2 SSH on a Non-Default Port
  6. Troubleshooting SELinux Issues

    • 6.1 Understanding AVC Denials
    • 6.2 Using audit2allow to Generate Rules
    • 6.3 Testing in Permissive Mode
  7. SELinux Best Practices

  8. Conclusion

  9. References

1. Understanding SELinux Fundamentals

1.1 What is SELinux?

SELinux is a security framework integrated into the Linux kernel that enforces mandatory access control (MAC). It was developed by the National Security Agency (NSA) to address limitations in the standard Linux DAC model, where users with root privileges can bypass most security restrictions.

1.2 DAC vs. MAC

  • DAC (Discretionary Access Control): The default Linux security model, where file owners set permissions (e.g., rwx for user/group/others). Access is determined by user identity and ownership.
  • MAC (Mandatory Access Control): SELinux adds a second layer, where access is controlled by system-wide policies. Even root users are restricted by SELinux rules unless explicitly allowed.

1.3 SELinux Architecture

SELinux relies on three core components:

  • Policy: A set of rules defining allowed interactions between subjects (processes) and objects (files, sockets, etc.).
  • Contexts: Labels assigned to all subjects and objects (format: user:role:type:level). The type component is most critical for beginners.
  • Enforcement: The kernel enforces policy rules by checking if a subject’s context is allowed to access an object’s context.

2. SELinux Modes

SELinux operates in three modes, which determine how strictly policies are enforced:

2.1 Enforcing

SELinux actively enforces policies and blocks unauthorized actions. This is the default and recommended mode for production systems.

2.2 Permissive

SELinux logs policy violations (denials) but does not block them. Use this mode for testing or troubleshooting to identify what would be blocked in Enforcing mode.

2.3 Disabled

SELinux is completely turned off. Not recommended—disabling removes all SELinux protections and requires a reboot to re-enable.

3. Basic SELinux Configuration Tools

3.1 Checking SELinux Status

Use sestatus to view the current SELinux status, mode, and policy:

$ sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing
Mode from config file:          enforcing
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Max kernel policy version:      33

To check only the current mode, use getenforce:

$ getenforce
Enforcing

3.2 Temporarily Changing Modes

Use setenforce to switch modes temporarily (persists until reboot):

  • Switch to Permissive mode:
    $ sudo setenforce 0
    $ getenforce  # Verify: Outputs "Permissive"
  • Switch back to Enforcing mode:
    $ sudo setenforce 1
    $ getenforce  # Verify: Outputs "Enforcing"

3.3 Permanently Changing Modes

To persist mode changes across reboots, edit the /etc/selinux/config file:

$ sudo nano /etc/selinux/config

Set SELINUX= to enforcing, permissive, or disabled:

SELINUX=enforcing  # Recommended for production
# SELINUX=permissive  # For testing/troubleshooting
# SELINUX=disabled    # Not recommended!

Note: Changing to disabled requires a reboot. Re-enabling from disabled also requires a reboot.

4. Managing SELinux Contexts

4.1 What Are SELinux Contexts?

Every process, file, directory, and network port in SELinux has a context—a label that defines its role in the policy. Contexts follow the format:

user:role:type:level
  • user: SELinux user (e.g., unconfined_u for regular users).
  • role: SELinux role (e.g., object_r for files, system_r for processes).
  • type: The most critical component (e.g., httpd_t for Apache processes, httpd_sys_content_t for web files).
  • level: Used for Multi-Level Security (MLS) (advanced; often omitted in basic setups).

4.2 Viewing Contexts

To view the context of files/directories, use ls -Z:

$ ls -Z /var/www/html
-rw-r--r--. root root system_u:object_r:httpd_sys_content_t:s0 index.html

Here, httpd_sys_content_t is the type, indicating the file is allowed to be read by Apache.

To view process contexts, use ps -Z:

$ ps -Z | grep httpd
system_u:system_r:httpd_t:s0    1234 ?        00:00:00 httpd

4.3 Modifying Contexts

SELinux contexts can be modified temporarily (with chcon) or permanently (with semanage).

Temporary Changes with chcon

chcon (change context) modifies a file’s context, but changes are lost after a reboot or when restorecon is run (see below).

Example: Temporarily set a file’s type to httpd_sys_content_t:

$ chcon -t httpd_sys_content_t /var/www/custom/index.html
$ ls -Z /var/www/custom/index.html  # Verify
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 index.html

Permanent Changes with semanage

To make context changes persistent, use semanage fcontext (file context management). This updates the SELinux policy to associate a path with a specific context.

Example: Permanently set the context for /var/www/custom and its subdirectories:

# Add a rule to map /var/www/custom(/.*)? to httpd_sys_content_t
$ sudo semanage fcontext -a -t httpd_sys_content_t "/var/www/custom(/.*)?"

# Apply the new context (restorecon = restore context)
$ sudo restorecon -Rv /var/www/custom
restorecon reset /var/www/custom context unconfined_u:object_r:default_t:s0->system_u:object_r:httpd_sys_content_t:s0
restorecon reset /var/www/custom/index.html context unconfined_u:object_r:default_t:s0->system_u:object_r:httpd_sys_content_t:s0
  • -R: Recursively apply to subdirectories.
  • -v: Verbose output.

5. Common SELinux Scenarios for Beginners

5.1 Web Server with Custom Directories

By default, Apache/Nginx is allowed to read files labeled httpd_sys_content_t (typically in /var/www/html). If you host files in a custom directory (e.g., /srv/mywebsite), SELinux will block access unless you update the context.

Step 1: Create the custom directory and add a test file

$ sudo mkdir -p /srv/mywebsite
$ echo "Hello, SELinux!" | sudo tee /srv/mywebsite/index.html

Step 2: Check the default context (likely default_t, which Apache cannot read)

$ ls -Z /srv/mywebsite
drwxr-xr-x. root root unconfined_u:object_r:default_t:s0 mywebsite

Step 3: Permanently set the context to httpd_sys_content_t

$ sudo semanage fcontext -a -t httpd_sys_content_t "/srv/mywebsite(/.*)?"
$ sudo restorecon -Rv /srv/mywebsite

Step 4: Verify Apache can access the file
Update your web server config to serve /srv/mywebsite, then test with curl:

$ curl http://localhost
Hello, SELinux!  # Success if SELinux allows access

5.2 SSH on a Non-Default Port

SELinux restricts services to specific ports. For example, SSH is allowed on port 22 (ssh_port_t type). To use SSH on a custom port (e.g., 2222), update SELinux to allow it.

Step 1: Update SSH config to use port 2222
Edit /etc/ssh/sshd_config:

Port 2222  # Add/modify this line

Restart SSH:

$ sudo systemctl restart sshd

Step 2: Check for SELinux denial (if Enforcing mode)
If SELinux blocks the new port, you’ll see an error when connecting. Check the audit log (see Section 6) for denials.

Step 3: Allow port 2222 for SSH with semanage port

# Add port 2222 to the ssh_port_t type
$ sudo semanage port -a -t ssh_port_t -p tcp 2222

# Verify the port is allowed
$ sudo semanage port -l | grep ssh_port_t
ssh_port_t                     tcp      2222, 22

Step 4: Test the connection

$ ssh -p 2222 user@localhost  # Should now work

6. Troubleshooting SELinux Issues

6.1 Understanding AVC Denials

When SELinux blocks an action, it logs an AVC (Access Vector Cache) denial to /var/log/audit/audit.log (or /var/log/messages on some systems).

Example AVC denial log entry (simplified):

type=AVC msg=audit(1234567890.123:456): avc:  denied  { read } for  pid=1234 comm="httpd" name="index.html" dev="sda1" ino=789 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:default_t:s0 tclass=file permissive=0

Key fields:

  • comm="httpd": Process (Apache) trying to access the resource.
  • scontext: Subject context (httpd_t = Apache process).
  • tcontext: Target context (default_t = file with incorrect type).
  • { read }: Action blocked (read access).

6.2 Using audit2allow to Generate Rules

audit2allow parses AVC denials and generates SELinux policy rules to allow the blocked action.

Step 1: Install policycoreutils-python-utils (required for audit2allow)

$ sudo dnf install policycoreutils-python-utils  # RHEL/CentOS/Fedora
# Or for Debian/Ubuntu: sudo apt install policycoreutils

Step 2: Generate a rule from the audit log

# Extract denials for httpd and generate a policy module
$ sudo audit2allow -a -M my-httpd-policy
  • -a: Read all denials from /var/log/audit/audit.log.
  • -M my-httpd-policy: Create a module named my-httpd-policy.

Step 3: Load the new policy

$ sudo semodule -i my-httpd-policy.pp  # Load the module

6.3 Testing in Permissive Mode

If troubleshooting is complex, temporarily switch to Permissive mode to log denials without blocking actions:

$ sudo setenforce 0  # Switch to Permissive
# Perform the action (e.g., access the web page)
$ sudo setenforce 1  # Switch back to Enforcing

Use audit2allow to analyze the logged denials and create rules before re-enabling Enforcing mode.

7. SELinux Best Practices

  1. Keep SELinux in Enforcing Mode: Only use Permissive mode for troubleshooting. Disabling SELinux removes critical security protections.
  2. Use semanage for Permanent Changes: Avoid chcon for long-term context modifications; use semanage fcontext and restorecon.
  3. Update SELinux Policies: Regularly update selinux-policy packages to get the latest rules:
    $ sudo dnf update selinux-policy*
  4. Use restorecon After File Moves: When moving files (e.g., with mv), their context may not update automatically. Run restorecon -Rv /path to reset contexts.
  5. Limit Custom Policies: Minimize custom rules generated with audit2allow. Prefer built-in types (e.g., httpd_sys_content_t) over creating new policies.

8. Conclusion

SELinux is a powerful tool for securing Linux systems, but it requires patience to master. By understanding modes, contexts, and core tools like semanage, restorecon, and audit2allow, you can confidently configure SELinux to enforce least-privilege access.

Start with Enforcing mode, use Permissive mode for troubleshooting, and refer to audit logs to resolve denials. With practice, SELinux will become an integral part of your Linux security workflow.

9. References