Files
Charon/scripts/diagnose-crowdsec.sh
2026-03-04 18:34:49 +00:00

462 lines
13 KiB
Bash
Executable File

#!/usr/bin/env bash
# diagnose-crowdsec.sh - CrowdSec Connectivity and Enrollment Diagnostics
# Usage: ./diagnose-crowdsec.sh [--json] [--data-dir /path/to/crowdsec]
# shellcheck disable=SC2312
set -euo pipefail
# Default configuration
DATA_DIR="${CROWDSEC_DATA_DIR:-/var/lib/crowdsec}"
JSON_OUTPUT=false
LAPI_PORT="${CROWDSEC_LAPI_PORT:-8085}"
# Colors for terminal output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Parse arguments
while [[ $# -gt 0 ]]; do
case "$1" in
--json)
JSON_OUTPUT=true
shift
;;
--data-dir)
DATA_DIR="$2"
shift 2
;;
--lapi-port)
LAPI_PORT="$2"
shift 2
;;
-h|--help)
echo "Usage: $0 [--json] [--data-dir /path/to/crowdsec] [--lapi-port 8085]"
echo ""
echo "Options:"
echo " --json Output results as JSON"
echo " --data-dir CrowdSec data directory (default: /var/lib/crowdsec)"
echo " --lapi-port LAPI port (default: 8085)"
echo " -h, --help Show this help message"
exit 0
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
# Results storage
declare -A RESULTS
# Logging functions
log_info() {
if [[ "$JSON_OUTPUT" == "false" ]]; then
echo -e "${BLUE}[INFO]${NC} $1"
fi
}
log_success() {
if [[ "$JSON_OUTPUT" == "false" ]]; then
echo -e "${GREEN}[PASS]${NC} $1"
fi
}
log_warning() {
if [[ "$JSON_OUTPUT" == "false" ]]; then
echo -e "${YELLOW}[WARN]${NC} $1"
fi
}
log_error() {
if [[ "$JSON_OUTPUT" == "false" ]]; then
echo -e "${RED}[FAIL]${NC} $1"
fi
}
# Check if command exists
check_command() {
command -v "$1" &>/dev/null
}
# 1. Check LAPI process running
check_lapi_running() {
log_info "Checking if CrowdSec LAPI is running..."
if pgrep -x "crowdsec" &>/dev/null; then
local pid
pid=$(pgrep -x "crowdsec" | head -1)
RESULTS["lapi_running"]="true"
RESULTS["lapi_pid"]="$pid"
log_success "CrowdSec LAPI is running (PID: $pid)"
return 0
else
RESULTS["lapi_running"]="false"
RESULTS["lapi_pid"]=""
log_error "CrowdSec LAPI is NOT running"
return 1
fi
}
# 2. Check LAPI responding
check_lapi_health() {
log_info "Checking LAPI health endpoint..."
local health_url="http://127.0.0.1:${LAPI_PORT}/health"
local response
if response=$(curl -s --connect-timeout 5 --max-time 10 "$health_url" 2>/dev/null); then
RESULTS["lapi_healthy"]="true"
RESULTS["lapi_health_response"]="$response"
log_success "LAPI health endpoint responding at $health_url"
return 0
else
RESULTS["lapi_healthy"]="false"
RESULTS["lapi_health_response"]=""
log_error "LAPI health endpoint not responding at $health_url"
return 1
fi
}
# 3. Check cscli available
check_cscli() {
log_info "Checking cscli availability..."
if check_command cscli; then
local version
version=$(cscli version 2>/dev/null | head -1 || echo "unknown")
RESULTS["cscli_available"]="true"
RESULTS["cscli_version"]="$version"
log_success "cscli is available: $version"
return 0
else
RESULTS["cscli_available"]="false"
RESULTS["cscli_version"]=""
log_error "cscli command not found"
return 1
fi
}
# 4. Check CAPI registration
check_capi_registered() {
log_info "Checking CAPI registration..."
local creds_path="${DATA_DIR}/config/online_api_credentials.yaml"
if [[ ! -f "$creds_path" ]]; then
creds_path="${DATA_DIR}/online_api_credentials.yaml"
fi
if [[ -f "$creds_path" ]]; then
RESULTS["capi_registered"]="true"
RESULTS["capi_creds_path"]="$creds_path"
log_success "CAPI credentials found at $creds_path"
return 0
else
RESULTS["capi_registered"]="false"
RESULTS["capi_creds_path"]=""
log_error "CAPI credentials not found (checked ${DATA_DIR}/config/online_api_credentials.yaml)"
return 1
fi
}
# 5. Check CAPI connectivity
check_capi_connectivity() {
log_info "Checking CAPI connectivity..."
if ! check_command cscli; then
RESULTS["capi_reachable"]="unknown"
log_warning "Cannot check CAPI connectivity - cscli not available"
return 1
fi
local config_path="${DATA_DIR}/config/config.yaml"
if [[ ! -f "$config_path" ]]; then
config_path="${DATA_DIR}/config.yaml"
fi
local cscli_args=("capi" "status")
if [[ -f "$config_path" ]]; then
cscli_args=("-c" "$config_path" "capi" "status")
fi
local output
if output=$(timeout 10s cscli "${cscli_args[@]}" 2>&1); then
RESULTS["capi_reachable"]="true"
RESULTS["capi_status"]="$output"
log_success "CAPI is reachable"
return 0
else
RESULTS["capi_reachable"]="false"
RESULTS["capi_status"]="$output"
log_error "CAPI is not reachable: $output"
return 1
fi
}
# 6. Check Console API reachability
check_console_api() {
log_info "Checking CrowdSec Console API reachability..."
local console_url="https://api.crowdsec.net/health"
local http_code
http_code=$(curl -s -o /dev/null -w "%{http_code}" --connect-timeout 5 --max-time 10 "$console_url" 2>/dev/null || echo "000")
if [[ "$http_code" == "200" ]] || [[ "$http_code" == "204" ]]; then
RESULTS["console_reachable"]="true"
RESULTS["console_http_code"]="$http_code"
log_success "Console API is reachable (HTTP $http_code)"
return 0
else
RESULTS["console_reachable"]="false"
RESULTS["console_http_code"]="$http_code"
log_error "Console API is not reachable (HTTP $http_code)"
return 1
fi
}
# 7. Check Console enrollment status
check_console_enrolled() {
log_info "Checking Console enrollment status..."
if ! check_command cscli; then
RESULTS["console_enrolled"]="unknown"
log_warning "Cannot check enrollment - cscli not available"
return 1
fi
local config_path="${DATA_DIR}/config/config.yaml"
if [[ ! -f "$config_path" ]]; then
config_path="${DATA_DIR}/config.yaml"
fi
local cscli_args=("console" "status")
if [[ -f "$config_path" ]]; then
cscli_args=("-c" "$config_path" "console" "status")
fi
local output
if output=$(timeout 10s cscli "${cscli_args[@]}" 2>&1); then
if echo "$output" | grep -qi "enrolled"; then
RESULTS["console_enrolled"]="true"
RESULTS["console_enrollment_output"]="$output"
log_success "Console is enrolled"
return 0
else
RESULTS["console_enrolled"]="false"
RESULTS["console_enrollment_output"]="$output"
log_warning "Console enrollment status unclear: $output"
return 1
fi
else
RESULTS["console_enrolled"]="false"
RESULTS["console_enrollment_output"]="$output"
log_error "Failed to check console status: $output"
return 1
fi
}
# 8. Check config.yaml
check_config_yaml() {
log_info "Checking config.yaml..."
local config_path="${DATA_DIR}/config/config.yaml"
if [[ ! -f "$config_path" ]]; then
config_path="${DATA_DIR}/config.yaml"
fi
if [[ -f "$config_path" ]]; then
RESULTS["config_exists"]="true"
RESULTS["config_path"]="$config_path"
log_success "config.yaml found at $config_path"
# Try to validate
if check_command cscli; then
if timeout 10s cscli -c "$config_path" config check &>/dev/null; then
RESULTS["config_valid"]="true"
log_success "config.yaml is valid"
else
RESULTS["config_valid"]="false"
log_error "config.yaml validation failed"
fi
else
RESULTS["config_valid"]="unknown"
fi
return 0
else
RESULTS["config_exists"]="false"
RESULTS["config_valid"]="false"
log_error "config.yaml not found"
return 1
fi
}
# 9. Check acquis.yaml
check_acquis_yaml() {
log_info "Checking acquis.yaml..."
local acquis_path="${DATA_DIR}/config/acquis.yaml"
if [[ ! -f "$acquis_path" ]]; then
acquis_path="${DATA_DIR}/acquis.yaml"
fi
if [[ -f "$acquis_path" ]]; then
RESULTS["acquis_exists"]="true"
RESULTS["acquis_path"]="$acquis_path"
log_success "acquis.yaml found at $acquis_path"
# Check for datasources
if grep -q "source:" "$acquis_path" && grep -qE "(filenames?:|journalctl)" "$acquis_path"; then
RESULTS["acquis_valid"]="true"
log_success "acquis.yaml has datasource configuration"
else
RESULTS["acquis_valid"]="false"
log_warning "acquis.yaml may be missing datasource configuration"
fi
return 0
else
RESULTS["acquis_exists"]="false"
RESULTS["acquis_valid"]="false"
log_warning "acquis.yaml not found (optional for some setups)"
return 1
fi
}
# 10. Check bouncers registered
check_bouncers() {
log_info "Checking registered bouncers..."
if ! check_command cscli; then
RESULTS["bouncers_count"]="unknown"
log_warning "Cannot check bouncers - cscli not available"
return 1
fi
local config_path="${DATA_DIR}/config/config.yaml"
if [[ ! -f "$config_path" ]]; then
config_path="${DATA_DIR}/config.yaml"
fi
local cscli_args=("bouncers" "list" "-o" "json")
if [[ -f "$config_path" ]]; then
cscli_args=("-c" "$config_path" "bouncers" "list" "-o" "json")
fi
local output
if output=$(timeout 10s cscli "${cscli_args[@]}" 2>/dev/null); then
local count
count=$(echo "$output" | jq 'length' 2>/dev/null || echo "0")
RESULTS["bouncers_count"]="$count"
RESULTS["bouncers_list"]="$output"
if [[ "$count" -gt 0 ]]; then
log_success "Found $count registered bouncer(s)"
else
log_warning "No bouncers registered"
fi
return 0
else
RESULTS["bouncers_count"]="0"
log_error "Failed to list bouncers"
return 1
fi
}
# Output JSON results
output_json() {
echo "{"
local first=true
for key in "${!RESULTS[@]}"; do
if [[ "$first" == "true" ]]; then
first=false
else
echo ","
fi
local value="${RESULTS[$key]}"
# Escape special characters for JSON
value="${value//\\/\\\\}"
value="${value//\"/\\\"}"
value="${value//$'\n'/\\n}"
value="${value//$'\r'/\\r}"
value="${value//$'\t'/\\t}"
printf ' "%s": "%s"' "$key" "$value"
done
echo ""
echo "}"
}
# Print summary
print_summary() {
echo ""
echo "=========================================="
echo " CrowdSec Diagnostic Summary"
echo "=========================================="
echo ""
local passed=0
local failed=0
local warnings=0
for key in lapi_running lapi_healthy capi_registered capi_reachable console_reachable console_enrolled config_exists config_valid; do
case "${RESULTS[$key]:-unknown}" in
true) ((passed++)) ;;
false) ((failed++)) ;;
*) ((warnings++)) ;;
esac
done
echo -e "Checks passed: ${GREEN}$passed${NC}"
echo -e "Checks failed: ${RED}$failed${NC}"
echo -e "Checks unknown: ${YELLOW}$warnings${NC}"
echo ""
if [[ "$failed" -gt 0 ]]; then
echo -e "${RED}Some checks failed. See details above.${NC}"
echo ""
echo "Common solutions:"
echo " - If LAPI not running: systemctl start crowdsec"
echo " - If CAPI not registered: cscli capi register"
echo " - If Console not enrolled: cscli console enroll <token>"
echo " - If config missing: Check ${DATA_DIR}/config/"
exit 1
else
echo -e "${GREEN}All critical checks passed!${NC}"
exit 0
fi
}
# Main execution
main() {
if [[ "$JSON_OUTPUT" == "false" ]]; then
echo "=========================================="
echo " CrowdSec Diagnostic Tool v1.0"
echo "=========================================="
echo ""
echo "Data directory: ${DATA_DIR}"
echo "LAPI port: ${LAPI_PORT}"
echo ""
fi
# Run all checks (continue on failure)
check_lapi_running || true
check_lapi_health || true
check_cscli || true
check_capi_registered || true
check_capi_connectivity || true
check_console_api || true
check_console_enrolled || true
check_config_yaml || true
check_acquis_yaml || true
check_bouncers || true
if [[ "$JSON_OUTPUT" == "true" ]]; then
output_json
else
print_summary
fi
}
main