SSH Best Practices and Security Hardening

SSH Series: Part 4
Posted by Munish Mehta on Friday, January 24, 2025
Fortify Your Remote Access: Hardening SSH for Unyielding Security

This article is part of a series.

ssh

In the previous parts of SSH series, I introduced SSH, demonstrated setup procedures, and explored key-based authentication. Now, it’s time to delve into security hardening—a critical practice for any production system. A properly hardened SSH setup helps protect against brute-force attacks, unauthorized root access, and other common threats. In this post, I’ll walk you through recommended SSH configuration options, port changes, Fail2Ban, multi-factor authentication, and logging strategies.

The main SSH daemon configuration file on most Linux systems is located at:

/etc/ssh/sshd_config

You can fine-tune your SSH security using directives in this file.
Key directives include:

  • PermitRootLogin no Prevents direct root logins, forcing attackers to guess both a normal user and escalate privileges separately.
  • PasswordAuthentication no Disables password authentication in favour of key-based logins. Once you’re comfortable with SSH keys, consider turning off passwords entirely for enhanced security.
  • PubkeyAuthentication yes Ensures the server accepts key-based logins (enabled by default on most distributions).
  • Port 22 (default) You can change this to a non-standard port (e.g., 2222) to reduce noise from automated scans (more on this below).

Why Hardening Matters

  1. Brute-Force Attacks
    Attackers often run scripts that try common usernames and passwords on port 22. Hardening measures like key-based auth, fail2ban, and non-standard ports help mitigate this.

  2. Least Privilege
    Limiting who can connect, and how, ensures you minimize the blast radius if an account is compromised.

  3. Compliance and Audit
    Many industry regulations (e.g., HIPAA, PCI-DSS) require secure remote access and thorough logging of administrative actions.

Step-by-Step Guide to Hardening SSH

Changing the Default Port

By default, SSH listens on port 22. While security by obscurity isn’t a silver bullet, using a non-standard port can significantly reduce automated attacks. Consider using something like 2222 or 2202.

  1. Edit /etc/ssh/sshd_config:

    sudo nano /etc/ssh/sshd_config
    
  2. Set:

    Port 2222
    
  3. Restart SSH:

    sudo systemctl restart ssh
    
  4. Update Firewall Rules

    • For ufw

       sudo ufw allow 2222/tcp
       sudo ufw delete allow 22/tcp
      
    • For iptables:

       sudo iptables -A INPUT -p tcp --dport 2222 -j ACCEPT
       sudo iptables -A INPUT -p tcp --dport 22 -j DROP
      
  5. Connect on the New Port

    ssh -p 2222 user@server-ip
    

[!Tip]
Always keep a backup session open in case you misconfigure the new port and lock yourself out.

Pros and Cons of Non-Standard Ports

  • Pros:
    • Reduces noise from automated scanners.
    • Makes it slightly harder for opportunistic attackers.
  • Cons:
    • Not true “security,” just obscurity—committed attackers can still find your port.
    • Requires updating all your scripts/tools to specify the new port.

Disabling Root Login

Allowing direct root login is risky—once inside, an attacker has full control. A safer practice is to log in as a regular user and then escalate privileges using sudo or su as needed.

  1. Edit /etc/ssh/sshd_config

    sudo nano /etc/ssh/sshd_config
    
  2. Find (or add) the line

    PermitRootLogin no
    
  3. Restart SSH

    sudo systemctl restart ssh
    
  4. Verify
    Attempting ssh root@server-ip should fail. Instead, log in as a non-root user

Protecting Against Brute-Force Attacks with Fail2Ban

Fail2Ban scans log files (like /var/log/auth.log) for repeated failed login attempts and blocks offending IP addresses temporarily.

  1. Install Fail2Ban

    • Ubuntu/Debian

      sudo apt update -y
      sudo apt install fail2ban
      
    • CentOS/RHEL:

      sudo yum install fail2ban
      
  2. Configure Fail2Ban:

    • Copy the default config:

      sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
      
    • Edit /etc/fail2ban/jail.local:

      [sshd]
      enabled = true
      port    = 2222
      filter  = sshd
      logpath = /var/log/auth.log
      maxretry = 3
      bantime  = 600
      
      • port: Match the port from your sshd_config (e.g. 2222)
      • maxretry: Number of failed attempts before banning
      • bantime: Ban duration in seconds (600 = 10 minutes)
  3. Start Fail2Ban:

    sudo systemctl enable fail2ban
    sudo systemctl start fail2Ban
    
  4. Check Status:

    sudo fail2ban-client status sshd
    

    You’ll see how many IPs, if any, are currently banned.

    [!Tip] If you need to unban an IP

    sudo fail2ban-client set sshd unbanip <IP_ADDRESS> 
    

SSH Configuration Directives

Let’s look more closely at some sshd_config directives that go beyond basic settings:

  1. AllowUsers or AllowGroups

    • Restricts SSH access to specified users or groups:
      AllowUsers alice bob
      
  2. DenyUsers or DenyGroups

    • If you prefer to block specific accounts, similarly:
         DenyUsers root test
      
  3. ClientAliveInterval and ClientAliveCountMax

    • Helps manage idle sessions. If a client is inactive for a specified duration, the server ends the session. Example:
      ClientAliveInterval 300
      ClientAliveCountMax 2
      
      This disconnects idle sessions after approximately 10 minutes (300s × 2 = 600s).
  4. LoginGraceTime

    • Time allowed for someone to successfully log in before the server disconnects. Helps limit brute-force attempts.
          LoginGraceTime 60
      

Adding Multi-Factor Authentication (2FA)

Even with strong SSH keys, an extra authentication factor can enhance security further. Google Authenticator (or similar) provides a Time-based One-Time Password (TOTP) that changes every 30 seconds.

Installing Google Authenticator on the Server

  1. Install the Package:

    • Ubuntu/Debian

      sudo apt-get install libpam-google-authenticator
      
    • CentOS/RHEL

          sudo yum install google-autheticator
      
  2. Configure for Your User:

    google-authenticator
    
    • This generates a QR code and secret key. You’ll scan this with the Google Authenticator app on your phone.
    • Answer the prompts to set up constraints like rate limiting, forced new tokens, etc.

Update SSH PAM Settings

  1. Edit /etc/pam.d/sshd:

    # Add the following line at the top or appropriately
    auth required pam_google_authenticator.so
    
  2. Edit /etc/ssh/ssh_config:

    ChallengeResponseAuthentication yes
    

    If you rely on keys + TOTP:

    AuthenticationMethods publickey,keyboard-interactive
    

    or if you still allow passwords + TOTP:

    AuthenticationMethods password,keyboard-interactive
    
  3. Restart SSH:

    sudo systemctl restart ssh
    

Logging In with 2FA

Now, every time you attempt to SSH, after providing your key or password, you’ll also be prompted for a verification code from the authenticator app. This significantly raises the bar for attackers, since they need physical access to your TOTP device.

Logging and Auditing

Monitoring Log Files

  • Ubuntu/Debian: /var/log/auth.log

  • CentOS/RHEL: /var/log/secure

    Look for entries like:

    sshd[1234]: Failed password for invalid user test from 192.168.1.50 port 51234 ssh2
    

    Or

    Accepted publickey for alice from 203.0.113.10 port 55276 ssh2
    

    These logs show failed and successful login attempts.

Tools for Detecting Suspicious Activity

  • Logwatch: Generates daily email summaries of system logs.
  • Splunk/Elastic Stack: Centralized log ingestion and analysis.
  • Security Onion: A comprehensive platform for threat hunting and log correlation.

By regularly reviewing logs, you can spot unusual login attempts or repeated failures indicating potential brute-force attacks—even if Fail2Ban is already in place.

Conclusion

Securing SSH isn’t a single step—it’s a continuous process of configuration, monitoring, and updating. By:

  • Changing default ports (optional, but helpful),
  • Disabling root logins,
  • Enforcing key-based authentication,
  • Using Fail2Ban,
  • Implementing 2FA,
  • And regularly monitoring logs,

you significantly reduce your attack surface and ensure a more robust security posture.

In Part 5, I’ll move on to advanced SSH techniques such as port forwarding, jump hosts, and configuring ~/.ssh/config for streamlined workflows. Until then, review your current SSH settings and log files to make sure you’re on top of your server’s security!

Further Reading

Stay tuned for more on harnessing the full power of SSH, and drop any questions or tips in the comments below!

Have questions or want to share your own SSH hardening tips? Leave a comment below, and let’s keep the conversation going.

This article is part of a series.


comments powered by Disqus