CR: P16g AppArmor Deployment — Implementation

Implementation Plan

Phase 1: Install & Enable (Day 1)

1a. Install AppArmor userspace

sudo pacman -S apparmor
Package Purpose

apparmor

Meta-package: parser, utilities, profiles, systemd service

1b. Enable AppArmor in boot parameters

AppArmor is compiled into the Arch kernel but must be activated via kernel command line.

# BEFORE — check current boot parameters
cat /proc/cmdline
# Find the loader entry
ls /boot/loader/entries/
# Read current entry
cat /boot/loader/entries/arch.conf

Three boot entries exist: arch.conf, arch-fallback.conf, arch-lts.conf. All three must be updated.

Lesson learned during execution: The sed append approach (s/$/…​/) is fragile with long option lines — terminal line wrapping causes newlines inside the sed expression, truncating the command. The sed variable approach (${VAR} in double-quoted sed) caused double expansion. Use the full-line replacement approach below instead.

Also fixed: acpi_mask_gpe=0x6E was missing from arch-fallback.conf and arch-lts.conf — restored during this change.

# BEFORE — verify all three entries
grep '^options' /boot/loader/entries/arch.conf
grep '^options' /boot/loader/entries/arch-fallback.conf
grep '^options' /boot/loader/entries/arch-lts.conf
# APPLY — full-line replacement (one line each, no wrapping)
# arch.conf
sudo sed -i 's|^options.*|options cryptdevice=UUID=a33cc5e6-0e54-4aa4-bc26-d08a212aa32a:cryptroot root=/dev/mapper/cryptroot rootflags=subvol=@ rw nvidia_drm.modeset=1 mem_sleep_default=s2idle acpi_mask_gpe=0x6E lsm=landlock,lockdown,yama,integrity,apparmor,bpf apparmor=1 security=apparmor|' /boot/loader/entries/arch.conf
# arch-fallback.conf
sudo sed -i 's|^options.*|options cryptdevice=UUID=a33cc5e6-0e54-4aa4-bc26-d08a212aa32a:cryptroot root=/dev/mapper/cryptroot rootflags=subvol=@ rw nvidia_drm.modeset=1 mem_sleep_default=s2idle acpi_mask_gpe=0x6E lsm=landlock,lockdown,yama,integrity,apparmor,bpf apparmor=1 security=apparmor|' /boot/loader/entries/arch-fallback.conf
# arch-lts.conf
sudo sed -i 's|^options.*|options cryptdevice=UUID=a33cc5e6-0e54-4aa4-bc26-d08a212aa32a:cryptroot root=/dev/mapper/cryptroot rootflags=subvol=@ rw nvidia_drm.modeset=1 mem_sleep_default=s2idle acpi_mask_gpe=0x6E lsm=landlock,lockdown,yama,integrity,apparmor,bpf apparmor=1 security=apparmor|' /boot/loader/entries/arch-lts.conf
# VERIFY — all three entries, full file review
cat /boot/loader/entries/arch.conf
cat /boot/loader/entries/arch-fallback.conf
cat /boot/loader/entries/arch-lts.conf
Verified options line (identical across all three entries)
options cryptdevice=UUID=a33cc5e6-0e54-4aa4-bc26-d08a212aa32a:cryptroot root=/dev/mapper/cryptroot rootflags=subvol=@ rw nvidia_drm.modeset=1 mem_sleep_default=s2idle acpi_mask_gpe=0x6E lsm=landlock,lockdown,yama,integrity,apparmor,bpf apparmor=1 security=apparmor

1c. Enable AppArmor service

sudo systemctl enable apparmor.service

1d. Reboot and verify

sudo reboot

After reboot:

# Verify LSM stack
cat /sys/kernel/security/lsm
# Verify AppArmor is active
aa-enabled
# Check loaded profiles
sudo aa-status

Phase 2: Complain-Mode Baseline (Day 1-3)

2a. Load default profiles in complain mode

# Set all profiles to complain mode (logs violations but doesn't block)
sudo aa-complain /etc/apparmor.d/*
# Verify profile count
sudo aa-status | head -10

2b. Use the system normally for 2-3 days

Normal usage generates audit logs showing what each application accesses. This data informs custom profiles.

# Monitor AppArmor audit events
sudo journalctl -k | grep -i apparmor | tail -20
# Generate profile suggestions from logs
sudo aa-logprof

Phase 3: Enforce High-Risk Profiles (Day 3-7)

3a. Identify high-risk applications

Application Risk Priority

Firefox / Chromium

Browser exploits → credential exfiltration

High

node / npm

Supply chain attacks via npm packages

High

Docker daemon

Container escape → host filesystem

High

python / pip

Malicious packages

Medium

Claude Code (node-based)

Broad filesystem access by design

Medium — profile carefully

3b. Create custom deny rules for credential stores

The critical protection: deny high-risk apps access to sensitive directories.

# Example: deny Firefox access to credential stores
# /etc/apparmor.d/local/usr.bin.firefox
deny owner @{HOME}/.secrets/ rw,
deny owner @{HOME}/.secrets/** rw,
deny owner @{HOME}/.gnupg/ rw,
deny owner @{HOME}/.gnupg/** rw,
deny owner @{HOME}/.age/ rw,
deny owner @{HOME}/.age/** rw,
deny owner @{HOME}/.local/share/gopass/ rw,
deny owner @{HOME}/.local/share/gopass/** rw,
deny owner @{HOME}/.ssh/id_* rw,

3c. Enforce profiles for verified applications

# Switch from complain to enforce (one at a time, test each)
sudo aa-enforce /etc/apparmor.d/usr.bin.firefox
# Verify enforcement
sudo aa-status | grep -A2 enforce

Phase 4: Docker Confinement (Day 7+)

# Verify Docker uses AppArmor by default
docker info | grep -i apparmor
# Run a test container and verify AppArmor profile is applied
docker run --rm alpine cat /proc/self/attr/current