fix: CAPI registration with stale credentials cleanup
- repair_lapi() now removes stale online_api_credentials.yaml and retries - New repair_capi() function for dedicated CAPI repair - console_enroll() handles CAPI credential cleanup before retry - Added repairCapi API method in frontend - Bump luci-app-crowdsec-dashboard to 0.7.0-r20 - Add openwrt-luci-bf.yaml scenario for LuCI brute force detection - Add secubox-auth-acquis.yaml acquisition config Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
19f903c0c9
commit
c2ea22bcab
@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk
|
||||
|
||||
PKG_NAME:=luci-app-crowdsec-dashboard
|
||||
PKG_VERSION:=0.7.0
|
||||
PKG_RELEASE:=19
|
||||
PKG_RELEASE:=20
|
||||
PKG_ARCH:=all
|
||||
|
||||
PKG_LICENSE:=Apache-2.0
|
||||
|
||||
@ -197,6 +197,12 @@ var callRepairLapi = rpc.declare({
|
||||
expect: { }
|
||||
});
|
||||
|
||||
var callRepairCapi = rpc.declare({
|
||||
object: 'luci.crowdsec-dashboard',
|
||||
method: 'repair_capi',
|
||||
expect: { }
|
||||
});
|
||||
|
||||
var callResetWizard = rpc.declare({
|
||||
object: 'luci.crowdsec-dashboard',
|
||||
method: 'reset_wizard',
|
||||
@ -403,6 +409,7 @@ return baseclass.extend({
|
||||
checkWizardNeeded: callCheckWizardNeeded,
|
||||
getWizardState: callWizardState,
|
||||
repairLapi: callRepairLapi,
|
||||
repairCapi: callRepairCapi,
|
||||
resetWizard: callResetWizard,
|
||||
|
||||
// Console Methods
|
||||
|
||||
@ -1120,18 +1120,41 @@ repair_lapi() {
|
||||
|
||||
# Step 13: Register with CAPI (required for console enrollment)
|
||||
if [ "$lapi_ok" = "1" ] && [ -x "$CSCLI" ]; then
|
||||
local capi_creds="/etc/crowdsec/online_api_credentials.yaml"
|
||||
local capi_registered=0
|
||||
|
||||
# First attempt: try to register with existing credentials
|
||||
if run_with_timeout 15 "$CSCLI" capi register >/dev/null 2>&1; then
|
||||
capi_registered=1
|
||||
steps_done="${steps_done}CAPI registered; "
|
||||
else
|
||||
# CAPI registration may fail if already registered, which is OK
|
||||
# Check if CAPI is already working
|
||||
local capi_status=""
|
||||
capi_status=$(run_with_timeout 5 "$CSCLI" capi status 2>&1)
|
||||
if echo "$capi_status" | grep -qi "registered\|online"; then
|
||||
if echo "$capi_status" | grep -qi "You can successfully interact with Central API"; then
|
||||
capi_registered=1
|
||||
steps_done="${steps_done}CAPI OK; "
|
||||
else
|
||||
errors="${errors}CAPI not registered; "
|
||||
fi
|
||||
fi
|
||||
|
||||
# If CAPI still not working, try with fresh credentials
|
||||
if [ "$capi_registered" = "0" ] && [ -f "$capi_creds" ]; then
|
||||
secubox_log "CAPI registration failed, removing stale credentials and retrying..."
|
||||
rm -f "$capi_creds"
|
||||
steps_done="${steps_done}CAPI creds reset; "
|
||||
|
||||
# Retry registration with clean slate
|
||||
if run_with_timeout 15 "$CSCLI" capi register >/dev/null 2>&1; then
|
||||
capi_registered=1
|
||||
steps_done="${steps_done}CAPI re-registered; "
|
||||
else
|
||||
local capi_err=""
|
||||
capi_err=$(run_with_timeout 10 "$CSCLI" capi register 2>&1)
|
||||
errors="${errors}CAPI: ${capi_err}; "
|
||||
fi
|
||||
elif [ "$capi_registered" = "0" ]; then
|
||||
errors="${errors}CAPI not registered; "
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$lapi_ok" = "1" ]; then
|
||||
@ -1150,6 +1173,84 @@ repair_lapi() {
|
||||
json_dump
|
||||
}
|
||||
|
||||
# Repair CAPI - fix Central API registration issues
|
||||
repair_capi() {
|
||||
json_init
|
||||
local steps_done=""
|
||||
local errors=""
|
||||
local capi_creds="/etc/crowdsec/online_api_credentials.yaml"
|
||||
|
||||
secubox_log "Starting CAPI repair..."
|
||||
|
||||
# Check if CrowdSec and LAPI are running
|
||||
if ! pgrep crowdsec >/dev/null 2>&1; then
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "CrowdSec is not running. Start CrowdSec first."
|
||||
json_dump
|
||||
return
|
||||
fi
|
||||
|
||||
if ! run_with_timeout 5 "$CSCLI" lapi status >/dev/null 2>&1; then
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "LAPI is not available. Run LAPI repair first."
|
||||
json_dump
|
||||
return
|
||||
fi
|
||||
|
||||
# Check current CAPI status
|
||||
local capi_status=""
|
||||
capi_status=$(run_with_timeout 5 "$CSCLI" capi status 2>&1)
|
||||
if echo "$capi_status" | grep -qi "You can successfully interact with Central API"; then
|
||||
steps_done="${steps_done}CAPI already working; "
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "message" "CAPI is already connected"
|
||||
json_add_string "steps" "$steps_done"
|
||||
json_dump
|
||||
return
|
||||
fi
|
||||
|
||||
# Step 1: Backup and remove existing credentials
|
||||
if [ -f "$capi_creds" ]; then
|
||||
cp "$capi_creds" "${capi_creds}.bak" 2>/dev/null
|
||||
rm -f "$capi_creds"
|
||||
steps_done="${steps_done}Removed stale credentials; "
|
||||
fi
|
||||
|
||||
# Step 2: Register with CAPI
|
||||
local reg_output=""
|
||||
reg_output=$(run_with_timeout 20 "$CSCLI" capi register 2>&1)
|
||||
if [ $? -eq 0 ]; then
|
||||
steps_done="${steps_done}CAPI registered; "
|
||||
else
|
||||
# Check if error is about already registered
|
||||
if echo "$reg_output" | grep -qi "already registered"; then
|
||||
steps_done="${steps_done}Already registered; "
|
||||
else
|
||||
errors="${errors}Registration failed: ${reg_output}; "
|
||||
fi
|
||||
fi
|
||||
|
||||
# Step 3: Verify CAPI connection
|
||||
sleep 2
|
||||
capi_status=$(run_with_timeout 5 "$CSCLI" capi status 2>&1)
|
||||
if echo "$capi_status" | grep -qi "You can successfully interact with Central API"; then
|
||||
steps_done="${steps_done}CAPI connected; "
|
||||
json_add_boolean "success" 1
|
||||
json_add_string "message" "CAPI repaired successfully"
|
||||
json_add_string "steps" "$steps_done"
|
||||
secubox_log "CAPI repair successful: $steps_done"
|
||||
else
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "CAPI repair incomplete"
|
||||
json_add_string "steps" "$steps_done"
|
||||
json_add_string "errors" "$errors"
|
||||
json_add_string "capi_output" "$capi_status"
|
||||
secubox_log "CAPI repair failed: $errors"
|
||||
fi
|
||||
|
||||
json_dump
|
||||
}
|
||||
|
||||
# Reset wizard - clean up for fresh start
|
||||
reset_wizard() {
|
||||
json_init
|
||||
@ -1261,23 +1362,38 @@ console_enroll() {
|
||||
# Step 0: Ensure CAPI is registered (prerequisite for console enrollment)
|
||||
local capi_ok=0
|
||||
local capi_status=""
|
||||
local capi_creds="/etc/crowdsec/online_api_credentials.yaml"
|
||||
|
||||
capi_status=$(run_with_timeout 5 "$CSCLI" capi status 2>&1)
|
||||
if echo "$capi_status" | grep -qi "registered\|online"; then
|
||||
if echo "$capi_status" | grep -qi "You can successfully interact with Central API"; then
|
||||
capi_ok=1
|
||||
secubox_log "CAPI already connected"
|
||||
else
|
||||
# Try to register with CAPI
|
||||
secubox_log "CAPI not registered, attempting registration..."
|
||||
secubox_log "CAPI not connected, attempting registration..."
|
||||
if run_with_timeout 15 "$CSCLI" capi register >/dev/null 2>&1; then
|
||||
capi_ok=1
|
||||
secubox_log "CAPI registration successful"
|
||||
else
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "CAPI registration failed. Please run LAPI repair first."
|
||||
json_dump
|
||||
return
|
||||
# If registration fails and credentials exist, try with fresh credentials
|
||||
if [ -f "$capi_creds" ]; then
|
||||
secubox_log "CAPI registration failed, removing stale credentials..."
|
||||
rm -f "$capi_creds"
|
||||
if run_with_timeout 15 "$CSCLI" capi register >/dev/null 2>&1; then
|
||||
capi_ok=1
|
||||
secubox_log "CAPI re-registration successful"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
if [ "$capi_ok" = "0" ]; then
|
||||
json_add_boolean "success" 0
|
||||
json_add_string "error" "CAPI registration failed. Please run LAPI repair first."
|
||||
json_dump
|
||||
return
|
||||
fi
|
||||
|
||||
# Build enroll command
|
||||
local enroll_cmd="run_cscli console enroll $key"
|
||||
if [ -n "$name" ]; then
|
||||
@ -1954,7 +2070,7 @@ remove_hub_item() {
|
||||
# Main dispatcher
|
||||
case "$1" in
|
||||
list)
|
||||
echo '{"decisions":{},"alerts":{"limit":"number"},"metrics":{},"bouncers":{},"machines":{},"hub":{},"status":{},"ban":{"ip":"string","duration":"string","reason":"string"},"unban":{"ip":"string"},"stats":{},"seccubox_logs":{},"collect_debug":{},"waf_status":{},"metrics_config":{},"configure_metrics":{"enable":"string"},"collections":{},"install_collection":{"collection":"string"},"remove_collection":{"collection":"string"},"update_hub":{},"register_bouncer":{"bouncer_name":"string"},"delete_bouncer":{"bouncer_name":"string"},"firewall_bouncer_status":{},"control_firewall_bouncer":{"action":"string"},"firewall_bouncer_config":{},"update_firewall_bouncer_config":{"key":"string","value":"string"},"nftables_stats":{},"check_wizard_needed":{},"wizard_state":{},"repair_lapi":{},"reset_wizard":{},"console_status":{},"console_enroll":{"key":"string","name":"string"},"console_disable":{},"service_control":{"action":"string"},"configure_acquisition":{"syslog_enabled":"string","firewall_enabled":"string","ssh_enabled":"string","http_enabled":"string","syslog_path":"string"},"acquisition_config":{},"acquisition_metrics":{},"health_check":{},"capi_metrics":{},"hub_available":{},"install_hub_item":{"item_type":"string","item_name":"string"},"remove_hub_item":{"item_type":"string","item_name":"string"}}'
|
||||
echo '{"decisions":{},"alerts":{"limit":"number"},"metrics":{},"bouncers":{},"machines":{},"hub":{},"status":{},"ban":{"ip":"string","duration":"string","reason":"string"},"unban":{"ip":"string"},"stats":{},"seccubox_logs":{},"collect_debug":{},"waf_status":{},"metrics_config":{},"configure_metrics":{"enable":"string"},"collections":{},"install_collection":{"collection":"string"},"remove_collection":{"collection":"string"},"update_hub":{},"register_bouncer":{"bouncer_name":"string"},"delete_bouncer":{"bouncer_name":"string"},"firewall_bouncer_status":{},"control_firewall_bouncer":{"action":"string"},"firewall_bouncer_config":{},"update_firewall_bouncer_config":{"key":"string","value":"string"},"nftables_stats":{},"check_wizard_needed":{},"wizard_state":{},"repair_lapi":{},"repair_capi":{},"reset_wizard":{},"console_status":{},"console_enroll":{"key":"string","name":"string"},"console_disable":{},"service_control":{"action":"string"},"configure_acquisition":{"syslog_enabled":"string","firewall_enabled":"string","ssh_enabled":"string","http_enabled":"string","syslog_path":"string"},"acquisition_config":{},"acquisition_metrics":{},"health_check":{},"capi_metrics":{},"hub_available":{},"install_hub_item":{"item_type":"string","item_name":"string"},"remove_hub_item":{"item_type":"string","item_name":"string"}}'
|
||||
;;
|
||||
call)
|
||||
case "$2" in
|
||||
@ -2068,6 +2184,9 @@ case "$1" in
|
||||
repair_lapi)
|
||||
repair_lapi
|
||||
;;
|
||||
repair_capi)
|
||||
repair_capi
|
||||
;;
|
||||
reset_wizard)
|
||||
reset_wizard
|
||||
;;
|
||||
|
||||
@ -36,6 +36,10 @@ define Package/secubox-auth-logger/install
|
||||
$(INSTALL_BIN) ./files/secubox-auth-logger.init $(1)/etc/init.d/secubox-auth-logger
|
||||
$(INSTALL_DIR) $(1)/etc/crowdsec/parsers/s01-parse
|
||||
$(INSTALL_DATA) ./files/openwrt-luci-auth.yaml $(1)/etc/crowdsec/parsers/s01-parse/
|
||||
$(INSTALL_DIR) $(1)/etc/crowdsec/scenarios
|
||||
$(INSTALL_DATA) ./files/openwrt-luci-bf.yaml $(1)/etc/crowdsec/scenarios/
|
||||
$(INSTALL_DIR) $(1)/etc/crowdsec/acquis.d
|
||||
$(INSTALL_DATA) ./files/secubox-auth-acquis.yaml $(1)/etc/crowdsec/acquis.d/
|
||||
$(INSTALL_DIR) $(1)/etc/uci-defaults
|
||||
$(INSTALL_BIN) ./files/99-secubox-auth-logger $(1)/etc/uci-defaults/
|
||||
endef
|
||||
|
||||
@ -1,33 +1,24 @@
|
||||
#!/bin/sh
|
||||
# SecuBox Auth Logger - Post-install configuration
|
||||
# Enables verbose logging for Dropbear and uhttpd
|
||||
# Enables verbose logging for uhttpd and configures CrowdSec
|
||||
|
||||
# Note: Dropbear 2024.86 does NOT support -v flag
|
||||
# Auth monitoring relies on parsing existing syslog messages
|
||||
# The auth-monitor.sh script watches logread for auth failures
|
||||
|
||||
# Enable uhttpd syslog
|
||||
# Enable uhttpd syslog for LuCI login monitoring
|
||||
if [ -f /etc/config/uhttpd ]; then
|
||||
uci set uhttpd.main.syslog='1'
|
||||
uci commit uhttpd
|
||||
/etc/init.d/uhttpd restart 2>/dev/null
|
||||
fi
|
||||
|
||||
# Create auth failures log file
|
||||
touch /var/log/auth-failures.log
|
||||
chmod 644 /var/log/auth-failures.log
|
||||
# Create auth log file for secubox-auth-logger
|
||||
touch /var/log/secubox-auth.log
|
||||
chmod 644 /var/log/secubox-auth.log
|
||||
|
||||
# Add acquisition for CrowdSec if installed
|
||||
if [ -d /etc/crowdsec/acquis.d ]; then
|
||||
cat > /etc/crowdsec/acquis.d/secubox-auth.yaml << 'EOF'
|
||||
# SecuBox Auth Failure Acquisition
|
||||
# Reads from /var/log/messages for secubox-auth tagged messages
|
||||
filenames:
|
||||
- /var/log/messages
|
||||
labels:
|
||||
type: syslog
|
||||
EOF
|
||||
# Restart CrowdSec to pick up new acquisition
|
||||
# Restart CrowdSec to pick up new acquisition/parser/scenario
|
||||
if [ -x /etc/init.d/crowdsec ]; then
|
||||
/etc/init.d/crowdsec restart 2>/dev/null
|
||||
fi
|
||||
|
||||
|
||||
@ -1,10 +1,15 @@
|
||||
#!/bin/sh
|
||||
# SecuBox Auth Monitor - Lightweight auth failure detection
|
||||
# Monitors SSH and LuCI login failures, logs to syslog for CrowdSec
|
||||
# Monitors SSH and LuCI login failures for CrowdSec
|
||||
# Copyright (C) 2024 CyberMind.fr
|
||||
|
||||
LOG_FILE="/var/log/secubox-auth.log"
|
||||
LOG_TAG="secubox-auth"
|
||||
|
||||
# Ensure log file exists
|
||||
touch "$LOG_FILE"
|
||||
chmod 644 "$LOG_FILE"
|
||||
|
||||
# Track recent IPs to avoid duplicate logging
|
||||
TRACK_FILE="/tmp/auth-monitor-track"
|
||||
touch "$TRACK_FILE"
|
||||
@ -27,7 +32,12 @@ log_failure() {
|
||||
fi
|
||||
echo "${key}:${now}" >> "$TRACK_FILE"
|
||||
|
||||
# Log to syslog - CrowdSec will parse this
|
||||
# Log to dedicated file in syslog format for CrowdSec
|
||||
local ts=$(date "+%b %d %H:%M:%S")
|
||||
local hostname=$(cat /proc/sys/kernel/hostname 2>/dev/null || echo "OpenWrt")
|
||||
echo "$ts $hostname $LOG_TAG[$$]: authentication failure for $user from $ip via $service" >> "$LOG_FILE"
|
||||
|
||||
# Also log to syslog for local visibility
|
||||
logger -t "$LOG_TAG" -p auth.warning "authentication failure for $user from $ip via $service"
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,18 @@
|
||||
# CrowdSec Scenario for SecuBox LuCI Brute Force Detection
|
||||
# Triggers when multiple authentication failures are detected from the same IP
|
||||
# Works with secubox/openwrt-luci-auth parser
|
||||
|
||||
type: leaky
|
||||
name: secubox/openwrt-luci-bf
|
||||
description: "Detect LuCI/OpenWrt web interface brute force attempts"
|
||||
filter: "evt.Meta.log_type == 'auth_failure'"
|
||||
leakspeed: "10s"
|
||||
capacity: 5
|
||||
groupby: evt.Meta.source_ip
|
||||
blackhole: 1m
|
||||
reprocess: true
|
||||
labels:
|
||||
service: http
|
||||
remediation: true
|
||||
type: bruteforce
|
||||
confidence: 3
|
||||
@ -0,0 +1,7 @@
|
||||
# SecuBox Auth Logger Acquisition
|
||||
# Reads authentication failure logs from secubox-auth-logger
|
||||
# Used by secubox/openwrt-luci-auth parser and secubox/openwrt-luci-bf scenario
|
||||
filenames:
|
||||
- /var/log/secubox-auth.log
|
||||
labels:
|
||||
type: syslog
|
||||
Loading…
Reference in New Issue
Block a user