#!/usr/bin/env bash # policy: dev_mon_clamscan — daily ClamAV + rkhunter + chkrootkit scan at 02:00, # with results reported natively to CheckMK. # Applied when the host is a member of the dev_mon_clamscan host-group. # # Results are handed to CheckMK via a local check (ansipa_clamscan) rather than # uploaded to an SMB share: the CheckMK agent (installed by dev_mon_base) picks # up the local check and surfaces the scan status as a monitored service. Add a # host to BOTH dev_mon_clamscan (to run the scan + emit the check) and dev_mon_base # (to install the agent that collects it) to see results in CheckMK. SCAN_CRON="$CRON_DIR/ansipa-clamscan" SCAN_SCRIPT="/usr/local/bin/ansipa-clamscan.sh" SCAN_LOG="/var/log/ansipa-clamscan.log" CMK_LOCAL_DIR="/usr/lib/check_mk_agent/local" CMK_CHECK="$CMK_LOCAL_DIR/ansipa_clamscan" if [[ "$WANT_CLAMSCAN" == true ]]; then # (Re-)write the scan script so it stays current with this version of the enforcer. cat > "$SCAN_SCRIPT" <<'SCAN' #!/bin/bash # ansipa-clamscan — daily ClamAV / rkhunter / chkrootkit run. # Managed by ansipa-enforce-policies — do not edit manually. # Results are read by the ansipa_clamscan CheckMK local check; no SMB upload. LOG=/var/log/ansipa-clamscan.log # `hostname` (inetutils) may be absent on minimal Arch; resolve without it. HOSTNAME=$( { command -v hostname >/dev/null 2>&1 && hostname -f 2>/dev/null; } \ || hostnamectl --static 2>/dev/null || cat /etc/hostname 2>/dev/null \ || cat /proc/sys/kernel/hostname 2>/dev/null ) DATE=$(date +%Y-%m-%d) { echo "=== ansipa-clamscan: $DATE $HOSTNAME ===" if command -v freshclam &>/dev/null; then freshclam --quiet 2>/dev/null || true fi if command -v clamscan &>/dev/null; then clamscan -r --infected --quiet /home /etc /tmp /var/tmp 2>/dev/null || true fi if command -v rkhunter &>/dev/null; then rkhunter --update --quiet 2>/dev/null || true rkhunter --check --skip-keypress --quiet 2>/dev/null || true fi if command -v chkrootkit &>/dev/null; then chkrootkit 2>/dev/null || true fi echo "=== scan complete ===" } >> "$LOG" 2>&1 SCAN chmod 755 "$SCAN_SCRIPT" # ── CheckMK local check: report scan results to CheckMK ─────────────────── # Emitted regardless of whether the CheckMK agent is present yet; once # dev_mon_base installs the agent, it collects this check automatically. mkdir -p "$CMK_LOCAL_DIR" cat > "$CMK_CHECK" <<'CHECK' #!/bin/bash # ansipa_clamscan — CheckMK local check reporting the ansipa-clamscan result. # Managed by ansipa-enforce-policies (dev_mon_clamscan) — do not edit manually. LOG=/var/log/ansipa-clamscan.log CLAMDB=/var/lib/clamav/main.cvd [[ -f /var/lib/clamav/main.cld ]] && CLAMDB=/var/lib/clamav/main.cld if [[ ! -f "$LOG" ]]; then echo "1 Ansipa_ClamScan - No scan has run yet (scans run daily at 02:00)." exit 0 fi LAST_DATE=$(grep "^=== ansipa-clamscan:" "$LOG" 2>/dev/null | tail -1 \ | grep -oE "[0-9]{4}-[0-9]{2}-[0-9]{2}" || echo "") INFECTED=$(grep -c "FOUND$" "$LOG" 2>/dev/null) || INFECTED=0 RKWARN=$(grep -c "Warning:" "$LOG" 2>/dev/null) || RKWARN=0 DB_DAYS=999 if [[ -f "$CLAMDB" ]]; then DB_DAYS=$(( ( $(date +%s) - $(stat -c %Y "$CLAMDB" 2>/dev/null || echo 0) ) / 86400 )) fi PERF="infected=${INFECTED};1;1 rkhunter_warnings=${RKWARN} db_age_days=${DB_DAYS};7;30" if [[ -z "$LAST_DATE" ]]; then echo "1 Ansipa_ClamScan ${PERF} No completed scan found yet" elif [[ "$INFECTED" -gt 0 ]]; then echo "2 Ansipa_ClamScan ${PERF} INFECTED: ${INFECTED} threat(s) — last scan: ${LAST_DATE}" elif [[ "$DB_DAYS" -gt 7 ]]; then echo "1 Ansipa_ClamScan ${PERF} ClamAV DB stale (${DB_DAYS}d). Last scan: ${LAST_DATE}" elif [[ "$RKWARN" -gt 0 ]]; then echo "1 Ansipa_ClamScan ${PERF} Clean, but ${RKWARN} rkhunter warning(s) — last scan: ${LAST_DATE}" else echo "0 Ansipa_ClamScan ${PERF} Clean — last scan: ${LAST_DATE}, DB age: ${DB_DAYS}d" fi CHECK chmod 755 "$CMK_CHECK" if [[ ! -f "$SCAN_CRON" ]]; then log "Enabling daily ClamAV scan (dev_mon_clamscan) with CheckMK reporting" # /etc/cron.d may not exist yet if cron isn't installed — create it so the # drop-in lands (cronie/anti-malware tooling comes via dev_mod_anti-malware). mkdir -p "$CRON_DIR" cat > "$SCAN_CRON" <<'CRON' # ansipa-dev_mon_clamscan: managed by ansipa-enforce-policies — do not edit manually. # Install scan tools by adding the host to the dev_mod_anti-malware group. # Results appear in CheckMK (Ansipa_ClamScan) when the host is also in dev_mon_base. 0 2 * * * root /usr/local/bin/ansipa-clamscan.sh CRON chmod 644 "$SCAN_CRON" fi else if [[ -f "$SCAN_CRON" || -f "$SCAN_SCRIPT" || -f "$CMK_CHECK" ]]; then rm -f "$SCAN_CRON" "$SCAN_SCRIPT" "$CMK_CHECK" "$SCAN_LOG" log "Removed dev_mon_clamscan policy (host left dev_mon_clamscan group)" fi fi