Add support for suricata rules load status

This commit is contained in:
DefensiveDepth
2025-12-04 12:26:13 -05:00
parent f15a39c153
commit 9304513ce8
5 changed files with 84 additions and 0 deletions

View File

@@ -178,6 +178,14 @@ so-suricata-eve-clean:
- template: jinja
- source: salt://suricata/cron/so-suricata-eve-clean
so-suricata-rulestats:
file.managed:
- name: /usr/sbin/so-suricata-rulestats
- user: root
- group: root
- mode: 755
- source: salt://suricata/cron/so-suricata-rulestats
{% else %}
{{sls}}_state_not_allowed:

View File

@@ -0,0 +1,30 @@
#!/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.
# Query Suricata for ruleset stats and reload time, write to JSON file for Telegraf to consume
OUTFILE="/opt/so/log/suricata/rulestats.json"
SURICATASC="docker exec so-suricata /opt/suricata/bin/suricatasc"
SOCKET="/var/run/suricata/suricata-command.socket"
query() {
timeout 10 $SURICATASC -c "$1" "$SOCKET" 2>/dev/null
}
STATS=$(query "ruleset-stats")
RELOAD=$(query "ruleset-reload-time")
if echo "$STATS" | jq -e '.return == "OK"' > /dev/null 2>&1; then
LOADED=$(echo "$STATS" | jq -r '.message[0].rules_loaded')
FAILED=$(echo "$STATS" | jq -r '.message[0].rules_failed')
LAST_RELOAD=$(echo "$RELOAD" | jq -r '.message[0].last_reload')
jq -n --argjson loaded "$LOADED" --argjson failed "$FAILED" --arg reload "$LAST_RELOAD" \
'{rules_loaded: $loaded, rules_failed: $failed, last_reload: $reload, return: "OK"}' > "$OUTFILE"
else
echo '{"return":"FAIL"}' > "$OUTFILE"
fi

View File

@@ -90,6 +90,18 @@ clean_suricata_eve_files:
- month: '*'
- dayweek: '*'
# Add rulestats cron - runs every minute to query Suricata for rule load status
suricata_rulestats:
cron.present:
- name: /usr/sbin/so-suricata-rulestats > /dev/null 2>&1
- identifier: suricata_rulestats
- user: root
- minute: '*'
- hour: '*'
- daymonth: '*'
- month: '*'
- dayweek: '*'
{% else %}
{{sls}}_state_not_allowed:

View File

@@ -21,6 +21,7 @@ telegraf:
- sostatus.sh
- stenoloss.sh
- suriloss.sh
- surirules.sh
- zeekcaptureloss.sh
- zeekloss.sh
standalone:
@@ -36,6 +37,7 @@ telegraf:
- sostatus.sh
- stenoloss.sh
- suriloss.sh
- surirules.sh
- zeekcaptureloss.sh
- zeekloss.sh
- features.sh
@@ -81,6 +83,7 @@ telegraf:
- sostatus.sh
- stenoloss.sh
- suriloss.sh
- surirules.sh
- zeekcaptureloss.sh
- zeekloss.sh
- features.sh
@@ -95,6 +98,7 @@ telegraf:
- sostatus.sh
- stenoloss.sh
- suriloss.sh
- surirules.sh
- zeekcaptureloss.sh
- zeekloss.sh
idh:

View File

@@ -0,0 +1,30 @@
#!/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.
# Read Suricata ruleset stats from JSON file written by so-suricata-rulestats cron job
# JSON format: {"rules_loaded":45879,"rules_failed":1,"last_reload":"2025-12-04T14:10:57+0000","return":"OK"}
# or on failure: {"return":"FAIL"}
# if this script isn't already running
if [[ ! "`pidof -x $(basename $0) -o %PPID`" ]]; then
STATSFILE="/var/log/suricata/rulestats.json"
# Check file exists, is less than 90 seconds old, and has valid data
if [ -f "$STATSFILE" ] && [ $(($(date +%s) - $(stat -c %Y "$STATSFILE"))) -lt 90 ] && jq -e '.return == "OK" and .rules_loaded != null and .rules_failed != null' "$STATSFILE" > /dev/null 2>&1; then
LOADED=$(jq -r '.rules_loaded' "$STATSFILE")
FAILED=$(jq -r '.rules_failed' "$STATSFILE")
RELOAD_TIME=$(jq -r '.last_reload // ""' "$STATSFILE")
echo "surirules loaded=${LOADED}i,failed=${FAILED}i,reload_time=\"${RELOAD_TIME}\",status=\"ok\""
else
echo "surirules loaded=0i,failed=0i,reload_time=\"\",status=\"unknown\""
fi
fi
exit 0