101 lines
3.4 KiB
Bash
101 lines
3.4 KiB
Bash
|
|
#!/bin/bash
|
||
|
|
# =============================================================
|
||
|
|
# CrowdSec Local Attack Notifier
|
||
|
|
# Host: NAS16 (192.168.150.40)
|
||
|
|
# Target: CrowdSec LAPI on HAS (192.168.150.30:8080)
|
||
|
|
# Schedule: Every 5 minutes via OMV Scheduled Jobs
|
||
|
|
#
|
||
|
|
# Local (crowdsec origin) decisions are appended to:
|
||
|
|
# /var/log/crowdsec-notifier/local_pending.json
|
||
|
|
# and batched into a 4-hour digest by cs_local_digest.sh.
|
||
|
|
#
|
||
|
|
# CAPI decisions continue to be appended to capi_digest.json
|
||
|
|
# and sent as a midnight summary by cs_digest.sh (unchanged).
|
||
|
|
# =============================================================
|
||
|
|
|
||
|
|
LAPI_URL="http://192.168.150.30:8080"
|
||
|
|
API_KEY="K1nZ5TYeyl18adqw7+dop/po9gHZNQvsuLz78lla/34"
|
||
|
|
|
||
|
|
STARTUP_FLAG="/var/log/crowdsec-notifier/stream_initialized.flag"
|
||
|
|
LOCAL_PENDING="/var/log/crowdsec-notifier/local_pending.json"
|
||
|
|
CAPI_DIGEST="/var/log/crowdsec-notifier/capi_digest.json"
|
||
|
|
LOG_FILE="/var/log/crowdsec-notifier/notifier.log"
|
||
|
|
|
||
|
|
mkdir -p /var/log/crowdsec-notifier
|
||
|
|
touch "$CAPI_DIGEST"
|
||
|
|
touch "$LOCAL_PENDING"
|
||
|
|
|
||
|
|
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" >> "$LOG_FILE"; }
|
||
|
|
|
||
|
|
log "--- cs_notifier run start ---"
|
||
|
|
|
||
|
|
# --- First run: initialize stream cursor silently ---
|
||
|
|
if [[ ! -f "$STARTUP_FLAG" ]]; then
|
||
|
|
log "First run — initializing stream cursor. No emails will be sent."
|
||
|
|
INIT_RESPONSE=$(curl -s --max-time 60 \
|
||
|
|
-H "X-Api-Key: $API_KEY" \
|
||
|
|
"${LAPI_URL}/v1/decisions/stream?startup=true")
|
||
|
|
|
||
|
|
if [[ -z "$INIT_RESPONSE" ]]; then
|
||
|
|
log "ERROR: Empty response from LAPI during startup. Will retry next run."
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
NEW_COUNT=$(echo "$INIT_RESPONSE" | python3 -c "
|
||
|
|
import sys, json
|
||
|
|
data = json.load(sys.stdin)
|
||
|
|
print(len(data.get('new') or []))
|
||
|
|
" 2>/dev/null)
|
||
|
|
|
||
|
|
log "Stream cursor initialized. Skipped $NEW_COUNT existing decisions. Ready for live monitoring."
|
||
|
|
touch "$STARTUP_FLAG"
|
||
|
|
log "--- cs_notifier run complete (init) ---"
|
||
|
|
exit 0
|
||
|
|
fi
|
||
|
|
|
||
|
|
# --- Normal run: fetch only new decisions since last call ---
|
||
|
|
RESPONSE=$(curl -s --max-time 30 \
|
||
|
|
-H "X-Api-Key: $API_KEY" \
|
||
|
|
"${LAPI_URL}/v1/decisions/stream?startup=false")
|
||
|
|
|
||
|
|
HTTP_CHECK=$(echo "$RESPONSE" | python3 -c "import sys,json; json.load(sys.stdin); print('ok')" 2>/dev/null)
|
||
|
|
if [[ "$HTTP_CHECK" != "ok" ]]; then
|
||
|
|
log "ERROR: Invalid response from LAPI stream endpoint"
|
||
|
|
exit 1
|
||
|
|
fi
|
||
|
|
|
||
|
|
# --- Parse and route new decisions ---
|
||
|
|
NEW_LOCAL_COUNT=0
|
||
|
|
NEW_CAPI_COUNT=0
|
||
|
|
|
||
|
|
while IFS= read -r decision; do
|
||
|
|
[[ -z "$decision" ]] && continue
|
||
|
|
ORIGIN=$(echo "$decision" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('origin',''))" 2>/dev/null)
|
||
|
|
|
||
|
|
if [[ "$ORIGIN" == "crowdsec" ]]; then
|
||
|
|
# Append to pending local digest — cs_local_digest.sh will send every 4 hours
|
||
|
|
echo "$decision" >> "$LOCAL_PENDING"
|
||
|
|
NEW_LOCAL_COUNT=$((NEW_LOCAL_COUNT + 1))
|
||
|
|
elif [[ "$ORIGIN" == "CAPI" ]]; then
|
||
|
|
# Append to CAPI digest — cs_digest.sh will send at midnight
|
||
|
|
echo "$decision" >> "$CAPI_DIGEST"
|
||
|
|
NEW_CAPI_COUNT=$((NEW_CAPI_COUNT + 1))
|
||
|
|
fi
|
||
|
|
|
||
|
|
done < <(echo "$RESPONSE" | python3 -c "
|
||
|
|
import sys, json
|
||
|
|
data = json.load(sys.stdin)
|
||
|
|
new = data.get('new') or []
|
||
|
|
for item in new:
|
||
|
|
print(json.dumps(item))
|
||
|
|
")
|
||
|
|
|
||
|
|
CAPI_TODAY=$(wc -l < "$CAPI_DIGEST" 2>/dev/null | tr -d ' ')
|
||
|
|
CAPI_TODAY=${CAPI_TODAY:-0}
|
||
|
|
LOCAL_PENDING_COUNT=$(wc -l < "$LOCAL_PENDING" 2>/dev/null | tr -d ' ')
|
||
|
|
LOCAL_PENDING_COUNT=${LOCAL_PENDING_COUNT:-0}
|
||
|
|
|
||
|
|
log "New local: $NEW_LOCAL_COUNT (pending total: $LOCAL_PENDING_COUNT) | New CAPI: $NEW_CAPI_COUNT | CAPI today: $CAPI_TODAY"
|
||
|
|
|
||
|
|
log "--- cs_notifier run complete ---"
|