If you've read my Open SSH series, perhaps even if you haven't, you are probably aware of the power SSH offers to those who know how to use it. There are many ways to protect the service from unauthorized usage, focusing on self-contained or single host solutions, one finds two common flavors: those which make use of the Linux kernel's packet filtering tools (netfilter and iptables), and those which rely on Wietse Venema's TCP Wrappers. Netfilter certainly offers power and flexibility, but this may be at the cost of simplicity and management ease. While no security measure ought to be implemented blindly, there is an undeniable benefit to simple measures which can be configured quickly and with little fuss — in this arena, TCP Wrappers stands tall.
While TCP Wrappers is a tool worth knowing well, it also offers a flexibility which can lead to complexity; fortunately for those unfamiliar with it, or those who simply want to block ubiquitous Internet port scanners with a low management tool, there is DenyHosts. In essence, DenyHosts watches a system's logs for failed logins which exceed configurable thresholds, adding offending IP addresses to TCP Wrapper's deny list.
The configuration has fairly sensible defaults, but certain parameters merit careful consideration. In the common case of port scans from an interminable list of different source IP addresses, it probably makes sense to periodically purge hosts.deny (e.g. PURGE_DENY = 5d) while setting a threshold for permanent banishment (e.g. PURGE_THRESHOLD = 2).
The ability to set a lower threshold for failed logins to specific accounts (e.g. root, nobody, www-data) is nice, but the default configuration sets different thresholds for valid vs invalid user accounts. This seems unnecessary, as any attacker is unlikely to guess the password for an account which does not exist; moreover, this configuration makes it possible to enumerate valid login accounts. The best threshold value depends on how many legitimate shell users exists, whether authentication is interactive or dual key, etc., but I strongly recommend setting DENY_THRESHOLD_INVALID and DENY_THRESHOLD_VALID to the same value.
Perhaps my favorite feature of Denyhosts is the ability to enable server synchronization (SYNC_SERVER), which allows the server to share blocked IP addresses with a central server at denyhosts.net. Whilst it would be nice if the author would publish the XML RPC server daemon under an open source license, the availability of an active public server seems have sufficiently offset the incentive to reinvent this particular wheel.