AppArmor Mandatory Access Control
Implement kernel-level access control policies with AppArmor to restrict application privileges
AppArmor is a Mandatory Access Control (MAC) framework that enforces security policies per application. Unlike discretionary access control (DAC), AppArmor allows administrators to define exactly what resources each application can access, regardless of file ownership.
What is AppArmor
AppArmor operates at the Linux Security Module (LSM) level, providing:
- Profile-based security: Individual policies per application
- Path-based rules: File and directory access restrictions
- Capability restrictions: Linux capability enforcement
- Network rules: Per-application network access control
- Audit logging: Detailed enforcement and denial logs
- Easy migration: Complain mode for testing before enforcement
Check AppArmor Status
System Status
# Full status report
sudo aa-status
# Alternative command
sudo systemctl status apparmor
# Check if AppArmor is enabled
cat /sys/module/apparmor/parameters/enabledOutput shows loaded profiles with modes (enforce, complain, disabled).
Install Tools
# AppArmor utilities package
sudo apt install -y apparmor-utils
# Tools included:
# - aa-genprof: Generate profiles interactively
# - aa-complain: Switch profile to complain mode
# - aa-enforce: Switch profile to enforce mode
# - aa-disable: Disable a profile
# - aa-logprof: Process audit logs into profile rulesProfile Modes
| Mode | Behavior | Use Case |
|---|---|---|
| enforce | Deny denied access, log to audit | Production |
| complain | Allow all, log denials to audit | Development/testing |
| disabled | No enforcement | Temporarily disable |
Inspect Existing Profiles
View System Profiles
# List all loaded profiles
sudo aa-status | grep profiles
# View profile directory
ls -la /etc/apparmor.d/
# Example system profiles
ls -la /etc/apparmor.d/ | grep -E 'nginx|mysql|sshd'Read a Profile
# View nginx profile (if installed)
sudo cat /etc/apparmor.d/usr.sbin.nginx
# View Docker default profile
sudo cat /etc/apparmor.d/docker-defaultProfile syntax example:
#include <tunables/global>
profile /usr/sbin/nginx {
#include <abstractions/base>
#include <abstractions/nameservice>
/usr/sbin/nginx mr,
/etc/nginx/** r,
/var/log/nginx/*.log w,
}Create a Custom Profile with aa-genprof
Run aa-genprof on a test system or during low-traffic periods. It interactively monitors application behavior and requires user input.
Generate Profile Interactively
# Generate profile for custom application
sudo aa-genprof /opt/myapp/bin/myapp
# This will:
# 1. Start monitoring the application
# 2. Prompt you to execute application operations
# 3. Ask about each access attempt
# 4. Generate a profile based on responsesDuring execution, perform typical application operations (file access, network connections, etc.).
Review Generated Profile
# View newly created profile
sudo cat /etc/apparmor.d/opt.myapp.bin.myapp
# Switch to complain mode for testing
sudo aa-complain /opt/myapp/bin/myapp
# Monitor denials
sudo tail -f /var/log/audit/audit.log | grep apparmorProfile Syntax Reference
File Rules
# Read access
/etc/config r,
# Write access
/var/log/app.log w,
# Read and write
/tmp/socket rw,
# Execute access
/usr/bin/tool ix, # ix = inherit profile
# Directory access (r includes listing)
/home/user/** r, # Recursive read
# Deny rules (takes precedence)
deny /etc/shadow r,Capability Rules
capability net_admin,
capability setuid,
capability sys_chroot,
capability dac_override,Network Rules
network inet stream, # IPv4 TCP
network inet dgram, # IPv4 UDP
network unix stream, # Unix sockets
network netlink dgram, # NetlinkInclude Statements
# Include abstractions for common access patterns
#include <abstractions/base>
#include <abstractions/nameservice>
#include <abstractions/openssl>
# Include other profiles
#include <abstractions/php5>Enforce a Profile
Switch from Complain to Enforce
# Monitor audit logs first
sudo tail -f /var/log/audit/audit.log | grep "apparmor=" | grep "DENIED"
# Review denials and update profile as needed
sudo aa-logprof
# Switch to enforce when ready
sudo aa-enforce /opt/myapp/bin/myapp
# Verify mode
sudo aa-status | grep myappReload Profile
# Reload after editing profile
sudo apparmor_parser -r /etc/apparmor.d/opt.myapp.bin.myapp
# Or use service
sudo systemctl reload apparmorAppArmor with Docker
Default Docker Profile
Docker applies a default AppArmor profile to containers. View it:
docker info | grep -i apparmor
# View default profile
sudo cat /etc/apparmor.d/docker-defaultRun Container with Custom Profile
Create a custom profile for a specific application:
# Create profile
sudo cat > /etc/apparmor.d/docker-myapp << 'EOF'
#include <tunables/global>
profile docker-myapp flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
/etc/** r,
/proc/** r,
/sys/kernel/mm/** r,
/var/log/app.log w,
/tmp/** rw,
capability setuid,
capability setgid,
capability net_bind_service,
network inet stream,
network inet dgram,
}
EOF
# Load profile
sudo apparmor_parser -r /etc/apparmor.d/docker-myapp
# Run container with custom profile
docker run --security-opt apparmor=docker-myapp myimageContainer Execution Examples
# Use default profile
docker run --security-opt apparmor=docker-default nginx:latest
# Use custom profile
docker run --security-opt apparmor=docker-myapp myapp:latest
# Disable AppArmor (not recommended)
docker run --security-opt apparmor=unconfined ubuntu bashCommon System Profiles
Nginx Profile
# View default nginx profile
sudo cat /etc/apparmor.d/usr.sbin.nginx
# Enable (usually already enforced)
sudo aa-enforce /usr/sbin/nginx
# Test after changes
sudo systemctl reload nginxMySQL/MariaDB Profile
# Check MySQL profile
sudo aa-status | grep mysql
# View profile
sudo cat /etc/apparmor.d/usr.sbin.mysqld
# Reload if modified
sudo systemctl reload mysqlSSH Daemon Profile
# View SSH profile
sudo cat /etc/apparmor.d/usr.sbin.sshd
# Check status
sudo aa-status | grep sshdAudit Log Analysis
Check Denials in journalctl
# View AppArmor denials
sudo journalctl -k | grep apparmor | grep DENIED
# Real-time monitoring
sudo journalctl -f -k | grep apparmor
# Filter by specific profile
sudo journalctl -k | grep "apparmor.*profile=\"/opt/myapp"Detailed Audit Output
# View full audit logs
sudo cat /var/log/audit/audit.log | grep apparmor
# Parse with ausearch (if auditd installed)
sudo ausearch -m apparmor -ts todayProcess Audit Logs with aa-logprof
# Interactive tool to generate rules from audit logs
sudo aa-logprof
# This will:
# 1. Read audit logs
# 2. Ask about each DENIED event
# 3. Add rules to profile or create new ones
# 4. Allow you to test changes immediatelyCommon Issues and Solutions
Application Denied Access
Error in audit log: DENIED entry for file or capability
Solution:
# 1. Switch profile to complain mode
sudo aa-complain /path/to/profile
# 2. Run application normally
# Application complains about denials
# 3. Review audit logs
sudo journalctl -k | grep DENIED | tail -20
# 4. Update profile with new rules
sudo aa-logprof
# 5. Enforce when ready
sudo aa-enforce /path/to/profileProfile Parsing Errors
# Check syntax
sudo apparmor_parser -T -f /etc/apparmor.d/profile-name
# Fix errors and reload
sudo apparmor_parser -r /etc/apparmor.d/profile-nameService Won't Start
# Disable profile temporarily
sudo aa-disable /path/to/profile
# Start service to identify issue
sudo systemctl start service
# Check what was denied
sudo journalctl -k | grep DENIED
# Create proper rules
sudo aa-logprof
# Re-enable
sudo aa-enforce /path/to/profileAppArmor vs SELinux
AppArmor is preferred on Debian/Ubuntu systems. SELinux is the standard on RHEL/CentOS. Both provide MAC but use different approaches: AppArmor uses path-based rules, SELinux uses type enforcement and contexts.
| Feature | AppArmor | SELinux |
|---|---|---|
| Distribution | Ubuntu, Debian | RHEL, CentOS, Fedora |
| Policy Type | Path-based | Type-based (context) |
| Complexity | Lower | Higher |
| Learning Curve | Easier | Steeper |
| Granularity | Good | Very fine-grained |
| Default Mode | Complain-first | Audit-then-enforce |
Best Practices
- Test in complain mode first: Always use
-aoraa-complainbefore enforcing - Use abstractions: Reference
/etc/apparmor.d/abstractions/for common patterns - Monitor logs regularly: Keep audit logs reviewed for denials
- Version control profiles: Store in git with changes documented
- Gradual rollout: Deploy enforced profiles gradually across infrastructure
- Principle of least privilege: Grant only necessary file/capability access
- Use includes: Leverage
#includefor DRY profile management