secubox-openwrt/package/secubox/luci-app-wazuh/root/usr/libexec/rpcd/luci.wazuh
CyberMind-FR b1c34021db feat(wazuh): Add LuCI dashboard for Wazuh SIEM integration
Create luci-app-wazuh package with unified security monitoring dashboard
inspired by SysWarden's layered defense model:

- 4 views: Overview, Alerts, File Integrity, Agents
- RPCD handler with 12 API methods for status, alerts, FIM, agent control
- SysWarden-style 4-layer security visualization:
  - Layer 1: Vortex Firewall + nftables (kernel-level)
  - Layer 2: CrowdSec + Bouncer (IPS)
  - Layer 3: Wazuh Manager (SIEM/XDR)
  - Layer 4: mitmproxy + HAProxy (WAF)
- CrowdSec integration for threat correlation
- Real-time polling and auto-refresh
- Simplified printf-based JSON output (avoids jshn segfault)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-14 14:45:05 +01:00

388 lines
15 KiB
Bash

#!/bin/sh
# SecuBox Wazuh LuCI RPCD Handler
# Provides API for Wazuh dashboard
WAZUH_DIR="/var/ossec"
WAZUH_MANAGER_CONTAINER="wazuh"
WAZUH_AGENT_CONTAINER="wazuh-agent"
MANAGER_IP="192.168.255.50"
# ============================================
# CrowdSec Integration
# ============================================
get_crowdsec_correlation() {
local crowdsec_running="false"
local decisions=0
local wazuh_parser="false"
if pgrep crowdsec >/dev/null 2>&1; then
crowdsec_running="true"
decisions=$(cscli decisions list -o json 2>/dev/null | grep -c '"id"' 2>/dev/null || echo 0)
fi
if [ -f "/etc/crowdsec/parsers/s01-parse/wazuh.yaml" ]; then
wazuh_parser="true"
fi
printf '{"crowdsec_running":%s,"active_decisions":%d,"wazuh_parser_enabled":%s}\n' \
"$crowdsec_running" "$decisions" "$wazuh_parser"
}
# ============================================
# Agent Status
# ============================================
get_agent_status() {
local agent_running="false"
local agent_connected="false"
local agent_id=""
local agent_name=""
local manager_ip=""
if lxc-info -n "$WAZUH_AGENT_CONTAINER" -s 2>/dev/null | grep -q RUNNING; then
agent_running="true"
if lxc-attach -n "$WAZUH_AGENT_CONTAINER" -- pgrep -f wazuh-agentd >/dev/null 2>&1; then
agent_connected="true"
local client_keys=$(lxc-attach -n "$WAZUH_AGENT_CONTAINER" -- cat "$WAZUH_DIR/etc/client.keys" 2>/dev/null | head -1)
if [ -n "$client_keys" ]; then
agent_id=$(echo "$client_keys" | awk '{print $1}')
agent_name=$(echo "$client_keys" | awk '{print $2}')
fi
fi
fi
manager_ip=$(uci -q get wazuh.main.manager_ip 2>/dev/null || echo "$MANAGER_IP")
printf '{"running":%s,"connected":%s,"agent_id":"%s","agent_name":"%s","manager_ip":"%s","container":"%s"}\n' \
"$agent_running" "$agent_connected" "$agent_id" "$agent_name" "$manager_ip" "$WAZUH_AGENT_CONTAINER"
}
# ============================================
# Manager Status
# ============================================
get_manager_status() {
local manager_running="false"
local indexer_running="false"
local dashboard_running="false"
local cluster_health="unknown"
local agents_total=0
local agents_active=0
if lxc-info -n "$WAZUH_MANAGER_CONTAINER" -s 2>/dev/null | grep -q RUNNING; then
manager_running="true"
if lxc-attach -n "$WAZUH_MANAGER_CONTAINER" -- netstat -tlnp 2>/dev/null | grep -q ":9200 "; then
indexer_running="true"
cluster_health=$(lxc-attach -n "$WAZUH_MANAGER_CONTAINER" -- curl -sk -u admin:admin "https://127.0.0.1:9200/_cluster/health" 2>/dev/null | grep -o '"status":"[^"]*"' | cut -d'"' -f4 || echo "unknown")
fi
if lxc-attach -n "$WAZUH_MANAGER_CONTAINER" -- netstat -tlnp 2>/dev/null | grep -q ":5601 "; then
dashboard_running="true"
fi
local agent_list=$(lxc-attach -n "$WAZUH_MANAGER_CONTAINER" -- /var/ossec/bin/agent_control -l 2>/dev/null)
agents_total=$(echo "$agent_list" | grep -c "ID:" 2>/dev/null || echo 0)
agents_active=$(echo "$agent_list" | grep -c "Active" 2>/dev/null || echo 0)
fi
printf '{"running":%s,"indexer_running":%s,"dashboard_running":%s,"cluster_health":"%s","agents_total":%d,"agents_active":%d,"dashboard_url":"https://wazuh.gk2.secubox.in","container":"%s"}\n' \
"$manager_running" "$indexer_running" "$dashboard_running" "$cluster_health" "$agents_total" "$agents_active" "$WAZUH_MANAGER_CONTAINER"
}
# ============================================
# Alert Summary
# ============================================
get_alert_summary() {
local critical=0
local high=0
local medium=0
local low=0
local total=0
if lxc-info -n "$WAZUH_MANAGER_CONTAINER" -s 2>/dev/null | grep -q RUNNING; then
# Count alerts by severity using simple grep
local alerts_file="/var/ossec/logs/alerts/alerts.json"
critical=$(lxc-attach -n "$WAZUH_MANAGER_CONTAINER" -- sh -c "tail -n 1000 $alerts_file 2>/dev/null | grep -c '\"level\":1[2-5]' 2>/dev/null" || echo 0)
high=$(lxc-attach -n "$WAZUH_MANAGER_CONTAINER" -- sh -c "tail -n 1000 $alerts_file 2>/dev/null | grep -c '\"level\":[9]' 2>/dev/null" || echo 0)
medium=$(lxc-attach -n "$WAZUH_MANAGER_CONTAINER" -- sh -c "tail -n 1000 $alerts_file 2>/dev/null | grep -c '\"level\":[5-8]' 2>/dev/null" || echo 0)
low=$(lxc-attach -n "$WAZUH_MANAGER_CONTAINER" -- sh -c "tail -n 1000 $alerts_file 2>/dev/null | grep -c '\"level\":[1-4]' 2>/dev/null" || echo 0)
# Ensure values are numeric
critical=${critical:-0}
high=${high:-0}
medium=${medium:-0}
low=${low:-0}
# Strip any non-numeric chars
critical=$(echo "$critical" | tr -cd '0-9')
high=$(echo "$high" | tr -cd '0-9')
medium=$(echo "$medium" | tr -cd '0-9')
low=$(echo "$low" | tr -cd '0-9')
[ -z "$critical" ] && critical=0
[ -z "$high" ] && high=0
[ -z "$medium" ] && medium=0
[ -z "$low" ] && low=0
total=$((critical + high + medium + low))
fi
printf '{"critical":%d,"high":%d,"medium":%d,"low":%d,"total":%d}\n' \
"$critical" "$high" "$medium" "$low" "$total"
}
# ============================================
# Alerts List
# ============================================
get_alerts() {
local count="${1:-20}"
local level="${2:-0}"
printf '{"alerts":['
if lxc-info -n "$WAZUH_MANAGER_CONTAINER" -s 2>/dev/null | grep -q RUNNING; then
local first=1
lxc-attach -n "$WAZUH_MANAGER_CONTAINER" -- tail -n "$count" /var/ossec/logs/alerts/alerts.json 2>/dev/null | while read -r line; do
if [ -n "$line" ]; then
local rule_level=$(echo "$line" | grep -oE '"level":[0-9]+' | head -1 | cut -d':' -f2)
if [ -n "$rule_level" ] && [ "$rule_level" -ge "$level" ] 2>/dev/null; then
local timestamp=$(echo "$line" | grep -oE '"timestamp":"[^"]*"' | head -1 | cut -d'"' -f4)
local rule_id=$(echo "$line" | grep -oE '"id":"[0-9]+"' | head -1 | cut -d'"' -f4)
local rule_desc=$(echo "$line" | grep -oE '"description":"[^"]*"' | head -1 | cut -d'"' -f4 | sed 's/"/\\"/g')
local agent_name=$(echo "$line" | grep -oE '"name":"[^"]*"' | head -1 | cut -d'"' -f4)
local src_ip=$(echo "$line" | grep -oE '"srcip":"[^"]*"' | head -1 | cut -d'"' -f4)
[ $first -eq 0 ] && printf ','
first=0
printf '{"timestamp":"%s","rule_level":%s,"rule_id":"%s","rule_description":"%s","agent_name":"%s","src_ip":"%s"}' \
"$timestamp" "$rule_level" "$rule_id" "$rule_desc" "$agent_name" "$src_ip"
fi
fi
done
fi
printf ']}\n'
}
# ============================================
# FIM Functions
# ============================================
get_fim_events() {
local count="${1:-50}"
printf '{"events":['
if lxc-info -n "$WAZUH_MANAGER_CONTAINER" -s 2>/dev/null | grep -q RUNNING; then
local first=1
lxc-attach -n "$WAZUH_MANAGER_CONTAINER" -- grep -E 'syscheck' /var/ossec/logs/alerts/alerts.json 2>/dev/null | tail -n "$count" | while read -r line; do
if [ -n "$line" ]; then
local timestamp=$(echo "$line" | grep -oE '"timestamp":"[^"]*"' | head -1 | cut -d'"' -f4)
local path=$(echo "$line" | grep -oE '"path":"[^"]*"' | head -1 | cut -d'"' -f4 | sed 's/"/\\"/g')
local event_type=$(echo "$line" | grep -oE '"event":"[^"]*"' | head -1 | cut -d'"' -f4)
[ $first -eq 0 ] && printf ','
first=0
printf '{"timestamp":"%s","path":"%s","event_type":"%s"}' \
"$timestamp" "$path" "$event_type"
fi
done
fi
printf ']}\n'
}
get_fim_config() {
printf '{"directories":["/etc/config","/etc/init.d","/usr/sbin","/usr/libexec/rpcd","/srv/haproxy/config","/etc/passwd","/etc/shadow"]}\n'
}
# ============================================
# Agent Management
# ============================================
list_agents() {
printf '{"agents":['
if lxc-info -n "$WAZUH_MANAGER_CONTAINER" -s 2>/dev/null | grep -q RUNNING; then
local first=1
lxc-attach -n "$WAZUH_MANAGER_CONTAINER" -- /var/ossec/bin/agent_control -l 2>/dev/null | grep "ID:" | while read -r line; do
local id=$(echo "$line" | sed 's/.*ID: \([0-9]*\),.*/\1/')
local name=$(echo "$line" | sed 's/.*Name: \([^,]*\),.*/\1/')
local ip=$(echo "$line" | sed 's/.*IP: \([^,]*\),.*/\1/')
local status=$(echo "$line" | sed 's/.*IP: [^,]*, \(.*\)/\1/' | tr -d ' ')
[ $first -eq 0 ] && printf ','
first=0
printf '{"id":"%s","name":"%s","ip":"%s","status":"%s"}' \
"$id" "$name" "$ip" "$status"
done
fi
printf ']}\n'
}
# ============================================
# Service Control
# ============================================
start_agent() {
local success="false"
if lxc-info -n "$WAZUH_AGENT_CONTAINER" -s 2>/dev/null | grep -q RUNNING; then
lxc-attach -n "$WAZUH_AGENT_CONTAINER" -- /var/ossec/bin/wazuh-control start >/dev/null 2>&1
success="true"
fi
printf '{"success":%s}\n' "$success"
}
stop_agent() {
local success="false"
if lxc-info -n "$WAZUH_AGENT_CONTAINER" -s 2>/dev/null | grep -q RUNNING; then
lxc-attach -n "$WAZUH_AGENT_CONTAINER" -- /var/ossec/bin/wazuh-control stop >/dev/null 2>&1
success="true"
fi
printf '{"success":%s}\n' "$success"
}
restart_agent() {
local success="false"
if lxc-info -n "$WAZUH_AGENT_CONTAINER" -s 2>/dev/null | grep -q RUNNING; then
lxc-attach -n "$WAZUH_AGENT_CONTAINER" -- /var/ossec/bin/wazuh-control restart >/dev/null 2>&1
success="true"
fi
printf '{"success":%s}\n' "$success"
}
# ============================================
# Overview / Dashboard Data
# ============================================
get_overview() {
local agent_running="false"
local agent_connected="false"
local manager_running="false"
local indexer_status="unknown"
local dashboard_accessible="false"
local critical=0
local high=0
local total=0
local crowdsec_integrated="false"
# Agent status
if lxc-info -n "$WAZUH_AGENT_CONTAINER" -s 2>/dev/null | grep -q RUNNING; then
agent_running="true"
if lxc-attach -n "$WAZUH_AGENT_CONTAINER" -- pgrep -f wazuh-agentd >/dev/null 2>&1; then
agent_connected="true"
fi
fi
# Manager status
if lxc-info -n "$WAZUH_MANAGER_CONTAINER" -s 2>/dev/null | grep -q RUNNING; then
manager_running="true"
indexer_status=$(lxc-attach -n "$WAZUH_MANAGER_CONTAINER" -- curl -sk -u admin:admin "https://127.0.0.1:9200/_cluster/health" 2>/dev/null | grep -o '"status":"[^"]*"' | cut -d'"' -f4 || echo "unknown")
[ -z "$indexer_status" ] && indexer_status="unknown"
if lxc-attach -n "$WAZUH_MANAGER_CONTAINER" -- netstat -tlnp 2>/dev/null | grep -q ":5601 "; then
dashboard_accessible="true"
fi
# Alert counts - run directly in container to avoid variable issues
local alerts_file="/var/ossec/logs/alerts/alerts.json"
critical=$(lxc-attach -n "$WAZUH_MANAGER_CONTAINER" -- sh -c "tail -n 500 $alerts_file 2>/dev/null | grep -c '\"level\":1[2-5]' 2>/dev/null" || echo 0)
high=$(lxc-attach -n "$WAZUH_MANAGER_CONTAINER" -- sh -c "tail -n 500 $alerts_file 2>/dev/null | grep -c '\"level\":[9]' 2>/dev/null" || echo 0)
total=$(lxc-attach -n "$WAZUH_MANAGER_CONTAINER" -- sh -c "tail -n 500 $alerts_file 2>/dev/null | wc -l 2>/dev/null" || echo 0)
# Strip non-numeric chars
critical=$(echo "$critical" | tr -cd '0-9')
high=$(echo "$high" | tr -cd '0-9')
total=$(echo "$total" | tr -cd '0-9')
[ -z "$critical" ] && critical=0
[ -z "$high" ] && high=0
[ -z "$total" ] && total=0
fi
# CrowdSec
if pgrep crowdsec >/dev/null 2>&1; then
crowdsec_integrated="true"
fi
printf '{"agent":{"running":%s,"connected":%s},"manager":{"running":%s,"indexer_status":"%s","dashboard_accessible":%s},"alerts":{"critical":%d,"high":%d,"total":%d},"crowdsec_integrated":%s}\n' \
"$agent_running" "$agent_connected" "$manager_running" "$indexer_status" "$dashboard_accessible" "$critical" "$high" "$total" "$crowdsec_integrated"
}
# ============================================
# RPCD Interface
# ============================================
case "$1" in
list)
cat <<'EOF'
{
"get_overview": {},
"get_agent_status": {},
"get_manager_status": {},
"get_alerts": {"count": 20, "level": 0},
"get_alert_summary": {},
"get_fim_events": {"count": 50},
"get_fim_config": {},
"list_agents": {},
"get_crowdsec_correlation": {},
"start_agent": {},
"stop_agent": {},
"restart_agent": {}
}
EOF
;;
call)
case "$2" in
get_overview)
get_overview
;;
get_agent_status)
get_agent_status
;;
get_manager_status)
get_manager_status
;;
get_alerts)
read -r input
count=$(echo "$input" | grep -oE '"count":[0-9]+' | cut -d':' -f2 || echo 20)
level=$(echo "$input" | grep -oE '"level":[0-9]+' | cut -d':' -f2 || echo 0)
[ -z "$count" ] && count=20
[ -z "$level" ] && level=0
get_alerts "$count" "$level"
;;
get_alert_summary)
get_alert_summary
;;
get_fim_events)
read -r input
count=$(echo "$input" | grep -oE '"count":[0-9]+' | cut -d':' -f2 || echo 50)
[ -z "$count" ] && count=50
get_fim_events "$count"
;;
get_fim_config)
get_fim_config
;;
list_agents)
list_agents
;;
get_crowdsec_correlation)
get_crowdsec_correlation
;;
start_agent)
start_agent
;;
stop_agent)
stop_agent
;;
restart_agent)
restart_agent
;;
*)
echo '{"error": "Unknown method"}'
;;
esac
;;
*)
echo '{"error": "Unknown command"}'
;;
esac