dotlinux guide

Comparing SELinux and AppArmor: Which is Better for You?

In the landscape of Linux security, Mandatory Access Control (MAC) systems play a critical role in enforcing granular access policies beyond the default Discretionary Access Control (DAC) model. Two of the most widely adopted MAC frameworks are SELinux (Security-Enhanced Linux) and AppArmor (Application Armor). Both aim to restrict process capabilities and mitigate vulnerabilities, but they differ significantly in design, complexity, and use cases. This blog provides a deep dive into SELinux and AppArmor, covering their fundamental concepts, usage methods, common practices, and best practices. By the end, you’ll understand their strengths, weaknesses, and which is better suited for your environment.

Table of Contents

  1. Introduction
  2. Fundamental Concepts
  3. Key Differences: SELinux vs. AppArmor
  4. Usage Methods
  5. Common Practices
  6. Best Practices
  7. Conclusion
  8. References

Fundamental Concepts

What Are Linux Security Modules (LSMs)?

Linux Security Modules (LSMs) are a kernel-level framework that enables the implementation of MAC systems. Unlike DAC, which relies on user/group permissions (e.g., chmod), MAC enforces policies based on system-wide rules, restricting even privileged users (e.g., root) from unauthorized actions. SELinux and AppArmor are the most popular LSM implementations.

SELinux Basics

Developed by the NSA in the late 1990s, SELinux is a robust MAC framework integrated into the Linux kernel. It enforces policies based on type enforcement (TE), role-based access control (RBAC), and multi-level security (MLS).

  • Type Enforcement (TE): The core of SELinux. Every process and file is assigned a “security context” (e.g., httpd_t for Apache processes, httpd_sys_content_t for web files). Rules define which types can access others (e.g., “httpd_t can read httpd_sys_content_t files”).
  • Policy Types: SELinux uses prebuilt policies like targeted (default on most systems, restricts only critical services) or strict (restricts all processes).
  • Complexity: Policies are written in a low-level language (XML/TE rules), making them powerful but difficult to author from scratch.

AppArmor Basics

AppArmor, initially developed by Immunix and later maintained by Novell/Canonical, is a lighter MAC framework focused on path-based access control. It restricts processes to predefined paths and actions (e.g., “Nginx can only read /var/www/html/* and listen on port 80”).

  • Profiles: AppArmor enforces policies via “profiles”—human-readable text files that specify allowed paths, network access, and capabilities for a process (e.g., /etc/apparmor.d/usr.sbin.nginx for Nginx).
  • Simplicity: Profiles use intuitive syntax (e.g., allow /var/www/html/** r; to allow read access to web files), making them easier to write and modify.
  • Learning Mode: AppArmor supports “complain mode,” where it logs violations without blocking them, helping build profiles incrementally.

Key Differences: SELinux vs. AppArmor

To choose between SELinux and AppArmor, it’s critical to understand their architectural and practical differences. The table below summarizes key distinctions:

FeatureSELinuxAppArmor
Access Control ModelType/role-based (abstract labels)Path-based (concrete file paths)
Policy LanguageComplex XML/TE rules (e.g., allow httpd_t httpd_sys_content_t:file read;)Simple, human-readable profiles (e.g., allow /var/www/html/** r;)
Default PlatformsRHEL, CentOS, Fedora, Rocky LinuxUbuntu, Debian, SUSE, openSUSE
Learning CurveSteeper (requires understanding contexts)Gentler (familiar file paths)
GranularityHigh (enforces on users, roles, types)Moderate (focused on processes/paths)
Profile GenerationManual (via audit2allow) or prebuiltAutomated (via aa-genprof in complain mode)

Usage Methods

Installation & Status Checks

Both SELinux and AppArmor are preinstalled on their respective default distributions. Use these commands to verify status:

SELinux

# Check SELinux status (enabled/disabled, enforcing/permissive)
sestatus

# Sample output:
# 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
# Memory protection checking:     actual (secure)
# Max kernel policy version:      33

AppArmor

# Check AppArmor status (loaded profiles, modes)
aa-status

# Sample output:
# apparmor module is loaded.
# 14 profiles are loaded.
# 12 profiles are in enforce mode.
#   /sbin/dhclient
#   /usr/bin/evince
#   /usr/bin/evince-previewer
#   /usr/sbin/nginx
# ...
# 2 profiles are in complain mode.
#   /usr/bin/firefox
# ...

Managing Policies

SELinux Policy Management

SELinux policies are managed with tools like semanage, setsebool, and restorecon:

  • Relabel Files: If a file’s context is incorrect (e.g., after moving files), restore it:

    # Relabel a single file
    restorecon -v /var/www/html/index.html
    
    # Relabel an entire directory
    restorecon -Rv /var/www/html/
  • Modify Booleans: SELinux “booleans” toggle predefined rules (e.g., allowing Apache to serve HTTP over HTTPS):

    # List all booleans
    getsebool -a | grep httpd
    
    # Allow Apache to connect to the network
    setsebool -P httpd_can_network_connect on
  • Add Contexts: Define custom file contexts (e.g., for a new web directory):

    # Add a context for /srv/web (persistent across reboots)
    semanage fcontext -a -t httpd_sys_content_t "/srv/web(/.*)?"
    
    # Apply the new context
    restorecon -Rv /srv/web/

AppArmor Profile Management

AppArmor profiles are stored in /etc/apparmor.d/ and managed with aa-genprof, aa-enforce, and aa-complain:

  • Generate a Profile: Use aa-genprof to create a profile for a process (e.g., Nginx) by monitoring its activity:

    # Generate a profile for Nginx (starts in complain mode)
    aa-genprof nginx
    
    # Follow prompts to allow/deny logged accesses
  • Edit a Profile: Manually refine profiles (e.g., restrict Nginx to port 80 only):

    # Edit Nginx profile
    nano /etc/apparmor.d/usr.sbin.nginx
    
    # Add rule to allow port 80 (TCP)
    network inet tcp port 80,
  • Switch Modes: Toggle between enforce (block violations) and complain (log only):

    # Put Nginx in enforce mode
    aa-enforce /usr.sbin.nginx
    
    # Put Nginx in complain mode (for testing)
    aa-complain /usr.sbin.nginx

Troubleshooting

SELinux Troubleshooting

SELinux denials are logged to /var/log/audit/audit.log. Use audit2allow to analyze them:

# Find recent SELinux denials
grep "AVC" /var/log/audit/audit.log | tail -5

# Generate a policy module to allow denied actions (use cautiously!)
audit2allow -a -M mymodule
semodule -i mymodule.pp  # Load the module

AppArmor Troubleshooting

AppArmor logs to /var/log/syslog or /var/log/audit/audit.log. Use aa-logprof to refine profiles based on logs:

# Analyze logs and update profiles interactively
aa-logprof

Common Practices

SELinux Common Practices

  • Use Targeted Policy: The targeted policy (default) balances security and usability by restricting only critical services (e.g., Apache, SSH). Avoid strict unless you need it.
  • Avoid Permissive Mode: Permissive mode logs violations but doesn’t block them—use it only for debugging, not production.
  • Leverage Prebuilt Policies: Most applications (e.g., Nginx, MySQL) have prebuilt SELinux policies. Avoid writing custom policies unless necessary.

AppArmor Common Practices

  • Start with Complain Mode: Build profiles in complain mode to log violations without blocking processes, then refine rules with aa-logprof.
  • Restrict Network Access: Explicitly define allowed ports in profiles (e.g., network inet tcp port 443 for HTTPS) to limit attack surface.
  • Keep Profiles Minimal: Avoid overly broad rules (e.g., allow /** r;). Restrict paths to only what the process needs.

Best Practices

General Best Practices

  • Least Privilege: Both frameworks enforce “least privilege”—restrict processes to only the resources they need.
  • Test Policies: Always test policy changes in a staging environment before deploying to production.
  • Monitor Logs: Regularly check SELinux/AppArmor logs for violations to identify misconfigurations or attacks.

SELinux-Specific Best Practices

  • Understand Contexts: Use ls -Z (files) and ps -Z (processes) to inspect security contexts. For example:
    ls -Z /var/www/html/  # Show file contexts
    ps -Z | grep nginx    # Show Nginx process context
  • Use semanage for Persistence: Tools like semanage ensure changes survive reboots (unlike chcon, which is temporary).

AppArmor-Specific Best Practices

  • Avoid Wildcards: Overly broad wildcards (e.g., allow /var/** r;) weaken security. Use specific paths (e.g., allow /var/www/html/* r;).
  • Sign Profiles: Sign profiles with apparmor_parser -s to prevent tampering (requires apparmor-utils).

Conclusion

SELinux and AppArmor are both powerful MAC frameworks, but they cater to different needs:

  • Choose SELinux if: You need granular, type-based control (e.g., government, finance, or high-security environments). It excels at enforcing complex rules across users, roles, and resources but requires steeper learning.

  • Choose AppArmor if: You prioritize simplicity and path-based control (e.g., desktop systems, small businesses, or developers). Its human-readable profiles and lower learning curve make it ideal for rapid deployment.

Ultimately, the “better” choice depends on your environment, expertise, and security requirements. Both can significantly harden a Linux system—what matters most is consistent policy management and monitoring.

References