Securing a Python Service on Ubuntu with AppArmor: A Practical Guide
Enable Ubuntu’s AppArmor, write a profile for a Python script, test it in complain mode, then enforce. Step‑by‑step instructions, trade‑offs, and best practices are covered.
03 Apr 2026, 12:16 UTC

What is AppArmor?
AppArmor is a lightweight mandatory access control (MAC) system that ships with Ubuntu LTS releases. It confines programs to a set of file, network, and capability permissions defined in a profile. Unlike traditional discretionary access control (DAC), AppArmor’s rules are enforced by the kernel, preventing a compromised process from accessing resources it shouldn’t.
Why Use It for Python Services?
Python applications often read configuration files, write logs, and open network sockets. A mis‑configured or vulnerable script could be exploited to read system secrets or modify critical files. AppArmor lets you restrict the script to only the directories it needs, dramatically reducing the attack surface without changing the Python code.
Step‑by‑Step: Create a Profile for a Simple Python Script
Ensure AppArmor is installed and running
sudo apt-get update sudo apt-get install apparmor apparmor-profiles apparmor-utils sudo systemctl enable --now apparmor.serviceVerify the service status:
sudo systemctl status apparmor.serviceWrite the Python script
# /opt/myapp/hello.py #!/usr/bin/env python3 import time print("Hello, world!") time.sleep(60) # keep the process alive for testingMake it executable:
sudo chmod +x /opt/myapp/hello.pyCreate an AppArmor profile
AppArmor profiles are stored in
/etc/apparmor.d. Create a new file that mirrors the binary name:sudo tee /etc/apparmor.d/usr.bin.python3_myapp <<'EOF' # Profile for python3 running /opt/myapp/hello.py # This profile is generated manually for demonstration. # Allow execution of the interpreter @@ /usr/bin/python3 mr, # Allow reading of the script /opt/myapp/hello.py r, # Allow reading of standard library /usr/lib/python3.*/** r, # Allow reading of configuration directory (example) /etc/myapp/** r, # Allow writing to a dedicated log directory /var/log/myapp/ r, /var/log/myapp/** rw, # Allow network access only to localhost on port 0 (no real sockets here) network inet stream, # Deny all other file access deny /**, EOFLoad the profile into the kernel
sudo apparmor_parser -r /etc/apparmor.d/usr.bin.python3_myappCheck that it is loaded:
sudo aa-statusRun the script in complain mode to see what would be denied
sudo aa-complain /usr/bin/python3 sudo /opt/myapp/hello.pyOpen
/var/log/audit/audit.logto review any denied operations. If the script runs without errors, the profile is permissive enough.Switch to enforce mode once satisfied
sudo aa-enforce /usr/bin/python3 sudo /opt/myapp/hello.pyAny future violations will be blocked and logged.
Testing and Fine‑Tuning
Use aa-logprof to generate a profile automatically from audit logs:
sudo aa-logprof
It will ask you to approve or deny each denied operation, building a profile incrementally. After each change, re‑run the script in complain mode to confirm no new denials appear.
Trade‑offs & Limitations
- Over‑restriction can break functionality: If the script needs to create a temporary file in
/tmp, the profile must explicitly allow that path. - Dynamic file creation: Some Python libraries write to
/var/tmpor/usr/local/lib. Static profiles may block these unless you add wildcard allowances. - Maintenance overhead: When you update Python or the application, paths may change, requiring a profile review.
- Performance impact: Minimal; AppArmor adds a few microseconds to system calls, negligible for most workloads.
Next Steps
1. Extend the profile to allow /tmp/** rw if the script writes temporary files.
2. Use aa-complain during development and aa-enforce in production.
3. Enable automatic profile generation for new services with aa-logprof -r.
4. Monitor /var/log/audit/audit.log regularly for unexpected denials.
By following this workflow, you gain a robust, kernel‑level barrier around your Python services, keeping the system safe from privilege escalation while preserving necessary functionality.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.