AppArmor is a Linux Security Module (LSM) that restricts what a program can do — which files it can read/write/execute, which network access it has, which capabilities it can use — by attaching a per-program profile to its binary path, rather than to a user or file label as SELinux does. It ships enabled by default on Ubuntu/Debian-family distributions; RHEL-family distributions use SELinux instead (the two are mutually exclusive on one kernel).
Check status¶
sudo aa-status # loaded profiles and their mode; overall summary
sudo apparmor_status # same, older name
cat /sys/module/apparmor/parameters/enabled # Y if the LSM itself is active
Profile modes¶
| Mode | Behaviour |
|---|---|
enforce |
violations are blocked and logged |
complain (a.k.a. audit) |
violations are logged only, not blocked — used while developing/tuning a profile |
unconfined |
no profile loaded; program runs unrestricted |
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx # switch a profile to enforce
sudo aa-complain /etc/apparmor.d/usr.sbin.nginx # switch to complain (learning) mode
sudo aa-disable /etc/apparmor.d/usr.sbin.nginx # unload it entirely
Profiles live in /etc/apparmor.d/¶
Profile files are named after the binary's path with slashes turned into dots, e.g. /usr/sbin/nginx → /etc/apparmor.d/usr.sbin.nginx.
#include <tunables/global>
/usr/sbin/nginx {
#include <abstractions/base>
#include <abstractions/nameservice>
capability net_bind_service,
capability setuid,
capability setgid,
/etc/nginx/** r,
/var/log/nginx/* w,
/var/www/** r,
/run/nginx.pid rw,
network inet stream,
network inet6 stream,
deny /home/** rwx,
deny /root/** rwx,
}
r/w/x are read/write/execute; ix inherits the current profile for an exec'd child; Px/Cx transition the child to another/child profile. deny rules are evaluated after allow rules and always win.
Reload after editing:
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.nginx
sudo systemctl reload apparmor # reload everything
Generating a profile from observed behaviour¶
sudo aa-genprof /usr/local/bin/myapp
Run the program through its normal workflows in another terminal while aa-genprof watches; it prompts you to allow, deny, or glob each access it sees, then writes the profile.
sudo aa-logprof # after a profile has been running in complain mode for a while,
# walks you through the logged violations to turn them into rules
Investigating denials¶
sudo journalctl -k | grep -i apparmor # kernel log, most systems
sudo dmesg | grep -i apparmor
sudo aa-notify -p # desktop notifications for denials (if installed)
A denial log line names the profile, the operation, and the path — usually enough to add one more rule and reload.
Everyday commands¶
sudo aa-unconfined # list processes with open network sockets that have no profile
sudo aa-autodep /usr/local/bin/myapp # generate a minimal starter profile from static analysis
See also SELinux basics referenced from firewalld/RHEL contexts for the RHEL-family equivalent approach, and sudo and fail2ban for complementary access-control layers.