9 views today · 9 views all time
If you manage a Linux server and you have ever had a permission denied error that made absolutely no sense — the file existed, the ownership was correct, you were running as root — there is a reasonable chance AppArmor was the culprit. It certainly was for me.
Standard Linux file permissions control who can access something. A file owned by root with mode 600 can only be read or written by root. That model works well enough for most situations.
The weakness is that it says nothing about which programs can access a file. If a process is running as root, it can — in principle — do anything root is allowed to do. If that process is compromised, or simply misbehaving, the damage it can cause is only limited by root's own permissions. Which on most systems is essentially unlimited.
AppArmor (Application Armor) is a Linux kernel security module that adds a second layer of control. Rather than asking "does this user have permission?", it also asks "does this program have permission?"
Each application can be given a profile — a text file that describes exactly what it is allowed to do. This includes:
Anything not explicitly listed in the profile is denied, regardless of who is running the program. Even root.
I recently configured msmtp on an Ubuntu 24.04 server to relay email through Brevo SMTP. The configuration looked correct. The file /var/log/msmtp.log existed, was owned by root, and had 664 permissions. But every time msmtp ran, it threw:
msmtp: cannot log to /var/log/msmtp.log: cannot open: Permission denied
The kernel audit log told the real story:
apparmor="DENIED" operation="mknod" profile="msmtp" name="/var/log/msmtp.log"
AppArmor was blocking it, not the filesystem. Looking at the msmtp AppArmor profile at /etc/apparmor.d/usr.bin.msmtp, the permitted log paths were:
owner @{HOME}/.msmtp*.log wk,
/var/log/msmtp wk,
The profile permitted /var/log/msmtp with no extension. I had been creating /var/log/msmtp.log. One small difference, completely blocked. The fix was simply to point the log path in /etc/msmtprc to /var/log/msmtp and everything worked immediately.
AppArmor profiles live in /etc/apparmor.d/ and are named after the binary they apply to. The msmtp profile is /etc/apparmor.d/usr.bin.msmtp. You can read any of these as plain text.
To see which profiles are currently loaded and active:
sudo aa-status
To check the audit log for recent AppArmor denials:
sudo dmesg | grep -i apparmor
Profiles run in one of two modes:
You can switch a profile to complain mode temporarily:
sudo aa-complain /usr/bin/msmtp
And back to enforce:
sudo aa-enforce /usr/bin/msmtp
Ubuntu ships AppArmor enabled by default and includes profiles for many common server applications. It is less powerful than SELinux (the alternative used on Red Hat and CentOS systems) but considerably simpler to understand and manage, which is why Ubuntu chose it.
For the most part AppArmor is invisible. Your server runs, your applications behave, and you never think about it. The moment it becomes visible is exactly the situation above — a denial that standard file permission logic cannot explain. When that happens, check AppArmor before spending an hour on ownership and chmod.
| Concept | What it means |
|---|---|
| AppArmor profile | A per-program ruleset defining what it may access |
| Enforce mode | Violations are blocked and logged |
| Complain mode | Violations are logged only — nothing is blocked |
/etc/apparmor.d/ |
Where all profiles are stored |
aa-status |
Shows all loaded profiles and their mode |
dmesg | grep apparmor |
Shows recent denials |
If you manage Ubuntu servers and you have not looked at AppArmor before, it is worth spending twenty minutes reading through a profile or two. Not because you will need to write them often, but because the next time you hit an inexplicable permission denial, you will know exactly where to look.