← News
/PLAYBOOK · 2026-08-30

AppArmor Security Hardening in Practice: Linux Application MAC Configuration

AppArmor MAC in practice: aa-genprof profile generation, enforce/complain mode switch, unauthorized-access deny verification, and FAQ. Least privilege for Linux apps.

Scope: This tutorial covers AppArmor mandatory access control (MAC) deployment. Build fine-grained file/network allowlists for Linux app processes such as Nginx, MySQL, and Docker containers so a compromised app cannot access system resources beyond policy. Aimed at Debian/Ubuntu server hardening.

Prerequisites

How It Works

AppArmor is a Linux kernel MAC module. Same LSM (Linux Security Module) family as SELinux, simpler config model: path-based rule sets (Profiles) that define what each app may do. Access outside the rules is denied. Even if the process is compromised (e.g. Nginx RCE), AppArmor keeps it inside least privilege—no read of /etc/shadow, /root, or other sensitive paths. Profiles have complain (log only) and enforce (block) modes for staged rollout.

Procedure

Step 1: Install and Confirm Status

`sudo apt update && sudo apt install -y apparmor apparmor-utils
sudo aa-status`

Confirm AppArmor is loaded and some services already have default policy (e.g. dhclient).

Step 2: Generate an Application Profile

Use `aa-genprof` to interactively generate an Nginx policy (open another terminal and simulate normal traffic to collect behavior):

`sudo aa-genprof nginx`

Follow prompts to Allow/Deny legitimate access. Output: `/etc/apparmor.d/usr.sbin.nginx`. Or write a minimal policy by hand. Example:

`#include <tunables/global>

profile nginx /usr/sbin/nginx {
  #include <abstractions/base>
  #include <abstractions/nameservice>

  /usr/sbin/nginx mr,
  /var/www/** r,
  /var/log/nginx/*.log w,
  /run/nginx.pid rw,
  network inet tcp,
}`

Step 3: Load and Enable Policy

`sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.nginx
sudo aa-enforce /usr/sbin/nginx
sudo aa-status | grep nginx`

Output showing `nginx` in enforce mode means it is active. For temporary allow (debug), switch to complain:

`sudo aa-complain /usr/sbin/nginx`

Step 4: Verify Unauthorized Access Is Denied

Simulate attack: have an Nginx worker read a sensitive system file (e.g. PHP-FPM running `cat /etc/shadow`). AppArmor denies and records in the audit log:

`sudo tail -f /var/log/kern.log | grep -i apparmor`

Configuration Verification

Checks: (1) `aa-status` shows Nginx in enforce; (2) normal traffic (site access, log write, DB connect) unaffected; (3) unauthorized reads of `/etc/shadow`, `/root/.ssh` denied and logs show `apparmor="DENIED"`; (4) policy survives Nginx restart (`systemctl restart nginx` then `aa-status` again).

FAQ

FAQ1: AppArmor prevents the service from starting?

Switch to complain first: `sudo aa-complain /usr/sbin/nginx`. Read DENIED lines in `/var/log/kern.log`, add missing paths/permissions to the Profile, then `apparmor_parser -r` again. To restore service immediately: `sudo aa-disable /usr/sbin/nginx`.

FAQ2: Does AppArmor conflict with Docker/SELinux?

No. Docker ships a default AppArmor policy (docker-default). Ubuntu disables SELinux by default; they do not enforce together. On Ubuntu, AppArmor governs host processes; Docker's own profile governs containers. They do not interfere. Migrating from SELinux: watch policy syntax and kernel config differences.

Summary

AppArmor's path-centric policy model lowers the MAC adoption bar. High ROI for Ubuntu server hardening. Build Profiles for public-facing processes (Nginx, MySQL, PHP-FPM) one by one. Gray-release: complain first, then enforce. Keep policy files in config management. Least privilege as standing control.