How to Configure AppArmor Profiles, Complain Mode, and Security Enforcement on Ubuntu Server

Traditional Linux security relies on Discretionary Access Control (DAC)—the standard user, group, and permissions model (rwxrwxrwx). While DAC regulates file access between standard system users, it presents a catastrophic flaw: if a network-facing daemon (such as Nginx, Apache, or a custom Node.js microservice) running as root or www-data is compromised via a remote buffer overflow or remote code execution (RCE) vulnerability, the attacker inherits all privileges of that user account, potentially traversing the entire filesystem and reading sensitive configuration files.

To neutralize privilege escalation attacks, Ubuntu Server implements Mandatory Access Control (MAC) via AppArmor. Embedded natively within the Linux Security Modules (LSM) kernel framework, AppArmor binds path-based security profiles to specific program binaries. Even if an attacker executes arbitrary shellcode inside a compromised web server process, AppArmor restricts the process strictly to its declared filesystem paths, network sockets, and POSIX capabilities, rendering the exploit harmless.

Architectural Overview: DAC vs. AppArmor MAC Confinement

AppArmor complements the standard Linux security architecture by enforcing confinement at the kernel syscall boundary:

Security Layer Decision Basis Privilege Boundary Failure Vulnerability
Discretionary Access Control (DAC) User ID (UID) & Group ID (GID) Process inherits all rights of the running user. If root or www-data process is compromised, attacker accesses all user files.
AppArmor (MAC) Absolute Binary File Paths & Rulesets Process confined strictly to white-listed paths, capabilities, and sockets. Zero filesystem traversal beyond declared profile rules, even for UID 0 (root).
Complain Mode Audit Monitoring Mode Violations are permitted but logged to /var/log/audit/audit.log. Ideal for baseline training; does not block active attacks.
Enforce Mode Active Confinement Mode Disallowed syscalls return EACCES (Permission Denied) instantly. Production-grade attack neutralization.

Auditing Active Profiles with aa-status

Ubuntu Server enables AppArmor by default. Inspect the active security posture of your server using the aa-status utility.

# Display AppArmor daemon status, loaded profiles, and confined processes
sudo aa-status

The command output details three key metrics:

  • profiles are in enforce mode: Total number of active security barriers blocking unauthorised syscalls.
  • profiles are in complain mode: Profiles currently monitoring and baselining execution.
  • processes are confined but need restart: Active daemons updated on disk that require a process reload to inherit updated profile rules.

Anatomy of an AppArmor Security Profile

AppArmor profiles are stored in /etc/apparmor.d/. File names reflect the binary path with slashes replaced by periods (for instance, /usr/sbin/nginx becomes usr.sbin.nginx).

Review the essential rule declarations within a typical profile:

#include <tunables/global>

/usr/sbin/nginx {
  # Include standard base abstractions (POSIX libraries, DNS resolution)
  #include <abstractions/base>
  #include <abstractions/nameservice>

  # Linux Kernel Capabilities
  capability net_bind_service,
  capability setgid,
  capability setuid,

  # Network Socket Access
  network inet tcp,
  network inet6 tcp,

  # File Access Modes: r (read), w (write), k (file lock), m (memory map)
  /usr/sbin/nginx mr,
  /etc/nginx/** r,
  /var/log/nginx/* w,
  /var/run/nginx.pid rw,
  /var/www/html/** r,

  # Deny critical system binaries explicitly
  deny /bin/sh x,
  deny /bin/bash x,
  deny /etc/shadow r,
}

Authoring a New Profile with aa-genprof and Complain Mode

When deploying a custom internal web service or Python API (e.g. /opt/api/server.py), construct a custom profile using interactive profiling tools.

Step 1: Install AppArmor Utilities

# Install interactive profiling tools and utilities
sudo apt update
sudo apt install -y apparmor-utils apparmor-profiles

Step 2: Initialize Profile in Complain Mode with aa-genprof

# Begin interactive profile generation
sudo aa-genprof /usr/local/bin/custom_service

aa-genprof performs three actions simultaneously:

  1. Creates a basic profile template in /etc/apparmor.d/.
  2. Places the profile immediately into Complain Mode.
  3. Prompts you to exercise the application in a secondary terminal session.

Step 3: Exercise the Application

In a separate terminal, trigger all normal operational workflows of your application: restart the daemon, make API requests, upload test files, and rotate log files. Because the profile is in complain mode, no requests are blocked; every system call is logged to the system audit trail.

Interactive Policy Tuning with aa-logprof and Switching to Enforce

Once the application has been exercised, parse the audit logs to generate permanent white-list rules.

Step 1: Parse Audit Logs

Return to the terminal running aa-genprof and press S (Scan). Alternatively, execute:

# Parse audit logs and suggest profile updates interactively
sudo aa-logprof

aa-logprof reviews each logged event, presenting an interactive prompt:

Reading log entries from /var/log/audit/audit.log...
Profile:    /usr/local/bin/custom_service
Path:       /etc/custom_service/config.yaml
Mode:       r
Severity:   3

[(A)llow] / (D)eny / (I)gnore / (G)lob / (Q)uit

Press A to allow expected file reads, or D to deny unauthorized file access. Repeat for each prompt until the configuration baseline is established.

Step 2: Enforce the Hardened Profile

Once baseline tuning is complete, elevate the profile from Complain mode to Enforce mode:

# Put the profile into strict enforcement mode
sudo aa-enforce /etc/apparmor.d/usr.local.bin.custom_service

# Reload AppArmor profiles in the kernel
sudo systemctl reload apparmor

Verify that your daemon now appears under “profiles are in enforce mode” by running sudo aa-status.

Troubleshooting AppArmor Denials and Audit Log Parsing

Consult this diagnostic reference table to debug false-positive permission blocks and profile syntax errors:

Issue Underlying Root Cause Remediation Procedure
Application throws Permission Denied (EACCES) despite file permissions set to 777. AppArmor enforce mode is blocking file access because the path is not declared in the profile. Inspect audit logs: sudo dmesg | grep -i apparmor or check /var/log/audit/audit.log for apparmor="DENIED" entries. Add missing path via sudo aa-logprof.
AppArmor parser error: syntax error, unexpected TOK_ID. Missing trailing comma or invalid capability token in /etc/apparmor.d/* profile file. Verify syntax using sudo apparmor_parser -d /etc/apparmor.d/target_profile. Ensure every path or capability rule ends with a comma (,).
Emergency rollback: Service crashed and must be unblocked immediately in production. The newly applied enforce profile blocked a critical production workflow. Revert profile immediately to complain mode: sudo aa-complain /etc/apparmor.d/profile_name. The service will resume without security blocks.
Profile modifications do not take effect after saving the file. Profile was edited on disk but has not been reloaded into the active kernel LSM memory. Reload the profile manually: sudo apparmor_parser -r /etc/apparmor.d/profile_name or reload the systemd service via sudo systemctl reload apparmor.

Configuring AppArmor profiles, leveraging complain mode for iterative baselining, and enforcing strict kernel confinement transforms Ubuntu Server into a hardened defense-in-depth fortress, containing software vulnerabilities before they compromise the operating system.

Get the best tech tips delivered straight to your inbox.

Join thousands of readers mastering Apple, Google, Microsoft, and Linux.