462 lines
13 KiB
Bash
Executable File
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
|