Package: sshguard Version: 2.4.2-1+b2 Severity: normal Consider this change to prevent sshguard triggering itself (https://bugs.debian.org/928525):
https://salsa.debian.org/debian/sshguard/-/commit/3563a43968bf1e143f2a1b20d06a95c48a95570b - LOGREADER="LANG=C /bin/journalctl -afb -p info -n1 -o cat SYSLOG_FACILITY=4 SYSLOG_FACILITY=10" + LOGREADER="LANG=C journalctl -afb -p info -n1 -t sshd -o cat" In 2019, "apt install sshguard" was sufficient to protect postfix and dovecot. In 2023, "apt install sshguard" only protects openssh-server. It's not hard to fix this on each host if you're experienced, but I really liked being able to tell newbies: Just "apt install sshguard". Unlike fail2ban, it protects everything by default (except for apache2/nginx). It doesn't require any opt-in configuration (except for apache2/nginx). It defaults to modern nft sets, not the MUCH slower raw xtables rules (not even ipset!). It uses a C parser instead of Python regexps, so it has lower overheads. Attached is the sshguard.conf I've been running in production, as a reference. (It's probably not suitable for upstreaming into Debian as-is, though.) The important things are: 0. Watch for events from more than just openssh-server. Unfortunately journalctl does'nt provide an easy way to say "all events EXCEPT the ones from sshguard@localhost", so I simply listed every daemon in Debian whose logs sshguard understands. I haven't tried to solve "ingest sshguard events from OTHER hosts", which is why sshguard reacts to its own logs at all. 1. Use --unit= instead of --identifier=. I did this because e.g. postfix uses many different identifiers, and because when just reading the source, you can work out the unit(s) easier than the identifier(s). You could continue using -t, but you can't use a *mix* of -t and -u, because -tX -tY -tZ -uA -uB -uC means (X ∨ Y ∨ Z) ∧ (A ∨ B ∨ C). Also --unit= is harder to spoof, which may be a good thing or a bad thing. I don't know what the implications are for systemd-journal-remote and systemd-container. 2. Watch for CLF logs (sshguard won't break if they're missing) If they aren't used, the only impact is 1 warning when sshguard starts. I added the nginx and apache2 default paths, but there are probably others I haven't considered. Please consider making Debian's sshguard default to protecting postfix/dovecot (as it used to) and maybe also nginx/apache2 (new).
# Written for sshguard 2.4.2. # # The way sshguard is laid out internally is confusing. # # • sshguard is a shell script that creates a pipeline like this: # # ( $LOGREADER & tail -Fn0 $FILES ) | sshg-parser | sshg-blocker | $BACKEND # # BACKEND *must* be set. # Choices are https://bitbucket.org/sshguard/sshguard/src/master/src/fw/ # # At least one of LOGREADER and FILES *must* be set. # Both are used if both are set. # # This file is parsed by sshguard, which is a shell script. # So you could do things like # # for i in /etc/sshguard/sshguard.conf.d/*.conf; do [ -e "$i" ] && . "$i"; done # # • The following variables are used by sshg-blocker, but NOT understood by it! # sshguard reads them in and converts them to -x Y single-letter getopts CLI args. # The defaults are set here: # # https://bitbucket.org/sshguard/sshguard/src/a5ea6ffac184b6cec4f59f576b941247cb7d0c8f/src/blocker/sshguard_options.c#lines-41:52 # # ============== ============ ================== ======= # sshguard.conf sshg-blocker sshguard_options.c default # ============== ============ ================== ======= # THRESHOLD -a abuse_threshold 30 # BLACKLIST_FILE -b blacklist_filename n/a # BLOCK_TIME -p pardon_threshold 120 # DETECTION_TIME -s stale_threshold 1800 # IPv6_SUBNET -N subnet_ipv6 128 (i.e. single host) # IPV4_SUBNET -n subnet_ipv4 32 (i.e. single host) # WHITELIST_FILE -w n/a n/a (but Debian sets /etc/sshguard/whitelist) # ============== ============ ================== ======= # # • In sshguard.conf, WHITELIST_FILE and BLACKLIST_FILE may be whitespace-separate lists of files. # Each file MUST begin with "/" or ".", or sshg-blocker will treat it as a value (not a file containing values). # # • AFAICT there is no reason LOGREAD could not simply be "journalctl -f", i.e. reading EVERY log event. # The only reasons to narrow this down are: # # • To reduce CPU load (sshg-parser does less work) # • To avoid sshguard treating its own log events as evidence-of-attack logs. # # Debian default is # # LANG=C journalctl -afb -p info -n1 -t sshd -o cat # # This is very silly because "-t sshd" will prevent any log events except openssh-server being handled! # I think we should instead have something like this: # # journalctl # --follow # be like "tail -F" # --lines=0 # don't show old events (∵ sshg-parser ignores timestamps, so historical events would be treated as NEW!) # --boot=0 # current boot (--lines=0 already implies this, but being explicit might avoid some stat(2) calls) # --all # include non-ASCII bytes; don't truncate long lines # --output=cat # omit leading "timestamp hostname process[pid]: ". # --system # ignore spoofing attacks by local users (not needed?) # --priority=info # IFF we can guarantee ALL sshg-parser's events are above this threshold! # --unit=ssh.service # limit by systemd unit, rather than syslog tag (implicitly, ignore sshguard's own log events!) # --unit=ssh@*.service # --unit=postfix@*.service # --unit=dovecot.service # --unit=... # # FIXME: will journalctl show logs from systemd containers? # i.e. without -M is it -M <host system> or -M <all> ? # I suspect the answer is "you need --merge", BLERGH. # # # A high-level list of services sshguard protects is here: # https://bitbucket.org/sshguard/sshguard/src/a5ea6ffac184b6cec4f59f576b941247cb7d0c8f/src/common/attack.h#lines-27:52 # # The gritty details are in these files: # https://bitbucket.org/sshguard/sshguard/src/master/src/parser/attack_scanner.l # https://bitbucket.org/sshguard/sshguard/src/master/src/parser/attack_parser.y # https://bitbucket.org/sshguard/sshguard/src/master/src/parser/tests.txt # # attack.h systemd unit # ========= ============ # ALL ? # SSH ssh ssh@* (Debian default is ssh.service. tinyssd/dropbear NOT handled AFAICT) # SSHGUARD sshguard (NOT included, because meant for "remote" sshguards, not self!) # BIND named # UWIMAP - (dead https://sources.debian.org/src/uw-imap/8%3A2007f~dfsg-7/debian/changelog/#L77-L78) # DOVECOT dovecot (PrisonPC uses dovecot@*.service!) # CYRUSIMAP cyrus-imapd # CUCIPOP - (dead https://sources.debian.org/src/cucipop/) # EXIM exim4-base # SENDMAIL sendmail (/etc/init.d/sendmail via systemd-sysv-generator) # POSTFIX postfix postfix@* # OPENSMTPD opensmtpd # COURIER courier-imap-ssl courier-imap courier-ldap courier-mlm courier-msa courier-mta-ssl courier-mta courier courierfilter courier-pop-ssl courier-pop (WHICH OF THESE???) # FREEBSDFTPD - (ftpd shipped with FreeBSD) # PROFTPD proftpd proftpd@* # PUREFTPD - (not in Debian? https://en.wikipedia.org/wiki/Pure-FTPd) # VSFTPD vsftpd # COCKPIT cockpit cockpit-session@* cockpit-motd cockpit-wsinstance-http-redirect cockpit-wsinstance-http cockpit-wsinstance-https-factory@* cockpit-wsinstance-https@* (WHICH OF THESE???) # CLF_UNAUTH - (use FILES=) # CLF_PROBES - (use FILES=) # CLF_LOGIN_URL - (use FILES=) # OPENVPN openvpn openvpn@* openvpn-server@* openvpn-client@* (WHICH OF THESE???) # OPENVPN_PS # GITEA gitea (not in Debian... YET https://bugs.debian.org/935834 https://github.com/go-gitea/gitea/blob/main/contrib/systemd/gitea.service) # # # • By default it will protect every service it gets logs for. # So as long as you have liberal LOGREAD and/or FILES lines, # you don't need to go "oh, I installed postfix - I had better enable postfix in sshguard". # # • FILES (tail -Fn0) will work Just Fine™ if you tell it to tail files that don't exist yet. # You'll just get one warning message when tail starts. # Therefore should ALWAYS include well-known NCSA logfiles for nginx/apache! # # https://en.wikipedia.org/wiki/Common_Log_Format # # FIXME: can I get a reasonably exhaustive list of NCSA-format logs generated by Debian packages by default? # e.g. what about things like uwsgi, munin, gitit that have built-in web servers? # # FIXME: is checking nginx/apache logs only useful when nginx/apache itself does authentication (https://en.wikipedia.org/wiki/Basic_access_authentication)? # Or can it also help protect against brute-forcing accounts in wordpress/mediawiki/moodle/...? # # # sshguard example: # https://bitbucket.org/sshguard/sshguard/src/master/examples/sshguard.conf.sample # Debian default: # https://sources.debian.org/src/sshguard/2.4.2-1/debian/sshguard.conf.linux/ # NOTE: I did not include ALL the systemd units (see above); # I omitted ones Cyber IT will never ever EVER see in the wild. BACKEND="/usr/libexec/sshguard/sshg-fw-nft-sets" LOGREADER="journalctl --follow --lines=0 --boot=0 --all --output=cat --system --priority=info --unit=ssh.service --unit=ssh@*.service --unit=named.service --unit=dovecot.service --unit=dovecot@*.service --unit=exim4-base.service --unit=sendmail.service --unit=postfix.service --unit=postfix@*.service" FILES="/var/log/nginx/access.log /var/log/apache2/access.log " WHITELIST_FILE=/etc/sshguard/whitelist # Block IPv6 by /48 (typical ISP per-subscriber range), not by /128 (sshguard default) IPV6_SUBNET=48