Securing SSH access with Fail2Ban and key-based authentication

Server administrators across Australia, from boutique consultancies in Surry Hills to engineering teams in Perth, share one persistent headache: opportunistic SSH brute-force traffic. Public-facing Linux boxes see thousands of password guesses per day from botnets scanning every routable address online. With the Australian Cyber Security Centre's Essential Eight recommending key-based and multi-factor approaches for administrative access, the case for tightening remote shell access has never been stronger.

Key-based authentication replaces shared secrets with asymmetric cryptography. The private key stays on the operator's laptop, often protected by a hardware token or passphrase, while the public key lives on the server inside an authorised_keys file. Even if an attacker scrapes credentials from a third-party breach, the absence of a usable password means a stolen hash is worthless against a properly configured daemon.

Fail2Ban complements this by parsing log files for repeated authentication failures and dynamically rewriting firewall rules to block offending IPs. The two layers work together: keys prevent password guessing from succeeding, while Fail2Ban adds friction for anyone still attempting it, slowing scanners and freeing operators from reviewing auth logs at 3 a.m. AEDT.

This guide covers practical hardening steps that work on common distributions in Australian data centres like NextDC or under a desk in a Brisbane home office, building on patterns documented at karlkatzke.com.

The Australian threat picture

Brute-force traffic on TCP port 22 is global, but Australian networks see specific patterns. Scans often originate from compromised hosts in South-East Asia and Eastern Europe, and burst timing frequently aligns with Northern Hemisphere business hours, which conveniently fall outside local working time. A typical week of auth.log on a vanilla Ubuntu instance exposed to the NBN records tens of thousands of attempts against the root account alone, even on servers that disable password authentication.

Compliance pressures compound the operational reality. The Notifiable Data Breaches scheme treats credential compromise as a reportable event when personal information is involved. The Essential Eight maturity model from ACSC, available through cyber.gov.au, treats administrative access as a critical control surface worth meeting at maturity-2 or maturity-3, the level most Australian organisations target this financial year.

Migrating to public key authentication

Generating a key pair takes seconds on a modern workstation. The ed25519 algorithm offers strong security with short key material, making it the sensible default for new deployments. Operators should back the private key with a passphrase and, where possible, store it on a hardware token such as a YubiKey.

Deploying the public key requires nothing more exotic than appending it to ~/.ssh/authorized_keys on the target host. The file's mode must be 600 and the containing directory 700, a small detail that trips up many first attempts. Tools like ssh-copy-id automate the transfer and permission fix, which is handy when seeding keys across a fleet spun up in ap-southeast-2.

Before disabling password authentication, verify that key-based login actually works. Locking yourself out of a remote system hosted in Sydney while you are sitting in a Melbourne coworking space is a miserable way to spend an arvo. Test from a second session, confirm the key prompts correctly, and only then edit /etc/ssh/sshd_config to set PasswordAuthentication no. A reload of the daemon applies the change without dropping the active session.

For teams that need short-lived credentials, signed certificates from an internal SSH CA scale better than distributing individual public keys. HashiCorp Vault or Smallstep can issue user and host certificates with a validity window that expires automatically, which suits consultants parachuting into a project for a few weeks.

Tightening the SSH daemon configuration

The stock sshd_config file ships with permissive defaults that prioritise compatibility over security. PermitRootLogin no removes the most attacked username from the field entirely. MaxAuthTries 3 caps the number of attempts per connection, and LoginGraceTime 30 ensures half-open sessions do not linger.

Restricting which users can authenticate is another high-leverage change. An AllowGroups ssh-users line, combined with a dedicated Unix group containing only the operators who legitimately need shell access, narrows the attack surface dramatically. For organisations with a stable user base, this single directive often eliminates the majority of noise in auth logs.

Network-level controls add another layer. Australia's geolocation distribution means many teams can scope firewall rules to a handful of ASN ranges without inconveniencing staff. AWS Security Groups, Azure NSGs, and on-prem iptables rulesets all support CIDR-based allow-lists, and combining them with a bastion host behind a single hardened entry point is a common pattern across Australian financial-services and government tenants.

While digital access gets most of the attention, physical environment matters too. A well-ventilated rack with sensible cable management keeps hardware alive, and modest touches like airflow-friendly planters with built-in drainage can keep ambient temperature down in a small home-office closet.

Installing and configuring Fail2Ban

Fail2Ban is available in the default repositories of Debian, Ubuntu, Fedora, and RHEL derivatives, so installation is a single package manager call. On Ubuntu, apt install fail2ban pulls in the daemon, a default jail configuration, and a handful of stock filters. The systemd unit starts automatically and survives reboots, which matters for unattended servers in regional offices.

The recommended practice is to override defaults in /etc/fail2ban/jail.local rather than editing the package-managed jail.conf. The .local file is read after the defaults, so its values win without risking drift when the package updates. A minimal SSH jail sets enabled = true, points logpath at the auth log, and chooses sensible maxretry and findtime values. Five failed attempts inside ten minutes is a reasonable starting point.

Bantime choices reflect operational philosophy. A short ban of ten minutes frustrates casual bots but does little against patient attackers. Many Australian operators opt for an escalating scheme where repeated offenders graduate to week-long bans. Recidive jails, which watch the Fail2Ban log itself for repeat offenders, implement this pattern with a few lines of configuration.

Writing filters and tuning jails

Filters live in /etc/fail2ban/filter.d/ and consist of regular expressions matched against log lines. The bundled sshd.conf filter covers most OpenSSH failure modes out of the box, including pre-auth disconnects, invalid users, and exhausted max-auth-tries. Custom filters are useful when running SSH on non-standard ports, behind a TCP load balancer, or wrapped in a container that loses the original source IP.

Common attack patterns worth filtering:

  • Rapid succession of authentication failures from a single IP
  • Attempts to authenticate as non-existent users
  • Repeated connection resets during the key exchange phase
  • Scans targeting the root account specifically
  • Use of protocol versions below SSHv2

Filter verification deserves attention. fail2ban-regex lets you replay a log file against a filter and see exactly which lines matched, which were ignored, and where false positives might creep in. Running this against a representative sample of auth.log before deploying a new filter is a habit that pays for itself the first time it catches a regex that would have banned half the office.

Jail policies compose filters with actions. The default iptables-multiport action blocks the offending IP at the firewall, while sendmail notifies an operator by email. For teams on cloud platforms, the cloudflare, route53, and aws action sets push block entries into managed edge services, which is the only practical way to protect hosts behind a shared NAT or load balancer.

Observability and ongoing maintenance

Hardening is not a one-off project. Logs need somewhere to land where they will actually be read, and SSH is no exception. Shipping auth.log to a central syslog receiver, an Elastic stack, or a SaaS platform like Datadog or Splunk turns the firehose into queryable data. From there, dashboards can show authentication failure rates by source country, top targeted usernames, and the effectiveness of jail actions.

Useful log signals to track:

  • Authentication failures per minute, broken down by source IP
  • Successful logins from new geographic regions
  • Jail actions triggered per hour, with bantime distribution
  • Disabled accounts still receiving login attempts
  • Configuration changes applied to sshd_config

Alerting thresholds should reflect baseline traffic rather than absolute numbers. A server that normally sees two failures per hour does not warrant a page at ten, but a sudden spike to five hundred usually indicates a coordinated scan. Australian teams running 24/7 operations often route critical alerts through PagerDuty or Opsgenie, while smaller outfits rely on Slack webhooks triggered by Fail2Ban actions.

Regular reviews catch drift. Quarterly, run sshd -T to dump the effective configuration and diff it against the committed baseline. Re-run fail2ban-regex against fresh log samples, retire filters that no longer match anything useful, and rotate host keys on a sensible schedule. The few minutes spent each quarter are cheaper than the incident response bill that follows a successful intrusion.

If you would like to chat about a specific migration or hardening project, my professional background outlines the kind of infrastructure and cloud work I take on. Happy to hear from teams across Australia and beyond who are tightening their own remote access posture.

Time to lock down your own hosts. Start by enabling key-based authentication on a non-production box this week, then layer in Fail2Ban once you are comfortable reading the logs. Automate the configuration through your tool of choice once the basics are stable, and revisit the rules every quarter or whenever a major OpenSSH release lands.

Experience

Information Technology Consulting

Independent Practice

Provides IT consulting services focused on infrastructure planning, cloud migration strategy, and systems architecture. Engagements draw on years of hands-on sysadmin and development experience across Linux, Windows, and hybrid environments.

K9 Search & Rescue Volunteer

Ongoing

Active participant in K9 Search & Rescue operations, combining technical logistics skills with field support for canine search teams.

Karl Katzke's Blog

October 2006 – May 2014

Published a long-running personal technology blog covering cloud vs. in-house infrastructure, F# and Mono on OSX, hardware vendor critiques, RAID card performance analysis, and sysadmin storytelling. Notable posts include "When Sysadmins Ruled the Earth" (May 15, 2014) and "Getting Started with F# and Mono on OSX" (December 22, 2012).

Credentials

A small badge icon with a shield shape in muted blue tones on a light background

Systems Administration

Deep experience with Linux (RHEL, SLES, CentOS), high-availability clusters, and STONITH configurations.

A small badge icon with a gear shape in muted blue tones on a light background

Cloud Infrastructure

Practical knowledge of AWS EC2, reserved instances, and cost analysis for cloud vs. on-premises deployments.

A small badge icon with a code symbol in muted blue tones on a light background

Development

Proficient in F#, PHP (Symfony), and cross-platform tooling including Mono and MonoDevelop on OSX.

Studies

F# & Functional Programming

Self-directed, 2012

Explored strongly typed functional programming with F# on OSX using the Mono runtime. Published a detailed getting-started guide covering toolchain setup and cross-platform game development research.

High-Availability & Cluster Management

Professional Development, 2009

Configured and documented crm_mon email alerting for STONITH events on SLES11-HAE clusters, integrating with Nagios monitoring for production environments.

Hardware & Storage Performance

Ongoing

Conducted hands-on benchmarking of SATA/SAS RAID controllers including HighPoint RocketRaid 2740 and LSI/SuperMicro AOC-USASLP2-H8iR, comparing against software RAID configurations.

Skills

A small icon representing a server with clean geometric lines in slate blue

Linux Administration

RHEL, SLES, CentOS — package management, kernel tuning, HA clustering, and monitoring integration.

A small icon representing a cloud shape with clean geometric lines in slate blue

Cloud Architecture

AWS EC2, reserved-instance planning, cost modeling, and hybrid infrastructure strategy.

A small icon representing code brackets with clean geometric lines in slate blue

F# & .NET/Mono

Functional programming on OSX, MonoDevelop toolchain, and cross-platform game-dev exploration.

A small icon representing a database cylinder with clean geometric lines in slate blue

PHP & Symfony

Web application development with the Symfony framework and the broader PHP ecosystem.

A small icon representing a storage drive with clean geometric lines in slate blue

Storage & RAID

SATA/SAS controller evaluation, md RAID configuration, and performance benchmarking.

A small icon representing a shield with clean geometric lines in slate blue

High Availability

Pacemaker, STONITH, crm_mon alerting, and Nagios integration for production cluster monitoring.