The audit mirror¶
The audit table can be edited by anyone with database access, and nothing in it would show. So every audit event is also written, as one authenticated line, to places the database does not control:
standard error — the systemd journal (
journalctl -u mcprack | grep AUDIT), which you can ship off the host;optionally a file:
/var/log/mcprack/audit.logby default when that directory is writable (AUDIT_LOG_FILE=/other/path, oroff), rotated by the packaged logrotate rule.
A line holds the row’s id, the same fields as the row (never bodies or credentials)
and a MAC (HMAC-SHA-256) keyed from SECRET_KEY; SECRET_KEY_FALLBACKS keeps
lines verifiable after a rotation. An event whose database row could not be
written — database down, or sabotaged — is still logged, with "id": null.
AUDIT_MIRROR_ENABLED=false switches the mirror off, AUDIT_MIRROR_STDERR=false
only the journal copy.
Verifying¶
sudo mcprack audit-verify # /var/log/mcprack/audit.log and rotated copies
sudo mcprack audit-verify --log /srv/shipped/audit.log --days 30
sudo mcprack audit-verify --strict # rows without a line fail too
Report |
Meaning |
|---|---|
|
A line with no row: the row was removed |
|
A row that differs from its line (the fields are named); a user or server reference that became empty because the user or server was deleted is not reported |
|
A line whose MAC is wrong: the log was edited (or |
|
Two different events carry one id: a row was deleted and the next event was given its id |
|
A row nobody logged: inserted, or written while the mirror was off
(a failure with |
Exit status 1 for the first four, 2 if there is no log to check. Lines older than
AUDIT_RETENTION_DAYS are not checked, because audit-archive legitimately
removes those rows. After restoring a database backup new events reuse ids the
backup lost, so REUSED ID is expected: rotate the log when you restore and
verify the new one.
What it proves¶
It is tamper evidence, not prevention, and it only means something if the
attacker cannot also rewrite the log. Ship the journal off the host
(systemd-journal-upload, rsyslog imjournal) or make the file append-only
(chattr +a). Run audit-verify from cron and alert on a non-zero exit.
How the file is opened¶
The log directory belongs to the service user while the command line tool may run
as root, so the file is opened without following symbolic links, must be a plain
file with a single hard link, is never a FIFO, and its owner and mode are set only
on a file just created (root hands it to the directory’s owner). An existing file
is never chown-ed or chmod-ed.