AppArmor

AppArmor profile enforcement, complain mode, aa-genprof for profile generation, and profile management.

AppArmor Status

Check if AppArmor is enabled and loaded
sudo aa-status
Output
apparmor module is loaded.
54 profiles are loaded.
34 profiles are in enforce mode.
20 profiles are in complain mode.
3 processes have profiles defined.
3 processes are in enforce mode.
0 processes are in complain mode.
0 processes are unconfined but have a profile defined.
Quick check — is it running?
sudo aa-enabled
Check kernel support
cat /sys/module/apparmor/parameters/enabled

Profile Modes

Output: Y

AppArmor profiles have two modes:

  • Enforce — blocks violations and logs them

  • Complain — logs violations but doesn’t block (for testing)

Set a profile to enforce mode
sudo aa-enforce /etc/apparmor.d/usr.bin.firefox
Set a profile to complain mode (for debugging)
sudo aa-complain /etc/apparmor.d/usr.bin.firefox
Disable a profile entirely
sudo aa-disable /etc/apparmor.d/usr.bin.firefox
Reload all profiles
sudo systemctl reload apparmor

Profile Locations

Where profiles live
/etc/apparmor.d/                   # Profile definitions
/etc/apparmor.d/abstractions/      # Shared rule fragments (like partials!)
/etc/apparmor.d/tunables/          # Variables (home dir, system paths)
/etc/apparmor.d/local/             # Local overrides (survive package updates)
List all installed profiles
ls /etc/apparmor.d/
Read a specific profile
cat /etc/apparmor.d/usr.bin.firefox

Profile Syntax

AppArmor profiles are human-readable — one of its advantages over SELinux.

Basic profile structure
#include <tunables/global>

/usr/bin/myapp {
  #include <abstractions/base>        # Common system access
  #include <abstractions/nameservice>  # DNS, users, groups

  # File access rules
  /etc/myapp.conf       r,            # Read config
  /var/log/myapp.log    w,            # Write log
  /var/lib/myapp/**     rw,           # Read/write data directory
  /tmp/myapp.*          rw,           # Temp files

  # Network access
  network inet stream,                # TCP
  network inet dgram,                 # UDP

  # Capability
  capability net_bind_service,        # Bind to ports < 1024

  # Deny explicitly
  deny /etc/shadow      r,            # Never read shadow
  deny /root/**         rwx,          # Never touch root's home
}
Permission flags
r   — read
w   — write
a   — append
x   — execute
m   — memory map executable
k   — lock
l   — link

Creating a New Profile

Generate a profile interactively (best method)
sudo aa-genprof /usr/bin/myapp

This starts the app, watches what it accesses, and asks you to allow/deny each access. Creates the profile automatically.

Generate from logs (after running in complain mode)
# 1. Create a basic complain-mode profile
sudo aa-autodep /usr/bin/myapp

# 2. Run the application, exercise all features

# 3. Scan logs and update profile
sudo aa-logprof

# 4. Switch to enforce
sudo aa-enforce /etc/apparmor.d/usr.bin.myapp

Troubleshooting

Check for recent denials
sudo journalctl -k | grep apparmor | grep DENIED | tail -20
More detail with dmesg
dmesg | grep apparmor | grep DENIED
Example denial
apparmor="DENIED" operation="open" profile="/usr/bin/myapp"
  name="/etc/secret.conf" pid=12345 comm="myapp"
  requested_mask="r" denied_mask="r"

This tells you: myapp tried to read /etc/secret.conf and was denied. Add r permission for that path in the profile.

Parse denial into a rule
# The denial says: name="/etc/secret.conf" requested_mask="r"
# Add to profile:  /etc/secret.conf r,
Scan logs and auto-suggest fixes
sudo aa-logprof

Arch Linux Specifics

Install AppArmor on Arch
sudo pacman -S apparmor
Enable at boot (kernel parameter)
# Add to /boot/loader/entries/*.conf (systemd-boot) or GRUB:
apparmor=1 security=apparmor
Enable and start the service
sudo systemctl enable --now apparmor
Install extra profiles
# AUR: apparmor-profiles
yay -S apparmor-profiles

AppArmor vs SELinux

Dimension AppArmor SELinux

Default on

Debian, Ubuntu, SUSE, Arch

RHEL, CentOS, Fedora, Rocky

Model

Path-based (file paths)

Label-based (file contexts)

Profile format

Human-readable text

Complex policy modules (binary)

Learning curve

Lower — profiles are intuitive

Higher — contexts, booleans, types

Granularity

Per-application

System-wide (every file, process, port)

Tools

aa-status, aa-enforce, aa-genprof, aa-logprof

getenforce, semanage, restorecon, audit2allow

Troubleshooting

journalctl -k | grep DENIED

ausearch -m AVC, sealert

RHCSA exam

Not tested

Required — contexts, booleans, ports

Real-World: P16g AppArmor Deployment

The approach
# 1. Install
sudo pacman -S apparmor

# 2. Enable kernel parameter
# In /boot/loader/entries/arch.conf:
#   options ... apparmor=1 security=apparmor

# 3. Enable service
sudo systemctl enable --now apparmor

# 4. Verify
sudo aa-status
Key profiles enforced on P16g
/usr/bin/firefox        — browser isolation
/usr/lib/thunderbird    — email isolation
/usr/bin/evince         — PDF reader isolation
/snap/snapd/*/snapd     — snap confinement

Quick Decision Tree

Q: Which MAC system am I using?
├── RHEL/CentOS/Rocky/Fedora → SELinux
├── Arch/Debian/Ubuntu/SUSE  → AppArmor
└── Both (like you)          → Learn both. SELinux for RHCSA. AppArmor for daily driver.

Q: Something was denied — how do I fix it?
├── SELinux: ausearch -m AVC → restorecon or setsebool or semanage fcontext
└── AppArmor: journalctl -k | grep DENIED → edit profile or aa-logprof

See Also

  • SELinux — alternative MAC framework

  • Permissions — DAC layer that AppArmor supplements