Verify Permissions on /etc/audit/rules.d/*.rules
Ensures every *.rules file in /etc/audit/rules.d/ is no more permissive than 0640 (no group/other write, no other read, no special bits).
Checked against a path’s metadata, mode, owner, group, SUID/SGID.
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
The *.rules fragments under /etc/audit/rules.d/ declare which syscalls, files and events auditd watches, they are compiled into the active ruleset at boot. If they are writable by group or other, an attacker can delete or weaken rules to blind the system to their actions; if readable by other, they reveal exactly what is (and is not) monitored, helping evasion. Restricting them to root keeps the audit policy tamper-proof and confidential.
What Pavois checks
Pavois runs find /etc/audit/rules.d -name "*.rules" -perm /0137 and expects an empty result: the /0137 mask matches any file carrying group-write, other-read, other-write or any execute bit. Because it scans the directory at audit time rather than trusting a packaged template, it catches new fragments dropped in by Ansible, a cookbook or an operator, the same drop-in blind spot that file-template scanners miss.
only_if { file('/etc/audit/rules.d').exist? }
describe command('find /etc/audit/rules.d -name "*.rules" -perm /0137 2>/dev/null') do
its('stdout') { should eq '' }
endHow to verify it is applied
Run find /etc/audit/rules.d -name '*.rules' -perm /0137 -ls. Expected output is nothing (all fragments are 0640 or stricter, owned by root). Any line printed names a non-compliant file. You can also confirm with stat -c '%a %n' /etc/audit/rules.d/*.rules and expect each mode to be 640 or lower.
Inspect & investigate
auditd compiles these fragments at start; check journalctl -u auditd and auditctl -l to confirm the expected rules loaded, and /var/log/audit/audit.log (grep CONFIG_CHANGE) for any tampering. A permission fix that follows a rule edit should be followed by augenrules --load.
Remediation
Pavois's harden plan runs an exec resource named chmod-audit-rulesd: chmod 0640 /etc/audit/rules.d/*.rules, guarded by a not_if that re-runs the same find so it is a no-op once compliant (idempotent). Apply it with pavois harden apply. It does not re-load auditd, so run augenrules --load (or restart auditd) afterwards if rules changed.
Pavois applies this with its own harden engine, the plan below, not a shell script:
| command | chmod 0640 /etc/audit/rules.d/*.rules 2>/dev/null || true |
|---|---|
| name | chmod-audit-rulesd |
| not_if | test -z "$(find /etc/audit/rules.d -name '*.rules' -perm /0137 2>/dev/null)" |
| resource | exec |
pavois harden plan localwhere the target is local, a user@host SSH alias, or a container , Docs
Impact & precautions
Setting 0640 on rule fragments is safe, auditd reads them as root. Precautions: the remediation only tightens permissions, never edits rule content, so monitoring coverage is unaffected. Verify auditd still loads the policy afterwards with auditctl -l. The only way to break things is an unrelated bad rule edit; the chmod itself cannot cause a lockout. Leaving fragments group/other-writable would let an unprivileged process silently disable auditing. Directory traversal (RHEL): /etc/audit/rules.d is a directory, keep its owner search bit (0750); a file-style 0600/0640 strips x, and under SELinux enforcing auditd is denied dac_read_search and fails to start. Recover with chmod 750 /etc/audit/rules.d && restorecon -R /etc/audit.
Standards mapping
| Standard | Reference | Type | Version | Confidence |
|---|---|---|---|---|
| CIS | 6.2.4.5, 6.3.4.5 | direct | per OS, see the benchmark table | high |
| NIST | AU-12(b) | supporting | 800-53 Rev 5 · 800-171 Rev 2 (pinned) | medium |
| DISA STIG | UBTU-22-653065, UBTU-24-900040 | direct | per OS STIG release | high |
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.