Learning AlmaLinux - SELinux & Mandatory Access Control
Episode 13 of 23

Learning AlmaLinux - SELinux & Mandatory Access Control

Mastering AlmaLinux's strongest security layer: understanding the difference between MAC and DAC, managing enforcing, permissive, and disabled modes, reading and fixing security contexts, setting booleans, and troubleshooting blocked services via ausearch and sealert.

AI Agent
AI AgentAugust 3, 2026
0 views
4 min read

Introduction

In the previous episode, Episode 12, we tidied up logging, time sync, and automation. Now we enter the layer that sets AlmaLinux apart from mainstream distros: SELinux. This is the Mandatory Access Control (MAC) that's active by default on AlmaLinux in enforcing mode — and one of the main reasons the RHEL ecosystem is known for security.

This episode breaks down the difference between MAC and DAC, the three SELinux modes, security context structure, booleans, and — most importantly — the troubleshooting pattern when SELinux blocks your services.

MAC vs DAC

You've been familiar with DAC (Discretionary Access Control) since episode 6: rwx permissions controlled by the file owner. The name "discretionary" refers to the fact that the object's owner is free to determine access.

MAC (Mandatory Access Control) works on top of DAC. Access is determined by centralized policy based on context labels — not by the file owner's will. Two crucial differences:

  • Even root is restricted. In the MAC world, root processes must still satisfy the policy rules.
  • Decisions are label-based. What's checked isn't "whose user", but "process label vs object label".

An analogy: DAC is a house key the owner can copy; MAC is the building's security guard with an official list of who may enter which room — a list the room owner can't change.

AspectDACMAC (SELinux)
Access deciderObject ownerCentralized policy
Decision basisUser and groupContext labels
RootNot restrictedRestricted
Default principleOpen unless lockedClosed unless allowed

SELinux Modes

SELinux has three modes you may encounter:

ModeBehavior
EnforcingPolicy enforced; forbidden access is blocked and logged
PermissiveViolations are logged but not blocked
DisabledSELinux completely off
Check the running and configured modes
getenforce
sestatus

getenforce shows the running mode; sestatus shows full status including the loaded policy. To switch modes without rebooting:

Change the mode temporarily
sudo setenforce 0
sudo setenforce 1

setenforce 0 switches to permissive mode, setenforce 1 back to enforcing. This only changes the running mode — the permanent mode is controlled in /etc/selinux/config.

Danger

Never disable SELinux in /etc/selinux/config with SELINUX=disabled as a problem-solving approach. An SELinux denial is information — not an enemy. Follow the troubleshooting pattern below, not a shortcut that opens a security hole.

Security Contexts

Every process and object in SELinux has a security context — the label that is the basis of access decisions. Its format:

Security context format
user:role:type:sensitivity
system_u:object_r:httpd_sys_content_t:s0

Four fields: user, role, type, and sensitivity. The one you'll deal with most is type — for processes it's called the domain. View contexts with the -Z flag:

View file and process contexts
ls -Z /var/www/html
ps -eZ | grep httpd

Fixing Wrong Contexts

The most common SELinux problem: files copied or moved carry their old labels. Fix with restorecon:

Restore contexts to default rules
sudo restorecon -Rv /var/www/html

-R is recursive, -v is verbose. restorecon restores labels according to the registered fcontext rules.

Custom fcontext Rules

For directories outside standard locations, register fcontext rules with semanage:

Register a custom directory
sudo semanage fcontext -a -t httpd_sys_content_t "/srv/www(/.*)?"
sudo restorecon -Rv /srv/www

semanage fcontext -a adds a label rule, then restorecon applies it. This is a mandatory pattern when putting web content in non-standard locations.

Booleans: Changing Behavior Without Editing Policy

Booleans are on/off switches that change part of the policy without writing new rules — for example, allowing httpd to access the network:

View and change a boolean
getsebool -a | grep httpd
sudo setsebool -P httpd_can_network_connect on

The -P flag makes the change persistent (survives reboot). Without -P, the change only lasts until reboot — often the source of confusion when a configuration "doesn't stick".

Troubleshooting Blocked Services

When a service suddenly fails — usually with a mysterious permission denied in the logs — the first step: check whether SELinux is blocking it.

Search for AVC denials in the audit log
sudo ausearch -m avc -ts recent
Put SELinux in permissive mode for diagnosis
sudo setenforce 0
systemctl restart myapp

The correct diagnosis pattern:

  1. Read the denial with ausearch -m avc -ts recent.
  2. Allow temporarily by using permissive mode, not by disabling SELinux.
  3. Verify the service runs in permissive mode — if it does, SELinux is the blocker.
  4. Fix it properly — wrong labels with restorecon, booleans with setsebool, or create a policy module.
  5. Return to enforcing and confirm the service keeps running.

Reading Denials with sealert

For human-friendly interpretation, install setroubleshoot, which provides sealert:

Install and run sealert
sudo dnf5 install -y setroubleshoot-server
sudo sealert -a /var/log/audit/audit.log

sealert -a analyzes the entire audit log and gives step-by-step recommendations — including the exact restorecon or setsebool commands to fix the problem.

Check the latest denial summaries
sudo aureport -a --summary

aureport -a --summary summarizes all audit events — a quick way to see recurring denial patterns.

Common Pitfalls

  1. Disabling SELinux because of a denial. The biggest mistake. A denial is data to diagnose, not a reason to give up.
  2. Relying on setenforce 0 as a permanent solution. It's only temporary and is lost at reboot — fix the root cause.
  3. Forgetting -P in setsebool. Without -P, boolean changes are lost at reboot.
  4. Copying files between directories without restorecon. Labels carry over — always restore labels at the new location.
  5. Ignoring ausearch. Every denial is recorded; their patterns are the best diagnostic clues.

Conclusion

In this episode 13 you've mastered SELinux and MAC: the fundamental MAC vs DAC difference, the three enforcing, permissive, and disabled modes, security context structure, label fixing with restorecon and semanage fcontext, boolean configuration, and the denial troubleshooting pattern with ausearch and sealert.

Key takeaways:

  • MAC restricts even root; decisions are label-based, not user-based.
  • Modes: Enforcing (default), Permissive (log only), Disabled (don't).
  • Context format: user:role:type:sensitivity — manage the type.
  • restorecon fixes labels; semanage fcontext for custom locations.
  • Booleans change policy behavior without editing rules — remember -P for persistence.
  • Troubleshooting: read the denial → temporary permissive → fix → back to enforcing.

With SELinux under control, you're ready to secure remote access. In the next episode, Episode 14, we'll cover SSH Hardening & Remote Access — modern sshd configuration with ed25519 keys, disabling passwords and root, Match for conditional rules, tunneling, and hardening with Fail2ban and AllowUsers. See you there!

Learning AlmaLinux - SELinux & Mandatory Access Control | Learning AlmaLinux