sshd — alert on auth-fail spike (before fail2ban bans)
fail2ban bans sources by threshold — but a campaign hits from thousands of IPs at 1 attempt each. None get banned individually, but overall noise on the ssh port is huge.
Recipe
#!/usr/bin/env bash
# /etc/cron.d/sshd-spike
# */5 * * * * root /opt/sshd-spike.sh
WINDOW=${WINDOW:-5min}
THRESH=${THRESH:-100} # fails / 5 min
COUNT=$(journalctl -u ssh --since "$WINDOW ago" --no-pager 2>/dev/null \
| grep -cE 'Failed password|Invalid user|maximum authentication attempts')
if [ "${COUNT:-0}" -gt "$THRESH" ]; then
UNIQUE=$(journalctl -u ssh --since "$WINDOW ago" --no-pager 2>/dev/null \
| grep -oE 'from [0-9.]+' | sort -u | wc -l)
curl -fsS "$HEARTBEAT_URL" --data "ssh_fails=$COUNT,unique_ips=$UNIQUE"
exit 2
fi
echo "OK ($COUNT auth-fails / 5m)"
Same thing in Enterno.io
Wrap in an Enterno heartbeat — see a distributed brute-force campaign before it lucks into one weak ssh account.
Related recipes
Site is on the HSTS preload list, but after an nginx refactor the header is gone. In 3 months the domain will be removed from the preload list. Need a daily check.
A name-server misconfig leaks AXFR to the internet — every subdomain, MX, TXT (including SPF/DKIM keys) is visible to attackers. Daily check with alert.
An attacker is hammering a `limit_req_zone` — legit traffic now eats 429s too. The access log shows it but nobody is watching.