Audit / log collector (receive side)
An rsyslog container that receives logs forwarded by booted diskless hosts
and writes them to durable, per-source-host files. Diskless hosts run on an
immutable erofs root with a RAM-only volatile overlay, so their local
/var/log/audit/audit.log is lost on every reboot — this gives auditd somewhere
permanent to offload to. It implements the remote-audit-offload that STIG
deviation #6 (docs/stig-deviations.md) lists as future hardening.
booted host serving host
┌───────────────────────────┐ ┌──────────────────────────────┐
│ auditd → audisp-syslog │ TCP/514 │ audit (this container) │
│ → rsyslog (forward) ├──────────►│ rsyslogd → /var/log/remote/ │
│ to ${AUDIT_HOST} │ syslog │ <sender-ip>/audit.log │
└───────────────────────────┘ │ <sender-ip>/messages.log │
└──────────────────────────────┘
What this provides (the receiver)
- Listens on TCP/514 (plain syslog). Disk-assisted queue so bursts / brief stalls don't drop records.
- Writes per sender IP (not the claimed hostname): audit records →
audit.log, everything else →messages.log, under./logs/<ip>/(bind-mounted, inspectable on the host). - Host-networked, so hosts reach it at
${AUDIT_HOST}(resolved to the serving host by the stack's dnsmasq), matching the boot/NVMe DNS pattern.
Run it with the rest of the stack:
cd serving
docker compose build audit
docker compose up -d audit
docker compose logs -f audit # startup + connection messages
tail -F audit-collector/logs/*/audit.log
Quick self-test (send a line as if from a host):
logger -n 127.0.0.1 -P 514 -T -t audispd "test audit record"
ls audit-collector/logs/ # a 127.0.0.1/ dir appears
What's still needed (the sender — in the image)
This container only receives. To make hosts actually send, the hardened
image needs (not yet wired — keep no per-host state, use the generic
${AUDIT_HOST} name, never a per-host address):
-
auditd → syslog: enable the
audisp-syslogplugin (/etc/audit/plugins.d/syslog.conf:active = yes), so audit events also go to the local syslog socket. -
rsyslog forward rule: a drop-in (e.g.
/etc/rsyslog.d/60-fleet-remote.conf) forwarding to the collector with a disk-assisted action queue, so a network blip doesn't drop records:*.* action(type="omfwd" target="audit.fleet.lab" port="514" protocol="tcp" queue.type="LinkedList" queue.fileName="fwdq" queue.maxDiskSpace="256m" queue.saveOnShutdown="on" action.resumeRetryCount="-1") -
Bake
audit.fleet.lab(the generic name) — DNS resolves it per environment.
Once the sender is wired, flip STIG deviation #6 in docs/stig-deviations.md
from "local-only" to "offloading to ${AUDIT_HOST}" and the
rsyslog_remote_loghost rule should pass.
Production hardening (lab simplifications to revisit)
The lab stack is plaintext TCP, mirroring the HTTP-boot/no-TLS posture. For a secured fleet:
- TLS: rsyslog
gtlsdriver (mutual auth with the boot-infra CA), or RELP + TLS (imrelp/omrelp) for guaranteed, acknowledged delivery. - Restrict senders by subnet (
$AllowedSender) or firewall :514 to the boot LAN. - Add log rotation/retention (logrotate sidecar or rsyslog
outchannel) and ship to long-term storage / SIEM.