Understanding SELinux and AppArmor Security Modules

Understanding SELinux and AppArmor Security Modules

Short introduction

Mandatory Access Control (MAC) systems like SELinux and AppArmor add a powerful layer of protection beyond traditional Unix user/group permissions. This article gives practical, beginner-friendly explanations of what they do, how they differ, and common commands and workflows for managing and troubleshooting each system.

What is MAC, and how do SELinux and AppArmor differ?

Both SELinux (Security-Enhanced Linux) and AppArmor implement Mandatory Access Control: security policies that limit what processes can do regardless of the user identity. The two projects take different approaches:

  • SELinux uses label-based controls: every file, process, and resource gets a security context (label), and policies define allowed interactions between contexts.
  • AppArmor uses path-based profiles: policies are attached to program binaries (by path) describing allowed file access, capabilities, and networking.

This makes SELinux more fine-grained and flexible for complex environments, while AppArmor is often easier to write and adopt for single-application restrictions.

Example: view basic status for each

# SELinux status (Red Hat/CentOS/Fedora):
$ getenforce
Enforcing

$ sestatus
SELinux status:                 enabled
SELinuxfs mount:                /selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
...

# AppArmor status (Ubuntu/Debian):
$ sudo aa-status
apparmor module is loaded.
16 profiles are loaded.
12 profiles are in enforce mode.
3 profiles are in complain mode.
... 

Note: commands vary slightly by distribution; use the package manager to confirm installation if these fail.

SELinux basics: labels, modes, and common commands

SELinux enforces policies by comparing labels (user:role:type:level) on processes and objects. Common troubleshooting starts with checking modes and reading audit logs.

Key SELinux modes:

  • Enforcing: policy violations are blocked.
  • Permissive: violations are logged but allowed.
  • Disabled: SELinux is off.

Check and change mode:

# Check current mode
$ getenforce
Permissive

# Temporarily set enforcing (until reboot)
$ sudo setenforce 1

# Make permanent (edit /etc/selinux/config)
$ sudo sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config

List loaded modules and policies:

# Show loaded SELinux modules
$ sudo semodule -l
100 local
400 allow_ssh
...

# Show contexts of a file
$ ls -Z /var/www/html/index.html
-rw-r--r--. root root unconfined_u:object_r:httpd_sys_content_t:s0 /var/www/html/index.html

If a service is denied access, check the audit log and generate a local allow rule:

# Search audit logs for AVC denials
$ sudo ausearch -m AVC,USER_AVC -ts recent-time

# Convert denial to allow rule (careful; review before installing)
$ sudo ausearch -m AVC -ts today | audit2allow -M myapp
$ sudo semodule -i myapp.pp

Important: audit2allow helps test fixes but you should review generated rules to avoid weakening policy.

AppArmor basics: profiles, modes, and typical workflows

AppArmor profiles are usually found under /etc/apparmor.d/ and can be in enforce or complain mode. Complain mode logs violations but doesn’t block them — good for developing profiles.

Check and manage AppArmor:

# Show status and loaded profiles
$ sudo aa-status

# Put a profile into complain (learning) mode
$ sudo aa-complain /usr/sbin/nginx

# Put it back into enforce mode
$ sudo aa-enforce /usr/sbin/nginx

Create or adjust profiles:

  • Use aa-genprof to generate a profile by exercising application behavior.
  • Use aa-logprof to interactively convert logged denies into profile rules.

Example workflow:

# Generate profile template while running a service
$ sudo aa-genprof /usr/sbin/myapp

# After running the app and creating log entries, update profile
$ sudo aa-logprof
Parsing AppArmor message log...
Suggesting changes for profile: /usr/sbin/myapp
Accept change? (y/n) y

For quick testing, you can load an unconfined profile or remove a profile (not recommended for production):

# Disable a profile (unloads it)
$ sudo aa-disable /etc/apparmor.d/usr.sbin.myapp

Managing policies and troubleshooting techniques

Both systems rely heavily on logs when debugging denials. Learn to read audit/audit.log (SELinux) and kern.log/syslog (AppArmor). A methodical approach helps:

  1. Reproduce the denial (run the failing action).
  2. Find the corresponding log lines.
  3. Interpret the message (which process, which file, which rule).
  4. Decide: change file labels (SELinux), alter profile (AppArmor), or create allowed rules.

SELinux example: a web server cannot write uploads:

# Reproduce failure, then search deny
$ sudo ausearch -m AVC -ts recent | tail -n 20
----
type=AVC msg=audit(1600000000.000:123): avc:  denied  { write } for  pid=1234 comm="httpd" name="uploads" dev="sda1" ino=5678 scontext=system_u:system_r:httpd_t:s0 tcontext=unconfined_u:object_r:user_home_t:s0 tclass=file

# Fix by restoring correct context or setting a permissive rule
$ sudo chcon -t httpd_sys_rw_content_t /var/www/html/uploads -R
# Or make persistent:
$ sudo semanage fcontext -a -t httpd_sys_rw_content_t "/var/www/html/uploads(/.*)?"
$ sudo restorecon -Rv /var/www/html/uploads

AppArmor example: a program denied network access:

# Check logs for AppArmor messages (journalctl or syslog)
$ sudo journalctl -k | grep apparmor | tail -n 20

# Edit profile to allow network access and reload
$ sudo vim /etc/apparmor.d/usr.bin.myapp
# add: network inet stream,
$ sudo apparmor_parser -r /etc/apparmor.d/usr.bin.myapp

When troubleshooting, use the following checklist:

  • Is the module enabled? (getenforce / aa-status)
  • Is the service running under the expected context/profile?
  • Are file contexts correct (SELinux)?
  • Does the profile allow needed capabilities/networks (AppArmor)?
  • Did you reload or install the changed policy?

Commands table

Command System Purpose / Notes
getenforce SELinux Show SELinux mode (Enforcing/Permissive/Disabled)
sestatus SELinux Detailed SELinux status and policy info
semodule -l SELinux List installed SELinux modules
semanage fcontext SELinux Manage file context rules (add, delete)
restorecon SELinux Apply file contexts from semanage to files
ausearch / audit2allow SELinux Search AVC logs and generate allow rules
aa-status AppArmor Show AppArmor status and loaded profiles
aa-complain / aa-enforce AppArmor Switch profile between complain and enforce modes
aa-genprof / aa-logprof AppArmor Generate and refine profiles interactively
apparmor_parser AppArmor Load or reload profiles from /etc/apparmor.d
journalctl / /var/log/audit/audit.log Both Inspect kernel/AppArmor/SELinux logs

Common Pitfalls

  • Thinking Permissive = safe to ignore: Running SELinux in permissive mode hides denials and can mask issues you should fix before switching to enforcing.
  • Changing permissions instead of contexts: For SELinux, adjusting Unix permissions (chmod/chown) often won’t fix denials; you need to set the correct SELinux context (chcon/semanage + restorecon).
  • Over-permissive fixes: Using audit2allow blindly or adding broad allow rules in AppArmor can accidentally weaken security; always review generated rules and prefer the minimum privilege.

Next Steps

  • Practice in a safe environment: enable permissive mode, reproduce denials, and convert them to controlled policy changes.
  • Read real logs: regularly inspect /var/log/audit/audit.log (SELinux) or journalctl/kern.log (AppArmor) to learn how denials are reported.
  • Start small: create or modify a single AppArmor profile or one SELinux fcontext rule for a service, then tighten controls incrementally.

If you want, I can provide a step-by-step lab exercise for either SELinux or AppArmor tailored to your Linux distribution.

👉 Explore more IT books and guides at dargslan.com.