Security

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/enabled

Output 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 rules

Profile Modes

ModeBehaviorUse Case
enforceDeny denied access, log to auditProduction
complainAllow all, log denials to auditDevelopment/testing
disabledNo enforcementTemporarily 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-default

Profile 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 responses

During 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 apparmor

Profile 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,        # Netlink

Include 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 myapp

Reload Profile

# Reload after editing profile
sudo apparmor_parser -r /etc/apparmor.d/opt.myapp.bin.myapp

# Or use service
sudo systemctl reload apparmor

AppArmor 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-default

Run 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 myimage

Container 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 bash

Common 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 nginx

MySQL/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 mysql

SSH Daemon Profile

# View SSH profile
sudo cat /etc/apparmor.d/usr.sbin.sshd

# Check status
sudo aa-status | grep sshd

Audit 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 today

Process 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 immediately

Common 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/profile

Profile 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-name

Service 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/profile

AppArmor 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.

FeatureAppArmorSELinux
DistributionUbuntu, DebianRHEL, CentOS, Fedora
Policy TypePath-basedType-based (context)
ComplexityLowerHigher
Learning CurveEasierSteeper
GranularityGoodVery fine-grained
Default ModeComplain-firstAudit-then-enforce

Best Practices

  • Test in complain mode first: Always use -a or aa-complain before 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 #include for DRY profile management

On this page