AppArmor (Application Armor) เป็นระบบ Mandatory Access Control (MAC) ที่ใช้ Profile-based Security ควบคุมว่า Process แต่ละตัวสามารถเข้าถึงไฟล์, Network, และ Capability ใดได้บ้าง แตกต่างจาก SELinux ที่ใช้ Security Context บน Inode, AppArmor ใช้ Path-based โดยอ้างอิงชื่อ Path ของไฟล์ ทำให้เขียนและอ่าน Policy ง่ายกว่ามาก
บทความนี้อธิบายการติดตั้งและตั้งค่า AppArmor บน Ubuntu/Debian ตั้งแต่การตรวจสอบ Status, การใช้ Mode (Enforce/Complain/Disabled), การสร้างและแก้ไข Profile, การ Debug ด้วย aa-logprof, จนถึงการเขียน Custom Profile สำหรับ Application จริง
ตรวจสอบ AppArmor Status
# ตรวจสอบว่า AppArmor ทำงานอยู่หรือไม่
sudo apparmor_status
# หรือใช้ aa-status (เหมือนกัน)
sudo aa-status
# ตัวอย่าง Output:
# apparmor module is loaded.
# 35 profiles are loaded.
# 35 profiles are in enforce mode.
# /usr/bin/evince
# /usr/sbin/mysqld
# ...
# 0 profiles are in complain mode.
# 0 processes have profiles defined.
# ตรวจสอบว่า Module โหลดอยู่ใน Kernel
cat /sys/module/apparmor/parameters/enabled
# Y = เปิดใช้งาน
# ดู AppArmor ใน systemd
systemctl status apparmor
# ติดตั้ง AppArmor บน Ubuntu/Debian (มักติดตั้งมาแล้ว)
sudo apt install apparmor apparmor-utils apparmor-profiles apparmor-profiles-extra
# เปิดใช้ AppArmor ถ้าถูก Disable
sudo systemctl enable --now apparmor
# ตรวจสอบว่า Kernel Boot Parameter มี apparmor=1
grep -i apparmor /proc/cmdline
# BOOT_IMAGE=... apparmor=1 security=apparmor
AppArmor Modes — Enforce, Complain, Disabled
AppArmor มี 3 Mode สำหรับแต่ละ Profile โดยสามารถตั้งค่าแยกกันได้ในแต่ละ Application
# ดู Mode ของทุก Profile
sudo aa-status | grep -A 100 "profiles are in enforce mode"
# เปลี่ยน Profile เป็น Complain Mode (Log เท่านั้น ไม่ Block)
sudo aa-complain /usr/sbin/nginx
sudo aa-complain /etc/apparmor.d/usr.sbin.nginx # ระบุ Profile File ได้เช่นกัน
# เปลี่ยน Profile เป็น Enforce Mode (Block จริง)
sudo aa-enforce /usr/sbin/nginx
# Disable Profile (ปิดทั้งหมด ไม่ apply)
sudo aa-disable /usr/sbin/nginx
# ดู Mode ของ Profile เฉพาะตัว
sudo aa-status | grep nginx
# โหลด Profile ใหม่หลังแก้ไข
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.nginx
# โหลด Profile ใหม่ทั้งหมด
sudo systemctl reload apparmor
# โหลด Profile จากไฟล์เฉพาะ
sudo apparmor_parser -a /etc/apparmor.d/usr.sbin.nginx
# ลบ Profile ออกจาก Kernel (ไม่ลบไฟล์)
sudo apparmor_parser -R /etc/apparmor.d/usr.sbin.nginx
โครงสร้าง AppArmor Profile
Profile อยู่ที่ /etc/apparmor.d/ ชื่อไฟล์ใช้ Path ของ Binary โดยแทน / ด้วย . เช่น /usr/sbin/nginx → usr.sbin.nginx
# โครงสร้าง Profile พื้นฐาน
# /etc/apparmor.d/usr.sbin.nginx
#include <tunables/global>
/usr/sbin/nginx {
#include <abstractions/base>
#include <abstractions/nameservice>
# Capability
capability net_bind_service,
capability setuid,
capability setgid,
# File Access
/usr/sbin/nginx mr, # mr = map + read (binary)
/etc/nginx/** r, # r = read (config files)
/var/log/nginx/ rw,
/var/log/nginx/** rw, # rw = read + write (log)
/var/www/html/ r,
/var/www/html/** r,
/run/nginx.pid rw,
/tmp/ rw,
/tmp/** rw,
# Network
network inet tcp,
network inet6 tcp,
# Deny explicit
deny /etc/shadow r,
deny /root/** rw,
}
# Permission Modes ใน AppArmor Profile
# r = read
# w = write
# a = append
# x = execute
# m = mmap (executable mapping)
# k = lock
# l = link
# ix = inherit execute (ใช้ Profile ของ Parent)
# Px = execute ด้วย Profile ของ Binary นั้น (must exist)
# Ux = execute โดยไม่มี Profile (unconfined)
# cx = execute ด้วย Child Profile ที่ระบุใน Profile
# ตัวอย่างการใช้ Execute Modes
/bin/bash ix, # bash inherit ใช้ Profile ของ nginx
/usr/bin/perl Px, # perl ใช้ Profile ของ perl เอง
/usr/bin/python3 Ux, # python ทำงานแบบ unconfined (ไม่ปลอดภัย ใช้เฉพาะจำเป็น)
สร้าง Profile อัตโนมัติด้วย aa-genprof
aa-genprof เป็นเครื่องมือที่ช่วยสร้าง Profile แบบ Interactive โดยสังเกต Behavior ของ Program แล้วสร้าง Rule ให้อัตโนมัติ
# สร้าง Profile สำหรับ Program ใหม่ (ต้องรันเป็น root)
sudo aa-genprof /path/to/program
# aa-genprof จะ:
# 1. สร้าง Profile ว่างและตั้งเป็น Complain Mode
# 2. รอให้คุณรัน Program ในอีก Terminal
# 3. กด S เพื่อ Scan Log และแสดง Rule ที่แนะนำ
# 4. กด F เพื่อ Finish และ Save Profile
# ขั้นตอนปฏิบัติ:
# Terminal 1: sudo aa-genprof /usr/local/bin/myapp
# Terminal 2: /usr/local/bin/myapp --test-run
# ในระหว่าง aa-genprof จะถามว่าแต่ละ Access ให้ทำอะไร:
# (A)llow = อนุญาตและเพิ่มใน Profile
# (D)eny = ปฏิเสธและเพิ่ม deny rule
# (I)gnore = ข้ามไป
# (G)lob = ใช้ Glob Pattern แทน Path เฉพาะ
# (N)ew = พิมพ์ Path ใหม่เอง
Debug และปรับแต่ง Profile ด้วย aa-logprof
เมื่อ Application ทำงานในโหมด Complain, AppArmor จะบันทึก Denied Access ไปยัง Log โดยไม่ Block ใช้ aa-logprof อ่าน Log และเพิ่ม Rule เข้า Profile
# ดู AppArmor Log ใน syslog/audit
sudo grep "apparmor" /var/log/syslog | tail -20
sudo grep "apparmor" /var/log/kern.log | tail -20
# ตัวอย่าง Log Entry:
# kernel: audit: type=1400 audit(1234567890.123:456): apparmor="ALLOWED"
# operation="open" profile="/usr/sbin/nginx" name="/etc/ssl/private/server.key"
# pid=1234 comm="nginx" requested_mask="r" denied_mask="r" fsuid=33 ouid=0
# หรือดูผ่าน journalctl
sudo journalctl -k | grep apparmor | tail -20
# รัน aa-logprof เพื่ออ่าน Log และแนะนำ Rule
sudo aa-logprof
# aa-logprof อ่าน /var/log/syslog (และ /var/log/audit/audit.log ถ้ามี)
# แสดง Access ที่ถูก Log และถามว่าจะ Allow หรือ Deny
# ระบุ Log File เฉพาะ
sudo aa-logprof -f /var/log/syslog
# ตัวอย่าง Output ของ aa-logprof และการตอบ:
# Profile: /usr/sbin/nginx
# Path: /etc/ssl/private/server.key
# Old Mode: (none)
# New Mode: r
#
# Severit: 2
#
# (A)llow / (D)eny / (I)gnore / (G)lob / ...
# => กด A เพื่ออนุญาต
# หลังจากตอบทุก Entry แล้ว:
# Save Changes? [Y/n]
# => กด Y เพื่อบันทึก Profile
# โหลด Profile ที่แก้ไขแล้ว
sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.nginx
ตัวอย่าง Profile จริง — Nginx Web Server
# /etc/apparmor.d/usr.sbin.nginx
# Profile สำหรับ Nginx บน Ubuntu
#include <tunables/global>
/usr/sbin/nginx {
#include <abstractions/base>
#include <abstractions/nameservice>
#include <abstractions/openssl>
capability dac_override,
capability net_bind_service,
capability setgid,
capability setuid,
# Binary
/usr/sbin/nginx mr,
# Config
/etc/nginx/ r,
/etc/nginx/** r,
# Logs
/var/log/nginx/ rw,
/var/log/nginx/** rw,
# Web Root
/var/www/ r,
/var/www/** r,
# SSL Certificates
/etc/ssl/certs/ r,
/etc/ssl/certs/** r,
/etc/letsencrypt/live/ r,
/etc/letsencrypt/live/** r,
/etc/letsencrypt/archive/ r,
/etc/letsencrypt/archive/** r,
# PID, Cache, Temp
/run/nginx.pid rw,
/var/cache/nginx/ rw,
/var/cache/nginx/** rw,
/tmp/ rw,
/tmp/nginx* rw,
# Unix Sockets (สำหรับ PHP-FPM)
/run/php/ r,
/run/php/*.sock rw,
# Network
network inet tcp,
network inet6 tcp,
network unix stream,
# Proc (สำหรับ Worker Process)
/proc/*/cpuinfo r,
/proc/*/meminfo r,
# Deny
deny /etc/shadow r,
deny /root/ rw,
deny /home/**/.ssh/ rw,
}
ตัวอย่าง Profile — MySQL/MariaDB
# /etc/apparmor.d/usr.sbin.mysqld
# Profile สำหรับ MySQL/MariaDB
#include <tunables/global>
/usr/sbin/mysqld {
#include <abstractions/base>
#include <abstractions/nameservice>
#include <abstractions/user-tmp>
capability dac_override,
capability sys_resource,
capability net_bind_service,
capability setuid,
capability setgid,
# Binary
/usr/sbin/mysqld mr,
# Config
/etc/mysql/ r,
/etc/mysql/** r,
# Data Directory
/var/lib/mysql/ rw,
/var/lib/mysql/** rw,
# Logs
/var/log/mysql/ rw,
/var/log/mysql/** rw,
# PID, Socket
/run/mysqld/ rw,
/run/mysqld/mysqld.pid rw,
/run/mysqld/mysqld.sock rw,
/run/mysqld/mysqld.sock.lock rw,
# Tmp
/tmp/ rw,
/tmp/** rw,
# Deny access outside DB directory
deny /etc/passwd w,
deny /etc/shadow rw,
}
AppArmor Abstractions
Abstractions คือ Profile Fragment ที่ใช้ซ้ำได้ เก็บอยู่ที่ /etc/apparmor.d/abstractions/ ช่วยลดความซ้ำซ้อนในการเขียน Profile
# Abstractions ที่ใช้บ่อย
#include <abstractions/base> # libc, locale, tz, dns
#include <abstractions/nameservice> # DNS, /etc/hosts, NSS
#include <abstractions/openssl> # libssl, /etc/ssl/openssl.cnf
#include <abstractions/user-tmp> # /tmp, /var/tmp
#include <abstractions/python> # Python libs และ modules
#include <abstractions/perl> # Perl libs
#include <abstractions/php> # PHP libs (Ubuntu)
#include <abstractions/apache2-common> # Apache + modules
# ดู Abstractions ที่มีทั้งหมด
ls /etc/apparmor.d/abstractions/
# ดูเนื้อหา Abstraction
cat /etc/apparmor.d/abstractions/base
AppArmor สำหรับ Docker Container
# Docker ใช้ AppArmor Profile ชื่อ docker-default โดย Default
# ตรวจสอบ Profile ที่ Container ใช้
docker inspect --format='{{.AppArmorProfile}}' <container-id>
# รัน Container ด้วย Profile เฉพาะ
docker run --security-opt apparmor=docker-default nginx
# รัน Container โดยไม่มี AppArmor (ไม่แนะนำ)
docker run --security-opt apparmor=unconfined nginx
# ดู Profile docker-default
cat /etc/apparmor.d/docker
# สร้าง Custom Profile สำหรับ Docker Container
# /etc/apparmor.d/docker-nginx-strict
#include <tunables/global>
profile docker-nginx-strict flags=(attach_disconnected,mediate_deleted) {
#include <abstractions/base>
network inet tcp,
network inet6 tcp,
/etc/nginx/** r,
/var/www/html/** r,
/var/log/nginx/** rw,
deny /proc/sysrq-trigger rw,
deny /proc/sys/kernel/** rw,
}
# โหลด Profile
sudo apparmor_parser -r /etc/apparmor.d/docker-nginx-strict
# รัน Container ด้วย Custom Profile
docker run --security-opt apparmor=docker-nginx-strict nginx
Tunable Variables
# Tunables คือ Variable ที่ใช้แทนค่าซ้ำในหลาย Profile
# เก็บที่ /etc/apparmor.d/tunables/
# ดู Tunable ที่สำคัญ
cat /etc/apparmor.d/tunables/global
# @{PROC}=/proc/
# @{sys}=/sys/
# @{HOME}=@{HOMEDIRS}/*/ /root/
# @{HOMEDIRS}=/home/
# ใช้งานใน Profile
/usr/sbin/nginx {
@{PROC}/*/cpuinfo r, # แทน /proc/*/cpuinfo r
/var/www/** r,
}
# สร้าง Tunable เอง
# /etc/apparmor.d/tunables/webroot
# @{WEBROOT}=/var/www/html/ /srv/www/
Script ตรวจสอบ AppArmor
#!/bin/bash
# /usr/local/bin/apparmor-check.sh
# ตรวจสอบสถานะ AppArmor และ Profile
echo "=== AppArmor Status ==="
if ! command -v apparmor_status &>/dev/null; then
echo "AppArmor tools not installed"
exit 1
fi
if ! sudo apparmor_status --enabled 2>/dev/null; then
echo "❌ AppArmor is NOT enabled"
exit 1
fi
echo "✅ AppArmor is enabled"
echo ""
# สรุป Profile
ENFORCE=$(sudo aa-status 2>/dev/null | grep "profiles are in enforce" | awk '{print $1}')
COMPLAIN=$(sudo aa-status 2>/dev/null | grep "profiles are in complain" | awk '{print $1}')
echo "Profiles in Enforce mode: ${ENFORCE:-0}"
echo "Profiles in Complain mode: ${COMPLAIN:-0}"
echo ""
# แสดง Profile ที่ Complain (ควรตรวจสอบและเปลี่ยนเป็น Enforce)
if [ "${COMPLAIN:-0}" -gt 0 ]; then
echo "⚠️ Profiles in Complain mode (consider enforcing):"
sudo aa-status 2>/dev/null | grep -A "${COMPLAIN}" "profiles are in complain" | tail -"${COMPLAIN}"
fi
echo ""
# ตรวจหา Recent Denials
echo "=== Recent AppArmor Denials (last 24h) ==="
sudo journalctl -k --since "24 hours ago" 2>/dev/null \
| grep 'apparmor="DENIED"' \
| awk '{print $1, $2, $NF}' \
| sort | uniq -c | sort -rn | head -20
echo ""
echo "=== Done ==="
สรุป
AppArmor ใช้ Path-based Profile ควบคุม Access ของ Process แต่ละตัว โดยมี 3 Mode คือ Enforce (บังคับ), Complain (Log อย่างเดียว) และ Disabled วิธีสร้าง Profile ที่มีประสิทธิภาพที่สุดคือเริ่มจาก Complain Mode แล้วใช้ aa-logprof ในการอ่าน Log และเพิ่ม Rule ทีละส่วนจนครบ หรือใช้ aa-genprof สร้าง Profile แบบ Interactive การใช้ Abstractions ช่วยลดการเขียน Rule ซ้ำสำหรับ Library และ System Resource ที่ใช้บ่อย AppArmor เหมาะสำหรับระบบ Ubuntu/Debian และสามารถใช้ร่วมกับ Docker ได้โดยกำหนด --security-opt apparmor=<profile>
แนะนำบริการ DE
การตั้งค่า AppArmor Profile สำหรับ Application บน Server ต้องการสิทธิ์ Root และการเข้าถึง Kernel Module โดยตรง Cloud VPS ของ DE ให้ Root Access เต็มรูปแบบ สามารถติดตั้ง apparmor-utils, สร้าง Custom Profile, และตั้งค่า MAC Security สำหรับทุก Service บน Server ได้อย่างอิสระ
สำหรับผู้ที่ต้องการโฮสต์เว็บไซต์โดยมีระบบความปลอดภัยพร้อมใช้ Cloud Hosting ของ DE มี Security Infrastructure ที่ตั้งค่าไว้แล้ว เหมาะสำหรับผู้ที่ต้องการความปลอดภัยระดับ Enterprise โดยไม่ต้องจัดการ AppArmor เอง

