Initial version: npm-scanner image, filters, entrypoint, watcher, testbed
- Image based on crazymax/fail2ban:1.1.1 with inotify-tools - Filters npm-scanner and npm-wplogin, tested with fail2ban-regex in the build - jail.local generated from .env, optional npm-wplogin and recidive - Watcher reloads the jails when NPM creates a new proxy host log - check command, docs, testbed for LXC Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
commit
d7dcd9d6b1
29 files changed
+1163
No files matched your search
@@ -0,0 +1,70 @@
|
||||
#!/usr/bin/env bash
|
||||
# npm-scanner – watch the NPM log directories for new hosts
|
||||
# https://git.retronerd.at/schiwagoa/npm-scanner
|
||||
#
|
||||
# fail2ban resolves logpath globs only when a jail starts. A proxy host created later
|
||||
# in NPM would therefore not be watched. This script reloads the jails as soon as a
|
||||
# log file appears that no jail watches yet. Bans survive the reload.
|
||||
#
|
||||
# npm-newlog-watch.sh <dir> [<dir> …]
|
||||
# NPM_SCANNER_JAILS="npm-scanner npm-wplogin" jails that read NPM logs
|
||||
|
||||
set -uo pipefail
|
||||
|
||||
JAILS=${NPM_SCANNER_JAILS:-npm-scanner}
|
||||
SETTLE=${NEWLOG_SETTLE_SECONDS:-5}
|
||||
|
||||
log() { echo "[npm-newlog] $*"; }
|
||||
|
||||
[[ $# -gt 0 ]] || { log "no directories given"; exit 1; }
|
||||
|
||||
# Wait until the fail2ban server answers (max. 5 minutes).
|
||||
for _ in $(seq 1 300); do
|
||||
fail2ban-client ping >/dev/null 2>&1 && break
|
||||
sleep 1
|
||||
done
|
||||
if ! fail2ban-client ping >/dev/null 2>&1; then
|
||||
log "fail2ban does not answer – watcher stopped"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Same mode the crazymax entrypoint chose (nft or legacy) is active by now.
|
||||
chain=$(grep -m1 -oE 'chain=[A-Za-z0-9_-]+' /etc/fail2ban/jail.local | cut -d= -f2)
|
||||
if [[ -n "$chain" ]] && ! iptables -n -L "$chain" >/dev/null 2>&1; then
|
||||
log "WARNING: iptables chain $chain does not exist – bans will fail. Is Docker running on the host?"
|
||||
fi
|
||||
|
||||
watched() {
|
||||
local file=$1 jail
|
||||
for jail in $JAILS; do
|
||||
fail2ban-client get "$jail" logpath 2>/dev/null | grep -qF -- "$file" && return 0
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
declare -A tried=()
|
||||
|
||||
log "watching $* (jails: $JAILS)"
|
||||
inotifywait -m -q -e create -e moved_to --format '%w%f' "$@" | while read -r file; do
|
||||
case "${file##*/}" in
|
||||
proxy-host-*_access.log|default-host_access.log|fallback_access.log|fallback_http_access.log) ;;
|
||||
*) continue ;;
|
||||
esac
|
||||
[[ -n "${tried[$file]:-}" ]] && continue
|
||||
|
||||
# Give NPM time to finish writing the config, and debounce log rotation.
|
||||
sleep "$SETTLE"
|
||||
[[ -f "$file" ]] || continue
|
||||
watched "$file" && continue
|
||||
|
||||
tried[$file]=1
|
||||
for jail in $JAILS; do
|
||||
# npm-wplogin only reads proxy-host logs.
|
||||
[[ "$jail" == npm-wplogin && "${file##*/}" != proxy-host-* ]] && continue
|
||||
if fail2ban-client reload "$jail" >/dev/null 2>&1; then
|
||||
log "new log $file – $jail reloaded"
|
||||
else
|
||||
log "WARNING: reload of $jail failed for $file"
|
||||
fi
|
||||
done
|
||||
done
|
||||
Reference in new issue
Block a user