laurel(8)

✨ LAUREL (8) ✨

okay bestie so this is laurel(8), and it lives in the System Administration Utilities corner of the manpage universe πŸ’–. It's literally an auditd plug-in and it's about to be your new fave. Buckle up πŸŽ€


🌸 NAME 🌸

laurel(8) – transform, enrich Linux audit logs πŸ’…


πŸ¦‹ SYNOPSIS πŸ¦‹

laurel is an auditd(8) plug-in that parses Linux audit events, enriches them with local information, and transforms them into a JSON Lines-based output format intended for consumption by log processing and SIEM software.


πŸ‘‘ OPTIONS πŸ‘‘

  • -c FILE, --config=FILE β€” the path to the configuration file. Default: unset (so like, nothing, bestie, you gotta tell it)
  • -d, --dry-run β€” only parse the configuration and then just… exit. No vibes, no logs, just a lil config check ✨
  • -h, --help β€” prints the short help text and dips out
  • -v, --version β€” prints the version and bounces

πŸ’– DESCRIPTION πŸ’–

So normally laurel gets spawned by auditd(8) itself, or by audispd(8) if you're on the 2.x auditd versions. Either way, every single audit event gets fed to laurel through its standard input channel. That's the pipeline, that's the arrangement, no cap πŸ“₯

Here's a sample configuration file at /etc/audit/plugins.d/laurel.conf:

active = yes
direction = out
type = always
format = string
path = /usr/sbin/laurel
args = --config /etc/laurel/config.toml

There's also an alternative setup, and honestly? It's giving ✨main character✨ β€” you use an AF_UNIX socket that auditd(8) writes events to. Then laurel makes the connection itself (peep the input setting down below 🌈). Important though: in this setup, you the operator are responsible for starting and restarting laurel. It's not gonna do it for you, bestie 🫢

Example configuration file for that whole situation:

active = yes
direction = out
path = builtin_af_unix
type = builtin
args = 0600 /var/run/laurel.sock
format = string

πŸŽ€ CONFIGURATION πŸŽ€

laurel itself gets configured through a single configuration file in TOML format. One file. That's it. Iconic.


🌟 main section 🌟

This section holds the basic operation parameters. The fundamentals, the essentials, the bare minimum slay πŸ’…

  • user: laurel is started as root by auditd, but it drops to a dedicated user as soon as possible. Default: unset
  • directory: The base directory into which all files are written. Default: . (current directory)
  • statusreport-period: How often stats are written to Syslog, in seconds. Default: unset
  • input: laurel can consume audit events from standard input, or connect to a listening socket specified as unix:/path/to/socket at start. Default: stdin
  • marker: A string that is written to the log on startup and whenever laurel writes a status report. Default: none

🌈 [auditlog] section 🌈

This section describes the main audit log file. And yes, laurel performs its own log file rotation, just like auditd(8). It's self-sufficient, it's independent, it's that girl πŸ”₯

  • file: Filename for the audit log file. Default: audit.log
    • causes laurel to write its log to standard output.

A string beginning with a pipe (e.g. | /path/to/program) causes laurel to spawn an external program and write its log to that program's standard input.

A string beginning with unix: (e.g. unix:/path/to/socket) causes laurel to connect and write its log to a UNIX domain socket. On I/O errors, reconnection attempts will be made.

  • size: Size in bytes after which the log file is rotated. Default: 10MiB
  • generations: Number of generations to keep after rotation. Default: 5
  • read-users: List of users that are granted read access to the log file using POSIX ACLs. Default: empty
  • read-groups: List of groups that are granted read access to the log file using POSIX ACLs. Default: empty
  • read-other: Whether all users are granted read access to the log file. Default: false
  • line-prefix: A string that is prepended to every line. Default: unset

πŸ¦‹ [filterlog] section πŸ¦‹

This section describes the log file for filtered-out log events (see below πŸ‘€). The file, size, generations, read-users, line-prefix configuration items work just like for the audit log. Same energy, different file, periodt.


πŸ’œ [state] section πŸ’œ

This section describes the state file. laurel uses this file on restart to keep track of running processes. The state file contains snapshots of the user database cache, process list, currently used events and a list of event ids that have already been processed. It's like a little memory diary for laurel πŸ“”

  • file: Filename for the state file. Set to empty string to disable keeping state on disk. Default: state
  • generations: Number of generations of the state file to keep for debugging purposes. Default: 0; it should only be increased for debugging purposes. (like seriously only for debugging)
  • max-age: Number of seconds after which the state file is considered stale. Default: 60
  • write-state-period: How often the state file is written to the filesystem, in seconds. Default: unset

🌸 [transform] section 🌸

  • execve-argv: The list of EXECVE.a* fields are transformed to an ARGV list or ARGV_STR string. Set to array, string (or both). Default: array
  • execve-argv-limit-bytes: Arguments are cut out of the middle long argument lists in EXECVE.ARGV or EXECVE.ARGV_STR so that this limit is not exceeded. Default: unset

⭐ [translate] section ⭐

The options you can configure here correspond to what auditd(8) does when it's configured with log_format=ENRICHED. Same vibe, different config file bestie πŸ’–

  • userdb: Add translations for uid and gid fields. Default: false
  • universal: Add translations for everything else: SYSCALL.arch, SYSCALL.syscall, SOCKADDR.saddr
  • drop-raw: Drop raw (numeric) syscall, arch, UID, GID values if they are translated. Default: false

🫢 [enrich] section 🫢

The options configurable here actually add information to events. Real added value, we love to see it ✨

  • execve-env: A list of environment variables to dump for exec events. Prefix matches are used for strings ending with an asterisk (*). Default: ["LD_PRELOAD", "LD_LIBRARY_PATH"]
  • container: Add container information for processes running within container runtimes as SYSCALL.PID.container. Default: true
  • systemd: Add systemd cgroup information for processes running within systemd services as SYSCALL.PID.systemd_service. Default: true
  • container_info: Add container information as top-level CONTAINER_INFO key. Deprecated; default: false
  • pid: Add context information for process IDs. Default: true
  • ppid-verbose: As part of the SYSCALL.PPID.* enrichment, the first event ID referring to the parent process or its start time is logged. If this option is set, the comm, exe, and ppid fields are added. Deprecated, see spawned-by. Default: false
  • spawned-by: Add SYSCALL.SPAWNED_BY.* enrichments that contains information about the process responsible for spawning the current process. This is a replacement for the SYSCALL.PPID enrichment. For a more detailed discussion, see section "Adding Context: Process Relationships, Labels" in laurel-about(7). Default: true
  • script: If an exec syscall spawns a script (as opposed to a binary), add a SCRIPT entry to the SYSCALL record. A script is assumed if the first PATH entry does not correspond to file mentioned in SYSCALL.exe. Default: true
  • user-groups: Add groups that the user ("uid") is a member of. Default: true
  • prefix: Add a prefix to enriched fields; this may be useful if logs are consumed by analysis software that doesn't properly understand uppercase and lowercase JSON object fields as identical. This setting does not affect enriched fields passed in from auditd(8). Default: unset
  • exe-hash: Compute SHA256 hash of the executable (SYSCALL.exe) and add it as EXE_HASH to the SYSCALL record. Default: false
  • exe-hash-size-limit: Skip hashing executables larger than this size (in bytes). Recommended to avoid excessive I/O on large binaries. Default: 10_000_000
  • exe-hash-cache-entries: Maximum number of entries in the exe hash LRU cache (keyed by inode + mtime). Set to 0 to disable caching. Default: 1024

πŸ’… [label-process] section πŸ’…

Labels can be attached to processes and are added to any event associated with those processes. These labels can be propagated from parent to child processes. It's giving family heirloom but make it metadata 🧚

  • label-exe.<regexp> = <label-name>: Regular expressions/label mappings applied to binary executables (SYSCALL.exe) on execve calls. Default: none
  • label-argv.<regexp> = <label-name>: Regular expressions/label mappings applied to the command line (EXECVE.a*) on execve calls. Default: none
  • label-script.<regexp> = <label-name>: Regular expressions/label mappings applied to scripts (SYSCALL.SCRIPT, see enrich.script description above) on exec calls. Default: none
  • label-keys: A list of keys that are applied as a process label, see auditctl(8)'s -k option. Default: none
  • unlabel-exe.<regexp> = <label-name>: Like label-exe, but for removing labels
  • unlabel-argv.<regexp> = <label-name>: Like label-argv, but for removing labels
  • unlabel-script.<regexp> = <label-name>: Like label-script, but for removing labels
  • label-argv-count Number of command line arguments that are considered for label-argv, unlabel-argv. Default: 32
  • label-argv-bytes Number of bytes that are considered for label-argv, unlabel-argv. Default: 4096
  • propagate-labels: List of labels that are propagated to child processes. Default: empty

πŸ”₯ [filter] section πŸ”₯

Filters make laurel drop entire events from the log file while still using them for internal processing such as process tracking. So the event gets ghosted from the log but laurel still remembers it for its own inner workings. Bestie is keeping receipts in private but not posting them πŸ’€

  • filter-keys: A list of strings that are matched against SYSCALL.key to drop the event. Default: empty
  • filter-null-keys: Filter events without specified key. Default: false
  • filter-labels: A list of strings that are matched against process labels. Default: empty
  • filter-sockaddr: Filter events that contain SOCKADDR entries matching CIDR and/or ports. IPv4 and IPv6 addresses with optional bitmask and port numbers or plain port numbers can be specified. Examples:
    • 127.0.0.1
    • 192.168.0.0/24:22
    • ::/64
    • [2a00:1450:4001:82f::200e]:443
    • *:111

Default: empty list

  • filter-raw-lines: A list of regular expression that are matched against individual input lines as written by auditd(8). Events that contain such lines are then filtered. Default: empty
  • filter-action: What to do with filtered events? drop or log to the filterlog defined above.
  • keep-first-per-process: Keep the first event observed for any given process even if it would be filtered otherwise. This should only be turned off if reproducible process tracking or process tree reconstruction is not required. Default: true

🚨 SIGNALS 🚨

SIGHUP causes laurel to process any buffered input and restart. It can be used to reconfigure laurel without having restarting auditd(8) which would likely lead to lost audit messages. So like, huge β€” you get to glow up the config without dropping messages on the floor πŸ‘‘


πŸ” SEE ALSO πŸ”

auditd(8), auditd-plugins(5), audit.rules(7), laurel-about(7), laurel-audit-rules(7)

πŸ‘‘ AUTHORS πŸ‘‘

okay so if you're out here looking for someone to send a thank-you note to (and you should, this tool is doing a LOT for you πŸ’–), here's the cast:

  • Hilko Bengen πŸ’« β€” <bengen@hilluzination.de>
  • Sergej Schmidt πŸ’« β€” <sergej@msgpeek.net>

that's the whole list bestie, two absolute icons carrying the whole vibe. no cap. 🫢


aaaaand that's a wrap on laurel(8) β€” laurel version 0.8.2, page laurel(8), in the classic section-8 tradition of "system administration commands and daemons" energy. go forth, log beautifully, stay hydrated, and may your audit trail never eat itself πŸ’…βœ¨πŸ¦‹

πŸ“¦ where this page comes from