From a337a3e4f61c9a0a10ad0c2d2c39d47c14812154 Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Thu, 13 Aug 2026 14:30:45 -0400 Subject: [PATCH 1/2] Run zeekctl cron so the expire settings take effect LogExpireInterval, StatsLogExpireInterval and CrashExpireInterval are only acted on by "zeekctl cron", which nothing in the grid ran, so setting them in SOC did nothing. Add so-zeek-cron and run it every 5 minutes, the interval upstream recommends. This also restarts a node that died unexpectedly and marks it crashed so a crash report is written, which is what CrashExpireInterval then reaps. The crontab runs as root because the script needs the docker socket; it drops to the zeek user inside the container so the stats logs and zeekctl-config.sh it writes stay owned by uid 937. Annotate the five zeekctl settings that were previously undocumented. The regex on LogExpireInterval matters: a bare number means days, and a value shorter than LogRotationInterval raises ConfigurationError, which fails the zeekctl deploy in the container entrypoint. Zeek then never starts while Salt still reports success and the container still reports healthy. Excluding the min unit keeps that unreachable at the default 3600 second rotation interval. MinDiskSpace and MailHostUpDown only send mail and the image has no sendmail, so their descriptions say they currently have no effect. --- salt/zeek/disabled.sls | 5 ++++ salt/zeek/enabled.sls | 15 ++++++++++ salt/zeek/soc_zeek.yaml | 46 +++++++++++++++++++++++++++++++ salt/zeek/tools/sbin/so-zeek-cron | 24 ++++++++++++++++ 4 files changed, 90 insertions(+) create mode 100755 salt/zeek/tools/sbin/so-zeek-cron diff --git a/salt/zeek/disabled.sls b/salt/zeek/disabled.sls index 5011331bf..c75cdd7b1 100644 --- a/salt/zeek/disabled.sls +++ b/salt/zeek/disabled.sls @@ -23,6 +23,11 @@ zeekpacketlosscron: - identifier: zeekpacketlosscron - user: root +zeekctlcron: + cron.absent: + - identifier: zeekctlcron + - user: root + {% else %} {{sls}}_state_not_allowed: diff --git a/salt/zeek/enabled.sls b/salt/zeek/enabled.sls index ec01693d7..453990acb 100644 --- a/salt/zeek/enabled.sls +++ b/salt/zeek/enabled.sls @@ -87,6 +87,21 @@ zeekpacketlosscron: - month: '*' - dayweek: '*' +# LogExpireInterval, StatsLogExpireInterval and CrashExpireInterval are only acted on by +# 'zeekctl cron', so run it on the interval upstream recommends. This also restarts any +# node that died unexpectedly. Runs as root because the script needs the docker socket; +# it drops to the zeek user inside the container. +zeekctlcron: + cron.present: + - name: /usr/sbin/so-zeek-cron > /dev/null 2>&1 + - identifier: zeekctlcron + - user: root + - minute: '*/5' + - hour: '*' + - daymonth: '*' + - month: '*' + - dayweek: '*' + {% else %} {{sls}}_state_not_allowed: diff --git a/salt/zeek/soc_zeek.yaml b/salt/zeek/soc_zeek.yaml index 3bf1d2768..c03203623 100644 --- a/salt/zeek/soc_zeek.yaml +++ b/salt/zeek/soc_zeek.yaml @@ -58,6 +58,52 @@ zeek: CompressLogs: description: This setting enables compression of Zeek logs. If you are seeing packet loss at the top of the hour in Zeek or PCAP you might need to disable this by seting it to 0. This will use more disk space but save IO and CPU. helpLink: zeek + LogExpireInterval: + description: >- + How long to keep rotated Zeek logs in /nsm/zeek/logs. A bare number means DAYS, so 7 means 7 days. + You may also give an explicit unit, such as "7 days" or "12 hr". Use 0 to keep logs forever. + This value must not be shorter than LogRotationInterval (3600 seconds by default), so the smallest + usable value is 1 hr - Zeek will fail to start if it is shorter. Expiry is applied by "zeekctl cron", + which runs every 5 minutes, and removes log files older than this based on their modification time. + regex: ^(0|[1-9][0-9]*( ?(day|hr)s?)?)$ + regexFailureMessage: Enter 0, or a positive number optionally followed by "day" or "hr" (for example 7, "7 days", or "12 hr"). Minutes are not accepted because a log expire interval shorter than the log rotation interval prevents Zeek from starting. + helpLink: zeek + advanced: True + StatsLogExpireInterval: + description: >- + Number of days to keep entries in the Zeek stats log, or 0 to keep them forever. + Applied by "zeekctl cron", which runs every 5 minutes. + regex: ^[0-9]+$ + regexFailureMessage: You must enter a whole number of days, or 0 to keep entries forever. + helpLink: zeek + advanced: True + CrashExpireInterval: + description: >- + Number of days to keep Zeek crash directories, or 0 to keep them forever. + Applied by "zeekctl cron", which runs every 5 minutes. + regex: ^[0-9]+$ + regexFailureMessage: You must enter a whole number of days, or 0 to keep crash directories forever. + helpLink: zeek + advanced: True + MinDiskSpace: + description: >- + Percentage of free disk space below which ZeekControl reports a warning, or 0 to disable the check. + Note that this setting only sends email and the Zeek container does not include a mail program, + so it currently has no visible effect. It never deletes anything - disk based cleanup is handled + separately by so-sensor-clean. + regex: ^([0-9]|[1-9][0-9]|100)$ + regexFailureMessage: You must enter a percentage between 0 and 100. + helpLink: zeek + advanced: True + MailHostUpDown: + description: >- + Set to 1 to send email when a Zeek node changes between the up and down states. + Note that this setting only sends email and the Zeek container does not include a mail program, + so it currently has no visible effect. + regex: ^[01]$ + regexFailureMessage: You must enter 0 or 1. + helpLink: zeek + advanced: True policy: custom: filters: diff --git a/salt/zeek/tools/sbin/so-zeek-cron b/salt/zeek/tools/sbin/so-zeek-cron new file mode 100755 index 000000000..07399f55a --- /dev/null +++ b/salt/zeek/tools/sbin/so-zeek-cron @@ -0,0 +1,24 @@ +#!/bin/bash + +# Copyright Security Onion Solutions LLC and/or licensed to Security Onion Solutions LLC under one +# or more contributor license agreements. Licensed under the Elastic License 2.0 as shown at +# https://securityonion.net/license; you may not use this file except in compliance with the +# Elastic License 2.0. + +# Run zeekctl's periodic maintenance tasks. This is what actually enforces +# LogExpireInterval, StatsLogExpireInterval and CrashExpireInterval - without a periodic +# 'zeekctl cron' those settings are inert no matter what they are set to. + +# This also restarts any node that died unexpectedly, and marks it crashed so a crash report +# is produced. That is upstream's default cron behavior and it recovers a single node in +# place. The beacon in salt/_beacons/zeek.py is the only other recovery path, it is disabled +# by default (healthcheck:enabled), and it removes and recreates the whole container, so +# letting zeekctl handle a single dead worker avoids the heavier restart. + +if ! docker ps --filter name=so-zeek --format '{{.Names}}' | grep -q '^so-zeek$'; then + exit 0 +fi + +# Run as the zeek user so the stats logs and zeekctl-config.sh this writes stay owned by +# uid 937 rather than root. +docker exec so-zeek runuser -l zeek -c '/opt/zeek/bin/zeekctl cron' From 2663ca87a2f3c77f6b0098ee30986435c2086bea Mon Sep 17 00:00:00 2001 From: Josh Patterson Date: Fri, 14 Aug 2026 09:19:11 -0400 Subject: [PATCH 2/2] Mark the mail-only zeekctl settings read only MailTo, MailConnectionSummary and MailHostUpDown do nothing but send mail, and the Zeek container has no mail program, so nothing they control can happen. Mark them read only rather than offering knobs in SOC that cannot take effect. MailConnectionSummary only gates the emailed copy; the connection summary is generated and archived either way. MailTo also feeds Notice::mail_dest, but Security Onion never enables the notice email action, so that half is inert too. MailHostUpDown gates only the notification text - host status detection, the plugin hook and the stored state all run regardless. MinDiskSpace stays editable. It is not mail only: setting it to 0 skips the disk space check entirely, and the warning it produces is not emailed but does appear in the output of "zeekctl cron". Correct its description, and MailHostUpDown's, which both claimed these settings have no visible effect. --- salt/zeek/soc_zeek.yaml | 36 ++++++++++++++++++++++++++++-------- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/salt/zeek/soc_zeek.yaml b/salt/zeek/soc_zeek.yaml index c03203623..52934b044 100644 --- a/salt/zeek/soc_zeek.yaml +++ b/salt/zeek/soc_zeek.yaml @@ -87,23 +87,43 @@ zeek: advanced: True MinDiskSpace: description: >- - Percentage of free disk space below which ZeekControl reports a warning, or 0 to disable the check. - Note that this setting only sends email and the Zeek container does not include a mail program, - so it currently has no visible effect. It never deletes anything - disk based cleanup is handled - separately by so-sensor-clean. + Percentage of free disk space below which ZeekControl reports a warning, or 0 to disable the check + entirely. The Zeek container does not include a mail program, so the warning is not emailed - it + appears in the output of "zeekctl cron" instead. This setting never deletes anything - cleanup based + on disk usage is handled separately by so-sensor-clean. regex: ^([0-9]|[1-9][0-9]|100)$ regexFailureMessage: You must enter a percentage between 0 and 100. helpLink: zeek advanced: True - MailHostUpDown: + MailTo: description: >- - Set to 1 to send email when a Zeek node changes between the up and down states. - Note that this setting only sends email and the Zeek container does not include a mail program, - so it currently has no visible effect. + Address that ZeekControl would send mail to, covering cron output and crash reports, and the address + Zeek's notice framework would use. The Zeek container does not include a mail program, and Security + Onion never enables the notice email action, so no mail is sent and this address is unused. It is + read only for that reason. + helpLink: zeek + advanced: True + readonly: True + MailConnectionSummary: + description: >- + Set to 1 to email the hourly connection summary. This only controls the emailed copy - the summary is + generated and archived with the other Zeek logs either way. The Zeek container does not include a mail + program, so no mail is sent and this setting has no effect. It is read only for that reason. regex: ^[01]$ regexFailureMessage: You must enter 0 or 1. helpLink: zeek advanced: True + readonly: True + MailHostUpDown: + description: >- + Set to 1 to report when a Zeek node changes between the up and down states. The Zeek container does + not include a mail program, so this notification cannot be emailed. It is read only for that reason. + Host status detection still runs regardless of this setting - only the notification is affected. + regex: ^[01]$ + regexFailureMessage: You must enter 0 or 1. + helpLink: zeek + advanced: True + readonly: True policy: custom: filters: