How to Use Ubuntu apparmor to Enforce Mandatory Access Control Profiles

The Failure of Discretionary Access

In standard Linux security, permissions are governed by Discretionary Access Control (DAC)—the familiar rwxr-xr-x system (read, write, execute). If a user (like www-data) has the correct permissions to read a file (like /etc/passwd), the Linux kernel allows it. The security of the system relies entirely on the administrator carefully managing CHMOD and CHOWN attributes across millions of files.

This architecture is highly vulnerable to zero-day application exploits. Suppose you run a perfectly configured Apache web server. A hacker discovers a zero-day vulnerability in Apache that allows them to execute arbitrary bash commands. Because the Apache process (running as www-data) has native permission to read /etc/passwd, the hacker can instantly exfiltrate the user list. DAC cannot stop this, because DAC only cares about the user, not the application.

To mathematically neutralize application-level exploits, Ubuntu engineers deploy AppArmor, a Mandatory Access Control (MAC) system. AppArmor completely overrides standard Linux permissions. It binds a cryptographic “Profile” directly to a specific binary executable (like /usr/sbin/apache2). Even if the www-data user has full read/write access to the entire hard drive, if the AppArmor profile explicitly dictates that the Apache binary is only allowed to read files in /var/www/html, the kernel will violently block Apache from reading /etc/passwd, rendering the zero-day exploit mathematically useless.

Step 1: Verifying the AppArmor Subsystem

AppArmor is deeply integrated into the Ubuntu kernel and is enabled by default, but you must ensure it is actively enforcing its profiles.

Check the global status using the AppArmor status utility:

sudo aa-status

The output will list the number of profiles currently loaded into the kernel. Crucially, it separates them into two modes:

  1. Enforce Mode: If a binary violates the profile, the kernel blocks the action and logs it.
  2. Complain Mode: If a binary violates the profile, the kernel allows the action, but logs the violation. (This is strictly used for testing and profiling).

Step 2: Installing the Profiling Utilities

While Ubuntu comes with AppArmor, it does not install the advanced administrative tools required to build custom profiles from scratch.

Install the apparmor-utils package:

sudo apt update
sudo apt install apparmor-utils -y

Step 3: Building a Profile via Machine Learning (aa-genprof)

Writing an AppArmor profile manually is incredibly difficult because modern applications make thousands of complex system calls to hidden libraries. Instead of guessing, you use aa-genprof (Generate Profile) to mathematically monitor the application and build the profile automatically.

Suppose you have a custom, highly vulnerable Python web scraper located at /opt/scraper/scraper.py.

Launch the generator targeting the specific executable:

sudo aa-genprof /opt/scraper/scraper.py

The terminal will pause and instruct you to run the application in another window.

Open a second terminal, execute your Python script, and perform every single action it is designed to do (e.g., download a file, write to a log). The kernel is secretly watching the application, recording every single file path and network socket it attempts to access.

Once the application finishes, return to the first terminal and press S to scan the system log. AppArmor will prompt you interactively: “The script attempted to read /etc/ssl/certs. Allow or Deny?” You press Allow. “The script attempted to execute /bin/bash. Allow or Deny?” You press Deny.

When you finish, AppArmor compiles these decisions into a strict profile file located in /etc/apparmor.d/.

Step 4: Putting the Profile into Enforce Mode

The moment aa-genprof finishes, it places the new profile into Enforce mode by default.

If you open the generated profile (sudo nano /etc/apparmor.d/opt.scraper.scraper.py), you will see the mathematical boundaries you just created:

#include <tunables/global>
/opt/scraper/scraper.py {
  #include <abstractions/base>
  /opt/scraper/logs/* rw,
  /etc/ssl/certs/ r,
  deny /bin/bash x,
}

If a hacker manages to compromise the Python script and tries to force it to run a bash shell, the Linux kernel intercepts the execve() system call, compares it to the AppArmor profile, sees the deny rule, and instantly kills the operation, throwing an apparmor="DENIED" error into /var/log/kern.log.

Step 5: Troubleshooting with Complain Mode (aa-complain)

If you apply a profile to a complex application like MySQL, and MySQL suddenly fails to boot, the AppArmor profile is too restrictive. Finding the exact missing permission can be infuriating if the application keeps crashing.

You must shift the profile from Enforce mode into Complain mode. This allows the application to run perfectly, but forces the kernel to generate a log entry for every action that would have been blocked.

sudo aa-complain /usr/sbin/mysqld

Restart MySQL. Let it run for a few minutes. Then, you use the aa-logprof utility to parse the logs.

sudo aa-logprof

This utility behaves exactly like the generator. It reads the complain logs and interactively asks you to permanently add the missing permissions to the profile.

Once the profile is perfectly tuned and no more complain logs are generated, you lock the application back down into strict Enforce mode:

sudo aa-enforce /usr/sbin/mysqld

Conclusion

Relying exclusively on standard Discretionary Access Control (DAC) permissions assumes that application code will never be compromised. By deploying the AppArmor Mandatory Access Control system, Ubuntu engineers decouple security from user accounts and bind it directly to the executable binary. The ability to mathematically trace application behavior via aa-genprof and surgically restrict file, network, and execution access ensures that even if a zero-day exploit completely hijacks a network daemon, the blast radius is contained within an impenetrable kernel-level sandbox.

RELATED POSTS

  • How to Use Ubuntu ss Command to Analyze Active Network Socket Statistics
  • How to Configure High Availability with Keepalived and HAProxy on Ubuntu
  • How to Use Ubuntu iproute2 to Configure Advanced Policy-Based Routing
  • How to Use and Configure Netplan for Advanced Network Management in Ubuntu
  • How to Disable the Command History Log for a Specific Session in Linux
  • Get the best tech tips delivered straight to your inbox.

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