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.
Karl Katzke