← All rules
SOCLE-CLD-GEN-033// Hardening (misc)mediumeffective runtime

Enforce all AppArmor Profiles

Requires AppArmor to be enabled and zero profiles in complain mode, every loaded profile must be in enforce mode.

Checked against the resolved running state (e.g. sshd -T, sysctl, systemctl show), catches drop-ins and Includes a file read would miss. Caveat: runtime ≠ persistence; a value correct now may not survive a reboot.

A pass proves✓ running now? on disk? survives rebootthe qualified verdict →
Debian 12CIS 1.1.0Debian 13CIS 1.0.0Ubuntu 22.04CIS 3.0.0Ubuntu 24.04CIS 1.0.0Ubuntu 26.04
One check, maps to 2 standards

Pavois asserts the effective configuration, the live, resolved state, not a file. File-based scanners (OVAL/SCAP, Lynis) miss Includes, drop-ins and runtime defaults; this check sees what is actually applied.

A mapping is a cross-reference to where each standard places this requirement, anchored and cross-validated, not a claim of equivalence. A passing check is evidence toward these references, how to read it.

Why this rule matters

A profile in complain mode only logs policy violations; it does not block them, so it provides no actual confinement. Putting every profile in enforce mode ensures the mandatory access controls are genuinely applied: a compromised service is contained to exactly the files, capabilities and network it is allowed, limiting lateral movement and privilege escalation.

What Pavois checks

Pavois asks aa-status for the live kernel state: it requires AppArmor to be enabled and the complaining profile count to be 0. Querying aa-status reflects the profiles actually loaded into the kernel and their current mode, far more reliable than reading /etc/apparmor.d/ files, which may not all be loaded or may differ from the running policy.

describe command('[ "$(aa-status --complaining 2>/dev/null)" = "0" ] && [ -n "$(aa-status --enabled 2>/dev/null && echo y)" ] && echo ok || echo ko') do
  its('stdout.strip') { should eq 'ok' }
end

How to verify it is applied

Run aa-status. Expect profiles are in enforce mode to be non-zero and profiles are in complain mode to be 0. aa-status --complaining should print 0.

Inspect & investigate

AppArmor decisions are logged via the kernel audit subsystem in /var/log/audit/audit.log (look for apparmor="DENIED" / apparmor="ALLOWED") or in /var/log/kern.log / journalctl -k. Current mode per profile is shown by aa-status.

Remediation

Pavois's harden plan runs an exec resource that calls aa-enforce /etc/apparmor.d/* to switch every profile to enforce mode, guarded by a not_if so it is skipped when aa-status --complaining already reports 0 (idempotent). Apply it with pavois harden apply.

Pavois applies this with its own harden engine, the plan below, not a shell script:

commandaa-enforce /etc/apparmor.d/* 2>/dev/null; true
nameapparmor-enforce
not_iftest "$(aa-status --complaining 2>/dev/null)" = 0
resourceexec
pavois harden plan local

where the target is local, a user@host SSH alias, or a container , Docs

Impact & precautions

Enforcing profiles that were only being observed in complain mode can suddenly block previously-tolerated actions, breaking applications that relied on access the profile does not grant. Before applying, review /var/log/audit/audit.log for apparmor="ALLOWED"/complain-mode events to see what each profile would deny in enforce mode, fix the affected profiles (aa-logprof), and test critical services. A misbehaving profile can be reverted per-service with aa-complain <profile> without disabling AppArmor entirely.

Standards mapping

StandardReferenceTypeVersionConfidence
ANSSI BP-028R45direct2.0high
CIS1.3.1.4directper OS, see the benchmark tablehigh

Each reference is a cross-reference anchored in the upstream benchmark and cross-validated against the SCAP Security Guide and ansible-lockdown, not a claim of equivalence. Direct = a prescriptive, line-level requirement; supporting = an abstract control family (NIST) the check provides evidence toward. How to read a mapping.

Sources & references