Latest / Linux Server Admin with Fexingo: Sysadmin, Bash, and Server Engineering / How to Harden Your Linux Server with AppArmor Profiles
Transcript
- Lucas: So you're running Nginx on your Linux server, and you think it's secure because you've patched it, you've got a firewall, and you're using HTTPS. But what about the moment a vulnerability lets an attacker execute arbitrary code? That's where mandatory access control comes in, and today I want to talk about AppArmor. Luna: AppArmor feels like the easier cousin of SELinux. I've run into it on Ubuntu servers, but I'll admit I've never fully locked down a profile myself. Lucas: Exactly. And that's the thing — AppArmor ships with Ubuntu and Debian by default, but most admins never enable it beyond a few bundled profiles. There's this assumption that if you're not running SELinux, you're not doing mandatory access control. But AppArmor is a perfectly valid alternative for many workloads, and it's significantly easier to write profiles for. Luna: What's the core difference? I know SELinux labels everything with contexts, and AppArmor uses path-based profiles. Lucas: Right. AppArmor attaches a profile to a program by its executable path, and that profile defines what files the program can read, write, execute, and what network access it has. It's less granular than SELinux in some ways — you can't do fine-grained labeling on individual files — but for confining a web server or a database, it's often more than enough. And the syntax is a lot more readable. Lucas: Let me give you a real example. A few years ago, I had a production web server running Nginx and php fpm. One night, a developer pushed a PHP script that had a file upload function — nothing malicious, but the logic had a bug that allowed a user to specify an arbitrary file path. Someone uploaded a file with a path like '/etc/passwd' as the destination. Luna: Oh no. Did it overwrite the passwd file? Lucas: It tried. But the server had an AppArmor profile for php fpm that I'd set up months earlier. The profile only allowed writes to the upload directory — '/var/www/uploads'. When the script tried to write to '/etc/passwd', the kernel denied it, and the error logged as an AppArmor denial. The upload failed, the bug was caught, and no data was corrupted. Luna: That's a perfect example. And it's exactly the kind of thing a firewall or file permissions wouldn't catch. The web server user might have had write access to that directory, but AppArmor stopped it at the kernel level. Lucas: Exactly. So let's talk about how to actually get started with AppArmor. First, check if it's installed — on Ubuntu, 'sudo aa-status' will show you loaded profiles. By default, you'll see profiles for things like 'tcpdump', 'ping', and maybe some system services. But you'll rarely see a custom profile for your app. Luna: And aa-genprof is the tool for generating profiles, right? Lucas: Yes. You run 'sudo aa-genprof /usr/sbin/nginx' — or whatever the path to your binary is — and then you exercise the application while aa-genprof monitors its behavior. It'll ask you for each permission the program tries to use: 'Allow read of /etc/nginx/nginx.conf?' You answer 'a' for allow, 'd' for deny, and so on. At the end, it writes a profile. Luna: But there's a gotcha. If you generate a profile in complain mode — which aa-genprof does by default — then the app still works, but the profile isn't enforced. You have to manually switch it to enforce mode. Lucas: Right. And that's where a lot of people mess up. They generate a profile, see no errors because it's in complain mode, and think they're protected. But you're not protected until you set the profile to enforce. You can do that with 'sudo aa-enforce /path/to/binary'. And you should also check the logs — the kernel logs AppArmor denials to 'dmesg' or '/var/log/syslog'. Always review those logs before you enforce, or you'll break something in production. Luna: What about profiles for things like MySQL or PostgreSQL? Do I need to generate my own? Lucas: Good news — many common services already have profiles in the 'apparmor-profiles' package. On Ubuntu, you can install that package and then enable the profiles for MySQL, Apache, etc. But those are generic profiles — they might be too restrictive or too permissive for your specific setup. For example, the default MySQL profile might not allow custom data directory paths. You'll need to edit the profile and reload it. Luna: So there's a trade-off. The easier the profile, the more likely it's not tuned to your exact configuration. But writing your own takes time and testing. Lucas: Exactly. And the key is to iterate. Start with complain mode, exercise your application thoroughly, audit the denials, and then move to enforce. And if you're running your app in containers — say, Docker — AppArmor can still apply a profile to the container runtime itself or to the container's processes if you use the '--security-opt apparmor' flag. Lucas: One thing I want to stress: AppArmor is not a replacement for good file permissions or a firewall. It's a defense-in-depth layer. But when it works, it's incredibly effective at confining a compromised process. Luna: I've also seen people worry about the performance overhead. Does AppArmor add noticeable latency? Lucas: In practice, no. The kernel checks are very fast — we're talking microseconds per system call. For most workloads, you won't notice it. The bigger cost is the time you invest in writing and maintaining profiles. But once they're set, they're set. You mostly just need to update them when you change your application's file paths or capabilities. Luna: That reminds me — something that's not directly about AppArmor, but about how we keep this show going. We don't run ads, and that's a choice we've stuck with because we want episodes like this to stay focused and not interrupt your workflow. The way it works is that some listeners chip in a few bucks a month through Buy Me a Coffee. Lucas: Yeah, it's at buy me a coffee dot com slash fexingo. It's literally what lets us keep the servers on and the podcast ad-free. So if you've gotten something useful out of today's deep dive, that's the reason it exists. Luna: And we mean it — no pressure. Just wanted to share that it's there. So back to AppArmor: one thing I've wondered is how it compares to seccomp. Seccomp filters system calls, while AppArmor filters file paths and capabilities. Are they complementary? Lucas: Absolutely. In fact, you can use both. Seccomp restricts which system calls a process can make — think blocking 'clone' or 'execve' — while AppArmor restricts which files it can access and what capabilities it can use. They work at different layers. If you're really paranoid, you'd use AppArmor for file access, seccomp for syscall filtering, and maybe even a tool like 'firejail' for sandboxing. Luna: That's a lot of layers. But for most teams, just getting AppArmor enforced on their public-facing services would be a huge step up. Lucas: It really would. Let me give you a quick checklist. Step one: install apparmor-profiles. Step two: enable profiles for your services. Step three: switch from complain to enforce after testing. Step four: monitor logs for denials, especially after updates. And step five: if you have a custom app, use aa-genprof to create a profile from scratch. Luna: And I'd add: put those profiles in version control. Nothing worse than rebuilding a server and realizing you lost your custom profiles. Lucas: Yes. Store them in your configuration management — Ansible, Puppet, whatever you use. And test profile changes in staging first. I've seen an overly restrictive Nginx profile take down a production site because it blocked access to a new SSL certificate path. Luna: That's a great cautionary tale. So AppArmor is powerful, but it demands respect. You have to treat it like any other security control — test, audit, iterate. Lucas: Exactly. And if you do that, you'll have a server that can survive a lot more than just a firewall can stop. Luna: Alright, next time we should talk about auditing those denials — maybe a tool like 'aa-logprof' to update profiles automatically from logs. Lucas: That's a good idea. Let's tackle that in a future episode. For now, start with one service — maybe your web server — and get an AppArmor profile enforced. It's a small effort for a big security win.