Skip to content
FreeBSDDeep Dive Published Updated 6 min readViews unavailable

FreeBSD auditdistd: Send BSM Audit Trails to a Remote Collector

Configure FreeBSD auditdistd sender and receiver roles, enable trail distribution, pin TLS identity, protect credentials, and verify delivered files.

FreeBSD’s BSM audit subsystem writes structured audit trails locally. auditdistd(8) adds a separate distribution path: auditd makes trail files available under /var/audit/dist, and an auditdistd sender transfers them to a configured receiver. This is file distribution, not a replacement for local audit policy, retention, or an event-by-event application stream.

Keep two questions separate. Audit policy decides which events the kernel records. Distribution decides which host may receive the resulting trail files and where they are stored. A healthy receiver cannot recover events that were never recorded, while a local audit trail does not prove that an off-host copy arrived.

Map the data path before changing configuration

The dist setting in /etc/security/audit_control causes auditd to create hard links to audit trails in /var/audit/dist. The sender watches that directory. A receiver accepts configured source hosts and stores their trails below its remote audit directory. The receiver can be configured for multiple senders; a sender configuration currently supports one remote receiver.

The hard links are local filesystem references, not a second copy or a backup. Ensure the audit trail directory and distribution directory can be linked on the same filesystem, and budget space for both the live trail and the receiver’s retained copy. If you use a non-default trail directory, test the exact layout before enabling distribution. The receiver is not an immutable archive by itself: protect its filesystem, access policy, backups, and retention separately.

First inventory the host and the existing audit service. These checks do not change policy:

freebsd-version -kru
grep -E '^(dir|dist):' /etc/security/audit_control
ls -ld /var/audit /var/audit/dist
service auditd status
service auditdistd status
df -h /var/audit

The last two status checks may report that a service is not running; that is useful evidence, not a reason to edit the event classes. Preserve existing dir, flags, naflags, and retention policy. Do not replace a production audit_control with a short example from another host.

Configure the receiver and sender separately

On the collector, provision a certificate and private key through your approved certificate process. Keep the private key readable only by the required service account and administrators. A receiver configuration can be scoped to a source address and a per-host directory:

name "audit-collector"

receiver {
    listen "tls://192.0.2.50:7878"
    directory "/var/audit/remote"
    certfile "/etc/security/auditdistd.cert.pem"
    keyfile "/etc/security/auditdistd.key.pem"

    host "edge01" {
        remote "192.0.2.10"
        directory "edge01"
        password "replace-with-the-same-generated-secret"
    }
}

On the audited FreeBSD host, configure its identity, the distribution directory, and the collector:

name "edge01"

sender {
    directory "/var/audit/dist"
    host "audit-collector" {
        remote "tls://192.0.2.50:7878"
        fingerprint "SHA256=REPLACE_WITH_RECEIVER_CERTIFICATE_FINGERPRINT"
        password "replace-with-the-same-generated-secret"
    }
}

Replace the documentation-only addresses and secret in both files. Keep the host name aligned with the sender’s global name, and restrict the receiver’s remote entry to the sender address as observed by the collector. Bind listen to the intended collector interface rather than exposing the service on every interface without a firewall policy. The example explicitly uses tls://; do not change it to an unencrypted transport just to make a connection test pass.

The receiver’s certificate fingerprint in the sender configuration pins that certificate, not an abstract public key: reissuing a certificate changes its fingerprint, even if the same key is reused. Plan certificate rotation together with the corresponding sender configuration update. The shared password is a separate sender-authentication mechanism; it is not a substitute for TLS encryption or careful address restrictions. The configuration may contain passwords, so the FreeBSD manual recommends restrictive file permissions such as mode 0600. Keep both configuration files and the receiver’s private key out of support bundles.

On the sender, append dist:on to the existing /etc/security/audit_control policy. Follow the installed audit(8) procedure to restart or reload the audit system so auditd reads the change. Then enable and start auditdistd on each role:

sysrc auditdistd_enable="YES"
service auditdistd start
service auditdistd status

The rc service declares an ordering dependency on auditd and requires /etc/security/auditdistd.conf. Review the actual service script and installed manuals for the host’s FreeBSD release before automating startup. On the receiver, allow TCP port 7878 only from the expected sender addresses; if you choose a different port, configure it consistently on both ends and in the firewall.

Verify a complete transfer with a controlled trail

Start with a benign event that the existing policy already audits. Do not broaden production audit classes just to test transport. After recording the event, request a trail rotation:

audit -n
ls -lt /var/audit/dist

audit -n asks the audit daemon to close the current trail and switch to a new one; it does not mean that every record has been delivered. Wait for the sender to catch up, then inspect the receiver’s host-specific directory. Use the actual file name rather than assuming a current symlink:

ls -lt /var/audit/remote/edge01
praudit -l /var/audit/remote/edge01/RECEIVED_TRAIL
sha256 /var/audit/dist/SOURCE_TRAIL
sha256 /var/audit/remote/edge01/RECEIVED_TRAIL

Replace both trail placeholders with the matching file name. Compare the hashes only after the trail has been rotated and the receiver has finished writing it. A parsed record confirms the receiver file is readable as BSM; a matching hash confirms the compared files are byte-identical. Neither test proves the event policy was complete, so also verify that the expected test event appears and that the audit condition remains enabled with auditconfig -getcond.

For connection failures, compare the sender and receiver names, source address as seen by the receiver, TLS fingerprint, password, listener address and port, file permissions, and service logs. A running PID is not delivery evidence. Check whether hard links appear under /var/audit/dist, whether the receiver directory is writable by its service, and whether a disconnected sender catches up after the path is restored. Do not clear the distribution directory as a generic retry step; first establish which trail files are pending and preserve the evidence.

Set the recovery and retention boundary

The transport creates another copy, not a complete records-management policy. Define who can read received trails, how the collector detects gaps, how long trails remain, how backups are verified, and what happens when either filesystem is nearly full. Audit files can contain usernames, paths, command arguments, and other sensitive context. Restrict access at the sender and receiver, and use a protected channel for any later export.

Exercise a network interruption in a disposable environment. Confirm what remains in the sender’s distribution directory, whether delivery resumes, and how the collector names files from more than one host. Measure backlog growth during an outage and alert before the audit filesystem reaches its configured low-space threshold. Do not infer an exactly-once or immutable-ledger guarantee from a successful connection.

The acceptance test is deliberately end to end: the expected event exists in the local trail, its rotated file is available to the sender, the configured TLS receiver stores the same file under the intended host identity, the file parses, the hashes match, and the monitoring path detects a stopped daemon or growing backlog. Keep the local policy and the remote collection policy under separate review.

Related:

Sources:

Comments