major.io words of wisdom from a systems engineer

augenrules fails with “rule exists” when loading rules into auditd

When I came back from the holiday break, I found that the openstack-ansible-security role wasn’t passing tests any longer. The Ansible playbook stopped when augenrules ran to load the new audit rules. The error wasn’t terribly helpful:

/usr/sbin/augenrules: No change
Error sending add rule data request (Rule exists)
There was an error in line 5 of /etc/audit/audit.rules

A duplicated rule?

I’ve been working on lots of changes to implement the Red Hat Enterprise Linux 7 Security Technical Implementation Guide (STIG) and I assumed I put in the same rule twice with an errant copy and paste.

That wasn’t the case. I checked the input rule file in /etc/audit/rules.d/ and found that all of the rules were unique.

Is something missing?

The augenrules command works by taking files from /etc/audit/rules.d/ and joining them together into /etc/audit/audit.rules. Based on the output from augenrules, the rule file checks out fine and it determined that the existing rule doesn’t need to be updated. However, augenrules is still unable to load the new rules into auditd.

I decided to check the first several lines of /etc/audit/rules.d/ to see if line 5 had a problem:

## This file is automatically generated from /etc/audit/rules.d


-f 1
-a always,exit -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=4294967295 -k RHEL-07-030525
-a always,exit -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=4294967295 -k RHEL-07-030513

Two things looked strange to me:

  • Line 5 is correct and it is unique
  • Why are lines 2 and 3 blank?

I checked another CentOS 7 server and found the following in lines 2 and 3:

-D
-b 320

The -D deletes all previously loaded rules and -b increases the buffer size for busy periods. My rules weren’t loading properly because the -D was missing! Those two lines normally come from /etc/audit/rules.d/audit.rules, but that default file was not present.

Here’s what was going wrong:

  • augenrules read rules from rules.d/
  • augenrules found that the rules in rules.d/ were already in the main audit.rules file and didn’t need to be updated
  • augenrules attempted to load the rules into auditd, but that failed
  • auditd was rejecting the rules because at least one of them (line 5) already existed in the running rule set

All of this happened because the -D wasn’t handled first before new rules were loaded.

Fixing it

I decided to add the -D line explicitly in my rules file within rules.d/ to catch those situations when the audit.rules default file is missing. The augenrules command ensures that the line appears at the top of the rules when they are loaded into auditd.