mirror of
https://github.com/rubenhensen/k8scd.git
synced 2026-09-17 10:22:54 +02:00
683 lines
26 KiB
Bash
683 lines
26 KiB
Bash
#!/usr/bin/env bash
|
|
# CrowdSec Intrusion Prevention System test for nix-infra-machine
|
|
#
|
|
# This test:
|
|
# 1. Deploys CrowdSec with SSH and system protection enabled
|
|
# 2. Verifies the CrowdSec service and Local API are running
|
|
# 3. Tests firewall bouncer (nftables integration)
|
|
# 4. Tests HAProxy SPOA bouncer
|
|
# 5. Tests auditd integration for kernel-level monitoring
|
|
# 6. Tests cscli functionality (hub, parsers, scenarios)
|
|
# 7. Tests basic decision management
|
|
# 8. Cleans up on teardown
|
|
#
|
|
# [NIS2 COMPLIANCE VERIFICATION]
|
|
# This test validates that the CrowdSec deployment meets key NIS2 requirements:
|
|
# - Article 21(2)(b): Incident handling through automated threat detection
|
|
# - Article 21(2)(d): Network security through IDS/IPS capabilities
|
|
# - Article 21(2)(g): Security monitoring and logging
|
|
|
|
# Configuration
|
|
CROWDSEC_API_PORT=8080
|
|
FIREWALL_BOUNCER_ENABLED=true
|
|
HAPROXY_BOUNCER_ENABLED=false
|
|
HAPROXY_SPOA_PORT=3000
|
|
AUDITD_ENABLED=true
|
|
|
|
|
|
# Handle teardown command
|
|
if [ "$CMD" = "teardown" ]; then
|
|
echo "Tearing down CrowdSec test..."
|
|
|
|
# Stop CrowdSec services
|
|
if [ "$HAPROXY_BOUNCER_ENABLED" = "true" ]; then
|
|
$NIX_INFRA fleet cmd -d "$WORK_DIR" --target="$TARGET" \
|
|
'systemctl stop crowdsec-haproxy-bouncer 2>/dev/null || true'
|
|
fi
|
|
if [ "$FIREWALL_BOUNCER_ENABLED" = "true" ]; then
|
|
$NIX_INFRA fleet cmd -d "$WORK_DIR" --target="$TARGET" \
|
|
'systemctl stop crowdsec-firewall-bouncer 2>/dev/null || true'
|
|
fi
|
|
$NIX_INFRA fleet cmd -d "$WORK_DIR" --target="$TARGET" \
|
|
'systemctl stop crowdsec 2>/dev/null || true'
|
|
|
|
# Clean up data directories on target nodes
|
|
$NIX_INFRA fleet cmd -d "$WORK_DIR" --target="$TARGET" \
|
|
'rm -rf /var/lib/crowdsec'
|
|
$NIX_INFRA fleet cmd -d "$WORK_DIR" --target="$TARGET" \
|
|
'rm -rf /var/lib/crowdsec-firewall-bouncer 2>/dev/null || true'
|
|
$NIX_INFRA fleet cmd -d "$WORK_DIR" --target="$TARGET" \
|
|
'rm -rf /var/lib/crowdsec-haproxy-bouncer 2>/dev/null || true'
|
|
|
|
# Clean up declarative configuration directories on target nodes
|
|
$NIX_INFRA fleet cmd -d "$WORK_DIR" --target="$TARGET" \
|
|
'rm -rf /etc/crowdsec 2>/dev/null || true'
|
|
|
|
echo "CrowdSec teardown complete"
|
|
return 0
|
|
fi
|
|
|
|
# ============================================================================
|
|
# Test Setup
|
|
# ============================================================================
|
|
|
|
_start=$(date +%s)
|
|
|
|
echo ""
|
|
echo "========================================"
|
|
echo "CrowdSec Intrusion Prevention Test"
|
|
echo "========================================"
|
|
echo ""
|
|
echo "Testing NIS2-compliant security monitoring setup"
|
|
echo ""
|
|
|
|
# Deploy the CrowdSec configuration to test nodes
|
|
echo "Step 1: Deploying CrowdSec configuration..."
|
|
$NIX_INFRA fleet deploy-apps -d "$WORK_DIR" --batch --env="$ENV" \
|
|
--test-dir="$WORK_DIR/$TEST_DIR" \
|
|
--target="$TARGET"
|
|
|
|
# Apply the configuration
|
|
echo "Step 2: Applying NixOS configuration..."
|
|
$NIX_INFRA fleet cmd -d "$WORK_DIR" --target="$TARGET" "nixos-rebuild switch --fast"
|
|
|
|
_setup=$(date +%s)
|
|
|
|
# ============================================================================
|
|
# Test Verification - CrowdSec Service
|
|
# ============================================================================
|
|
|
|
echo ""
|
|
echo "Step 3: Verifying CrowdSec deployment..."
|
|
echo ""
|
|
|
|
# Wait for CrowdSec service to start
|
|
for node in $TARGET; do
|
|
wait_for_service "$node" "crowdsec" --timeout=90
|
|
wait_for_port "$node" "$CROWDSEC_API_PORT" --timeout=60
|
|
done
|
|
|
|
# Check if the systemd service is active
|
|
echo ""
|
|
echo "Checking CrowdSec systemd service status..."
|
|
for node in $TARGET; do
|
|
assert_service_active "$node" "crowdsec" || show_service_logs "$node" "crowdsec" 50
|
|
done
|
|
|
|
# Check if CrowdSec process is running
|
|
echo ""
|
|
echo "Checking CrowdSec process..."
|
|
for node in $TARGET; do
|
|
assert_process_running "$node" "crowdsec" "CrowdSec"
|
|
done
|
|
|
|
# Check if CrowdSec API port is listening
|
|
echo ""
|
|
echo "Checking CrowdSec API port ($CROWDSEC_API_PORT)..."
|
|
for node in $TARGET; do
|
|
assert_port_listening "$node" "$CROWDSEC_API_PORT" "CrowdSec API port $CROWDSEC_API_PORT"
|
|
done
|
|
|
|
# ============================================================================
|
|
# Test Verification - Firewall Bouncer
|
|
# ============================================================================
|
|
|
|
if [ "$FIREWALL_BOUNCER_ENABLED" = "true" ]; then
|
|
echo ""
|
|
echo "Step 4: Verifying Firewall Bouncer..."
|
|
echo ""
|
|
|
|
# Wait for bouncer service
|
|
for node in $TARGET; do
|
|
wait_for_service "$node" "crowdsec-firewall-bouncer" --timeout=60
|
|
done
|
|
|
|
# Check bouncer service status
|
|
echo "Checking Firewall Bouncer systemd service status..."
|
|
for node in $TARGET; do
|
|
assert_service_active "$node" "crowdsec-firewall-bouncer" || \
|
|
show_service_logs "$node" "crowdsec-firewall-bouncer" 50
|
|
done
|
|
|
|
# Check nftables integration
|
|
echo ""
|
|
echo "Checking nftables integration..."
|
|
for node in $TARGET; do
|
|
echo " Verifying nftables tables and sets on $node..."
|
|
|
|
# Check if crowdsec table exists
|
|
nft_table=$(cmd_clean "$node" "nft list table ip crowdsec 2>&1 || echo 'not found'")
|
|
if [[ "$nft_table" == *"table ip crowdsec"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} CrowdSec nftables IPv4 table exists [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} CrowdSec nftables tables: $nft_table [warning]"
|
|
fi
|
|
|
|
# Check if crowdsec set exists in IPv4 table
|
|
nft_set=$(cmd_clean "$node" "nft list set ip crowdsec crowdsec-blocklist 2>&1 || echo 'not found'")
|
|
if [[ "$nft_set" == *"crowdsec-blocklist"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} CrowdSec IPv4 nftables set exists [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} CrowdSec IPv4 set: $nft_set [warning]"
|
|
fi
|
|
|
|
# Check if crowdsec chain exists
|
|
nft_chain=$(cmd_clean "$node" "nft list chain ip crowdsec crowdsec-chain 2>&1 || echo 'not found'")
|
|
if [[ "$nft_chain" == *"crowdsec-chain"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} CrowdSec nftables chain exists [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} CrowdSec chain: $nft_chain [warning]"
|
|
fi
|
|
|
|
# Check IPv6 table
|
|
nft_table6=$(cmd_clean "$node" "nft list table ip6 crowdsec6 2>&1 || echo 'not found'")
|
|
if [[ "$nft_table6" == *"table ip6 crowdsec6"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} CrowdSec nftables IPv6 table exists [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} CrowdSec IPv6 table: $nft_table6 [warning]"
|
|
fi
|
|
done
|
|
else
|
|
echo ""
|
|
echo "Step 4: Firewall Bouncer (SKIPPED - disabled in test config)"
|
|
echo ""
|
|
fi
|
|
|
|
# ============================================================================
|
|
# Test Verification - HAProxy SPOA Bouncer
|
|
# ============================================================================
|
|
|
|
if [ "$HAPROXY_BOUNCER_ENABLED" = "true" ]; then
|
|
echo ""
|
|
echo "Step 5: Verifying HAProxy SPOA Bouncer..."
|
|
echo ""
|
|
|
|
# Wait for bouncer service
|
|
for node in $TARGET; do
|
|
wait_for_service "$node" "crowdsec-haproxy-bouncer" --timeout=60
|
|
wait_for_port "$node" "$HAPROXY_SPOA_PORT" --timeout=60
|
|
done
|
|
|
|
# Check bouncer service status
|
|
echo "Checking HAProxy SPOA Bouncer systemd service status..."
|
|
for node in $TARGET; do
|
|
assert_service_active "$node" "crowdsec-haproxy-bouncer" || \
|
|
show_service_logs "$node" "crowdsec-haproxy-bouncer" 50
|
|
done
|
|
|
|
# Check if SPOA port is listening
|
|
echo ""
|
|
echo "Checking HAProxy SPOA port ($HAPROXY_SPOA_PORT)..."
|
|
for node in $TARGET; do
|
|
assert_port_listening "$node" "$HAPROXY_SPOA_PORT" "HAProxy SPOA port $HAPROXY_SPOA_PORT"
|
|
done
|
|
|
|
# Verify SPOA config exists
|
|
echo ""
|
|
echo "Checking HAProxy SPOA bouncer configuration..."
|
|
for node in $TARGET; do
|
|
config_check=$(cmd_clean "$node" "test -f /var/lib/crowdsec-haproxy-bouncer/config.yaml && echo 'exists' || echo 'missing'")
|
|
if [[ "$config_check" == *"exists"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} HAProxy SPOA bouncer config exists [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} HAProxy SPOA bouncer config: $config_check [warning]"
|
|
fi
|
|
done
|
|
else
|
|
echo ""
|
|
echo "Step 5: HAProxy SPOA Bouncer (SKIPPED - disabled in test config)"
|
|
echo ""
|
|
fi
|
|
|
|
# ============================================================================
|
|
# Test Verification - Auditd Integration
|
|
# ============================================================================
|
|
|
|
if [ "$AUDITD_ENABLED" = "true" ]; then
|
|
echo ""
|
|
echo "Step 6: Verifying Auditd Integration..."
|
|
echo ""
|
|
|
|
# Check if auditd service is running
|
|
for node in $TARGET; do
|
|
echo "Checking auditd service on $node..."
|
|
|
|
# Check auditd service status
|
|
auditd_status=$(cmd_clean "$node" "systemctl is-active auditd 2>&1 || echo 'inactive'")
|
|
if [[ "$auditd_status" == "active" ]]; then
|
|
echo -e " ${GREEN}✓${NC} Auditd service is active [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Auditd service status: $auditd_status [warning]"
|
|
fi
|
|
|
|
# Check audit-rules-nixos service status and errors
|
|
echo " Checking audit-rules-nixos service..."
|
|
audit_rules_status=$(cmd_clean "$node" "systemctl is-active audit-rules-nixos 2>&1 || echo 'inactive'")
|
|
# Service might be one-shot, check if it succeeded
|
|
audit_rules_result=$(cmd_clean "$node" "systemctl show audit-rules-nixos --property=Result 2>&1 || echo 'unknown'")
|
|
if [[ "$audit_rules_result" == *"success"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} Audit rules loaded successfully [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Audit rules service result: $audit_rules_result [warning]"
|
|
# Show the actual error
|
|
echo " Debugging audit rules failure..."
|
|
audit_rules_file=$(cmd_clean "$node" "find /nix/store -name 'audit.rules' -path '*-audit.rules*' 2>/dev/null | head -1 || echo 'not found'")
|
|
echo " Audit rules file: $audit_rules_file"
|
|
if [[ "$audit_rules_file" != "not found" ]] && [[ -n "$audit_rules_file" ]]; then
|
|
echo " Rules file contents:"
|
|
audit_rules_content=$(cmd_clean "$node" "cat '$audit_rules_file' 2>&1 || echo 'cannot read'")
|
|
echo "$audit_rules_content" | while read line; do echo " $line"; done
|
|
echo " Trying to load rules manually..."
|
|
manual_load=$(cmd_clean "$node" "auditctl -R '$audit_rules_file' 2>&1 || echo 'load failed'")
|
|
echo " Manual load result: $manual_load"
|
|
fi
|
|
fi
|
|
|
|
# Check if audit rules are loaded
|
|
echo " Checking loaded audit rules..."
|
|
audit_rules=$(cmd_clean "$node" "auditctl -l 2>&1 || echo 'no rules'")
|
|
if [[ "$audit_rules" == *"passwd"* ]] || [[ "$audit_rules" == *"shadow"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} Audit rules for identity files loaded [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Audit rules: $audit_rules [warning]"
|
|
fi
|
|
|
|
# Check if sudoers watch rule is loaded
|
|
if [[ "$audit_rules" == *"sudoers"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} Audit rule for sudoers file loaded [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Sudoers audit rule not found [warning]"
|
|
fi
|
|
|
|
# Verify whitelist processes are configured (check audit config)
|
|
echo " Checking NixOS wrapper whitelist configuration..."
|
|
# The whitelist is configured via audit rules, we verify it was processed
|
|
# by checking that the service started without errors
|
|
if [[ "$auditd_status" == "active" ]]; then
|
|
echo -e " ${GREEN}✓${NC} NixOS wrapper whitelist configured (service active) [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Cannot verify whitelist (auditd not active) [warning]"
|
|
fi
|
|
done
|
|
else
|
|
echo ""
|
|
echo "Step 6: Auditd Integration (SKIPPED - disabled in test config)"
|
|
echo ""
|
|
fi
|
|
|
|
# ============================================================================
|
|
# Functional Tests - CLI Tools
|
|
# ============================================================================
|
|
|
|
echo ""
|
|
echo "Step 7: Testing CrowdSec CLI (cscli)..."
|
|
echo ""
|
|
|
|
for node in $TARGET; do
|
|
echo "Testing cscli on $node..."
|
|
|
|
# Test cscli version
|
|
echo " Checking cscli version..."
|
|
version_result=$(cmd_clean "$node" "cscli version 2>&1")
|
|
if [[ "$version_result" == *"version"* ]] || [[ "$version_result" == *"crowdsec"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} cscli version command works [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} cscli version output: $version_result [warning]"
|
|
fi
|
|
|
|
# Test LAPI status
|
|
echo " Checking Local API status..."
|
|
lapi_status=$(cmd_clean "$node" "cscli lapi status 2>&1 || true")
|
|
if [[ "$lapi_status" == *"successfully interact"* ]] || [[ "$lapi_status" == *"LAPI is reachable"* ]] || [[ "$lapi_status" == *"You can successfully"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} Local API is reachable [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} LAPI status check: $lapi_status [warning]"
|
|
fi
|
|
|
|
# Test hub listing
|
|
echo " Checking installed hub items..."
|
|
hub_result=$(cmd_clean "$node" "cscli hub list 2>&1 || true")
|
|
if [[ "$hub_result" == *"COLLECTIONS"* ]] || [[ "$hub_result" == *"PARSERS"* ]] || [[ "$hub_result" == *"SCENARIOS"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} Hub listing works [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Hub listing output: $hub_result [warning]"
|
|
fi
|
|
|
|
# Test collections listing
|
|
echo " Checking installed collections..."
|
|
collections_result=$(cmd_clean "$node" "cscli collections list 2>&1 || true")
|
|
if [[ "$collections_result" == *"sshd"* ]] || [[ "$collections_result" == *"crowdsecurity"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} SSH collection installed [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} SSH collection may still be installing [info]"
|
|
fi
|
|
|
|
# Test parsers listing
|
|
echo " Checking installed parsers..."
|
|
parsers_result=$(cmd_clean "$node" "cscli parsers list 2>&1 || true")
|
|
if [[ "$parsers_result" == *"sshd"* ]] || [[ "$parsers_result" == *"syslog"* ]] || [[ "$parsers_result" == *"crowdsecurity"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} Parsers installed [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Parsers may still be installing: $parsers_result [warning]"
|
|
fi
|
|
|
|
# Test scenarios listing
|
|
echo " Checking installed scenarios..."
|
|
scenarios_result=$(cmd_clean "$node" "cscli scenarios list 2>&1 || true")
|
|
if [[ "$scenarios_result" == *"ssh"* ]] || [[ "$scenarios_result" == *"crowdsecurity"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} Scenarios installed [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Scenarios may still be installing [info]"
|
|
fi
|
|
done
|
|
|
|
# ============================================================================
|
|
# Functional Tests - Decision Management
|
|
# ============================================================================
|
|
|
|
echo ""
|
|
echo "Step 8: Testing Decision Management..."
|
|
echo ""
|
|
|
|
for node in $TARGET; do
|
|
echo "Testing decision management on $node..."
|
|
|
|
# List current decisions (should be empty initially)
|
|
echo " Listing current decisions..."
|
|
decisions_result=$(cmd_clean "$node" "cscli decisions list 2>&1 || true")
|
|
if [[ "$decisions_result" == *"No active decisions"* ]] || [[ "$decisions_result" == *"0 decision"* ]] || [[ -z "$decisions_result" ]] || [[ "$decisions_result" == *"decision"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} Decision listing works [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Decision listing output: $decisions_result [info]"
|
|
fi
|
|
|
|
# Add a test decision (ban a test IP)
|
|
echo " Adding test decision (ban 192.0.2.1 - TEST-NET-1)..."
|
|
add_result=$(cmd_clean "$node" "cscli decisions add --ip 192.0.2.1 --reason 'nix-infra test' --type ban 2>&1 || true")
|
|
if [[ "$add_result" == *"Decision successfully added"* ]] || [[ "$add_result" == *"added"* ]] || [[ "$add_result" == *"success"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} Decision added successfully [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Decision add result: $add_result [info]"
|
|
fi
|
|
|
|
# Verify the decision was added
|
|
echo " Verifying decision was recorded..."
|
|
verify_result=$(cmd_clean "$node" "cscli decisions list 2>&1 || true")
|
|
if [[ "$verify_result" == *"192.0.2.1"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} Decision recorded in database [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Decision verification: $verify_result [warning]"
|
|
fi
|
|
|
|
# Remove the test decision
|
|
echo " Removing test decision..."
|
|
remove_result=$(cmd_clean "$node" "cscli decisions delete --ip 192.0.2.1 2>&1 || true")
|
|
if [[ "$remove_result" == *"decision"* ]] || [[ "$remove_result" == *"deleted"* ]] || [[ "$remove_result" == *"removed"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} Decision delete command executed [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Decision delete result: $remove_result [warning]"
|
|
fi
|
|
|
|
# Verify the decision was actually removed
|
|
echo " Verifying decision was removed..."
|
|
verify_removed=$(cmd_clean "$node" "cscli decisions list 2>&1 || true")
|
|
if [[ "$verify_removed" != *"192.0.2.1"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} Decision successfully removed from database [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Decision may still exist: $verify_removed [warning]"
|
|
fi
|
|
done
|
|
|
|
# ============================================================================
|
|
# Functional Tests - Bouncer Registration
|
|
# ============================================================================
|
|
|
|
echo ""
|
|
echo "Step 9: Testing Bouncer Registration..."
|
|
echo ""
|
|
|
|
for node in $TARGET; do
|
|
echo "Checking bouncer status on $node..."
|
|
|
|
# List registered bouncers
|
|
bouncers_result=$(cmd_clean "$node" "cscli bouncers list 2>&1 || true")
|
|
|
|
if [ "$FIREWALL_BOUNCER_ENABLED" = "true" ]; then
|
|
if [[ "$bouncers_result" == *"firewall"* ]] || [[ "$bouncers_result" == *"bouncer"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} Firewall bouncer is registered [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Bouncer registration status: $bouncers_result [info]"
|
|
fi
|
|
fi
|
|
|
|
if [ "$HAPROXY_BOUNCER_ENABLED" = "true" ]; then
|
|
if [[ "$bouncers_result" == *"haproxy"* ]] || [[ "$bouncers_result" == *"spoa"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} HAProxy SPOA bouncer is registered [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} HAProxy bouncer registration status: $bouncers_result [info]"
|
|
fi
|
|
fi
|
|
|
|
if [ "$FIREWALL_BOUNCER_ENABLED" = "false" ] && [ "$HAPROXY_BOUNCER_ENABLED" = "false" ]; then
|
|
echo -e " ${YELLOW}!${NC} Bouncer check skipped (both disabled in config) [info]"
|
|
fi
|
|
done
|
|
|
|
# ============================================================================
|
|
# Functional Tests - Metrics and API Endpoints
|
|
# ============================================================================
|
|
|
|
echo ""
|
|
echo "Step 10: Testing Metrics and API Endpoints..."
|
|
echo ""
|
|
|
|
for node in $TARGET; do
|
|
echo "Checking metrics on $node..."
|
|
|
|
# Test cscli alerts list
|
|
echo " Checking cscli alerts functionality..."
|
|
alerts_result=$(cmd_clean "$node" "cscli alerts list 2>&1 || true")
|
|
if [[ "$alerts_result" == *"No active alerts"* ]] || [[ "$alerts_result" == *"ID"* ]] || [[ "$alerts_result" == *"Source"* ]] || [[ "$alerts_result" == *"Reason"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} cscli alerts command works [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Alerts output unexpected: $alerts_result [warning]"
|
|
fi
|
|
|
|
# Test API endpoint
|
|
echo " Checking API endpoint..."
|
|
api_result=$(cmd_clean "$node" "curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:$CROWDSEC_API_PORT/v1/decisions 2>&1 || echo '000'")
|
|
if [[ "$api_result" == "200" ]] || [[ "$api_result" == "401" ]] || [[ "$api_result" == "403" ]]; then
|
|
echo -e " ${GREEN}✓${NC} API endpoint responds (HTTP $api_result) [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} API response code: $api_result [warning]"
|
|
fi
|
|
done
|
|
|
|
# ============================================================================
|
|
# Functional Tests - Machine Registration
|
|
# ============================================================================
|
|
|
|
echo ""
|
|
echo "Step 11: Testing Machine Registration..."
|
|
echo ""
|
|
|
|
for node in $TARGET; do
|
|
echo "Checking machine registration on $node..."
|
|
|
|
echo " Checking registered machines..."
|
|
machines_result=$(cmd_clean "$node" "cscli machines list 2>&1 || true")
|
|
if [[ "$machines_result" == *"testnode"* ]] || [[ "$machines_result" == *"localhost"* ]] || [[ "$machines_result" == *"validated"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} Local machine is registered with LAPI [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Machine registration status: $machines_result [warning]"
|
|
fi
|
|
done
|
|
|
|
# ============================================================================
|
|
# Functional Tests - Acquisition Sources
|
|
# ============================================================================
|
|
|
|
echo ""
|
|
echo "Step 12: Testing Acquisition Sources..."
|
|
echo ""
|
|
|
|
for node in $TARGET; do
|
|
echo "Checking acquisition sources on $node..."
|
|
|
|
# Check if acquisitions are configured
|
|
echo " Checking acquisition configuration..."
|
|
acq_file=$(cmd_clean "$node" "cat /var/lib/crowdsec/config/acquisitions.yaml 2>&1 || true")
|
|
if [[ "$acq_file" == *"journalctl"* ]] || [[ "$acq_file" == *"sshd"* ]] || [[ "$acq_file" == *"source"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} Acquisition sources configured [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Acquisition config: $acq_file [warning]"
|
|
fi
|
|
|
|
# Check cscli metrics for acquisition stats
|
|
echo " Checking acquisition metrics..."
|
|
acq_metrics=$(cmd_clean "$node" "cscli metrics show acquisitions 2>&1 || true")
|
|
if [[ "$acq_metrics" == *"journalctl"* ]] || [[ "$acq_metrics" == *"file"* ]] || [[ "$acq_metrics" == *"Source"* ]] || [[ "$acq_metrics" == *"Lines"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} Acquisition metrics available [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Acquisition metrics: $acq_metrics [info]"
|
|
fi
|
|
done
|
|
|
|
# ============================================================================
|
|
# Functional Tests - Database and Config Files
|
|
# ============================================================================
|
|
|
|
echo ""
|
|
echo "Step 13: Testing Database and Configuration Files..."
|
|
echo ""
|
|
|
|
for node in $TARGET; do
|
|
echo "Checking persistence on $node..."
|
|
|
|
# Check if SQLite database exists
|
|
echo " Checking CrowdSec database..."
|
|
db_check=$(cmd_clean "$node" "test -f /var/lib/crowdsec/data/crowdsec.db && echo 'exists' || echo 'missing'")
|
|
if [[ "$db_check" == *"exists"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} SQLite database exists [pass]"
|
|
else
|
|
echo -e " ${RED}✗${NC} SQLite database missing [fail]"
|
|
fi
|
|
|
|
# Check if config directory exists with required files
|
|
echo " Checking configuration files..."
|
|
config_check=$(cmd_clean "$node" "ls /var/lib/crowdsec/config/ 2>&1 || true")
|
|
if [[ "$config_check" == *"config.yaml"* ]] && [[ "$config_check" == *"profiles.yaml"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} Configuration files present [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Config directory contents: $config_check [warning]"
|
|
fi
|
|
|
|
# Check if hub directory exists
|
|
echo " Checking hub directory..."
|
|
hub_check=$(cmd_clean "$node" "test -d /var/lib/crowdsec/hub && echo 'exists' || echo 'missing'")
|
|
if [[ "$hub_check" == *"exists"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} Hub directory exists [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} Hub directory status: $hub_check [warning]"
|
|
fi
|
|
done
|
|
|
|
# ============================================================================
|
|
# Functional Tests - Service Restart
|
|
# ============================================================================
|
|
|
|
echo ""
|
|
echo "Step 14: Testing Service Restart..."
|
|
echo ""
|
|
|
|
for node in $TARGET; do
|
|
echo "Testing service restart on $node..."
|
|
|
|
# Restart the service
|
|
echo " Restarting CrowdSec service..."
|
|
restart_result=$(cmd_clean "$node" "systemctl restart crowdsec 2>&1 && echo 'restart_ok' || echo 'restart_failed'")
|
|
if [[ "$restart_result" == *"restart_ok"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} Service restart command successful [pass]"
|
|
else
|
|
echo -e " ${RED}✗${NC} Service restart failed: $restart_result [fail]"
|
|
fi
|
|
|
|
# Wait for service to come back up
|
|
echo " Waiting for service to recover..."
|
|
wait_for_service "$node" "crowdsec" --timeout=60
|
|
wait_for_port "$node" "$CROWDSEC_API_PORT" --timeout=30
|
|
|
|
# Verify service is active after restart
|
|
echo " Verifying service is active after restart..."
|
|
assert_service_active "$node" "crowdsec"
|
|
|
|
# Verify LAPI is responsive after restart
|
|
echo " Verifying LAPI responds after restart..."
|
|
lapi_after=$(cmd_clean "$node" "cscli lapi status 2>&1 || true")
|
|
if [[ "$lapi_after" == *"successfully interact"* ]] || [[ "$lapi_after" == *"You can successfully"* ]]; then
|
|
echo -e " ${GREEN}✓${NC} LAPI responsive after restart [pass]"
|
|
else
|
|
echo -e " ${YELLOW}!${NC} LAPI status after restart: $lapi_after [warning]"
|
|
fi
|
|
done
|
|
|
|
# ============================================================================
|
|
# NIS2 Compliance Summary
|
|
# ============================================================================
|
|
|
|
echo ""
|
|
echo "========================================"
|
|
echo "NIS2 Compliance Verification Summary"
|
|
echo "========================================"
|
|
echo ""
|
|
echo "Article 21(2)(b) - Incident Handling:"
|
|
echo " ✓ CrowdSec provides automated threat detection"
|
|
if [ "$FIREWALL_BOUNCER_ENABLED" = "true" ]; then
|
|
echo " ✓ Firewall bouncer enables real-time response"
|
|
fi
|
|
if [ "$HAPROXY_BOUNCER_ENABLED" = "true" ]; then
|
|
echo " ✓ HAProxy SPOA bouncer enables layer 7 protection"
|
|
fi
|
|
echo ""
|
|
echo "Article 21(2)(d) - Network Security:"
|
|
echo " ✓ IDS/IPS capabilities via CrowdSec engine"
|
|
if [ "$FIREWALL_BOUNCER_ENABLED" = "true" ]; then
|
|
echo " ✓ Automated IP blocking via firewall bouncer (nftables)"
|
|
fi
|
|
if [ "$HAPROXY_BOUNCER_ENABLED" = "true" ]; then
|
|
echo " ✓ Application-layer protection via HAProxy SPOA"
|
|
fi
|
|
echo ""
|
|
echo "Article 21(2)(g) - Security Monitoring:"
|
|
echo " ✓ SSH authentication monitoring enabled"
|
|
echo " ✓ System/kernel log monitoring enabled"
|
|
echo " ✓ Centralized decision logging active"
|
|
if [ "$AUDITD_ENABLED" = "true" ]; then
|
|
echo " ✓ Kernel-level auditd integration enabled"
|
|
echo " ✓ NixOS wrapper whitelist configured"
|
|
fi
|
|
echo ""
|
|
echo "Article 21(2)(i) - Human Resources Security:"
|
|
echo " ✓ Protection against credential attacks"
|
|
echo ""
|
|
|
|
# ============================================================================
|
|
# Test Summary
|
|
# ============================================================================
|
|
|
|
_end=$(date +%s)
|
|
|
|
echo ""
|
|
echo "========================================"
|
|
echo "CrowdSec Test Summary"
|
|
echo "========================================"
|
|
|
|
printf '+ setup %s\n' $(printTime $_start $_setup)
|
|
printf '+ tests %s\n' $(printTime $_setup $_end)
|
|
printf '= TOTAL %s\n' $(printTime $_start $_end)
|
|
|
|
echo ""
|
|
echo "========================================"
|
|
echo "CrowdSec Test Complete"
|
|
echo "========================================"
|