Running the script on a Debian 13 server with a PHP web app (nginx + PHP-FPM). After hardening and a reboot, the app returned 500s with no obvious cause. Traced it through nginx logs, PHP-FPM logs, and eventually to AppArmor: the php-fpm profile was in enforce mode and blocking PHP-FPM from reading /etc/appname/ — a path the generic distro profile doesn't allow.
The root cause is aa-enforce /etc/apparmor.d/* in module_apparmor(). It enforces every profile in the directory without exception, including profiles the distro deliberately ships in complain mode (they have flags=(complain) in the file). The distro leaves those in complain mode precisely because they're too generic to enforce safely — they don't account for application-specific paths.
Any PHP app, custom database setup, or service with config outside the standard paths is going to hit this silently.
Suggested approach — no behaviour change needed:
Before enforcing, scan for profiles with flags=(complain) and log them as a visible warning after the enforce step, with the commands to check for denials and revert specific profiles:
sudo journalctl -k | grep apparmor
sudo aa-complain /etc/apparmor.d/<profile-name>
sudo systemctl restart <service>
verify_fortress.sh could also scan the kernel log for apparmor="DENIED" entries and surface the affected profile names with remediation steps.
This keeps full enforcement (no weakening of the posture) but makes it visible so users don't spend an hour debugging a broken app after hardening.
Running the script on a Debian 13 server with a PHP web app (nginx + PHP-FPM). After hardening and a reboot, the app returned 500s with no obvious cause. Traced it through nginx logs, PHP-FPM logs, and eventually to AppArmor: the php-fpm profile was in enforce mode and blocking PHP-FPM from reading
/etc/appname/— a path the generic distro profile doesn't allow.The root cause is
aa-enforce /etc/apparmor.d/*inmodule_apparmor(). It enforces every profile in the directory without exception, including profiles the distro deliberately ships in complain mode (they haveflags=(complain)in the file). The distro leaves those in complain mode precisely because they're too generic to enforce safely — they don't account for application-specific paths.Any PHP app, custom database setup, or service with config outside the standard paths is going to hit this silently.
Suggested approach — no behaviour change needed:
Before enforcing, scan for profiles with
flags=(complain)and log them as a visible warning after the enforce step, with the commands to check for denials and revert specific profiles:verify_fortress.shcould also scan the kernel log forapparmor="DENIED"entries and surface the affected profile names with remediation steps.This keeps full enforcement (no weakening of the posture) but makes it visible so users don't spend an hour debugging a broken app after hardening.