How to stop brute force ssh attempts in CentOS/RHEL using sshd_config, TCP Wrappers and iptables

You may have seen a large number of login trials in your Linux box, similar to below:

Jan 25 01:37:27 [_HOST_] sshd[21819]: Invalid user [USER1] from xxx.xxx.xxx.xxx port 57770
Jan 25 01:37:27 [_HOST_] sshd[21819]: input_userauth_request: invalid user [USER1] [preauth]
Jan 25 01:37:27 [_HOST_] sshd[21819]: Received disconnect from xxx.xxx.xxx.xxx port 57770:11: Bye Bye [preauth]
Jan 25 01:37:27 [_HOST_] sshd[21819]: Disconnected from xxx.xxx.xxx.xxx port 57770 [preauth]
Jan 25 01:37:33 [_HOST_] sshd[21824]: Invalid user [USER2] from x.x.x.x port 46514
Jan 25 01:37:33 [_HOST_] sshd[21824]: input_userauth_request: invalid user [USER2] [preauth]
Jan 25 01:37:33 [_HOST_] sshd[21824]: Received disconnect from x.x.x.x port 46514:11: Bye Bye [preauth]
Jan 25 01:37:33 [_HOST_] sshd[21824]: Disconnected from x.x.x.x port 46514 [preauth]
Jan 25 01:37:35 [_HOST_] sshd[21822]: Invalid user [USER3] from xx.xx.xx.xx port 56374
Jan 25 01:37:35 [_HOST_] sshd[21822]: input_userauth_request: invalid user [USER3] [preauth]
Jan 25 01:37:35 [_HOST_] sshd[21822]: Connection closed by xx.xx.xx.xx port 56374 [preauth]
Jan 25 01:38:02 [_HOST_] sshd[21829]: Invalid user [USER4] from xx.xx.xx.xx port 58642
Jan 25 01:38:02 [_HOST_] sshd[21829]: input_userauth_request: invalid user [USER4] [preauth]

The above attempts of fraudulent login are quite annoying and each connection to your SSH daemon may also take up valuable instance resources. There are many ways to mitigate ssh brute-force attacks:

  • Use 3rd party tool fail2ban: Fail2ban is an application that blacklists IP addresses involved in brute-force login attempts (that is, too many failed attempts to an instance). Fail2ban inspects SSH accesses by default and can be configured for other protocols.
  • Instance level: harden ssh with ssh configuration options,keep the instance ssh up-to-date; harden Linux instance system via TCP wrappers and iptables. This method will be elaborated in this post.

Harden ssh on the instance

We can harden ssh on the instance by using ‘public-key logins only(PubkeyAuthentication yes)’, ‘disabling password logins(PasswordAuthentication no)’ and ‘disabling root logins(PermitRootLogin no)’ to prevents root privileges for remote logins in. We can also change the ssh port to something other than 22 and change the MaxStartups value to limit the simultaneous login attempts. Here is an example setup, you can modify the ones with uncomment mark.


# cat /etc/ssh/sshd_config |grep -v ^#
PasswordAuthentication no
PubkeyAuthentication yes
PermitRootLogin No
ChallengeResponseAuthentication no
GSSAPIAuthentication yes
GSSAPICleanupCredentials no
UsePAM yes
UseDNS No
HostbasedAuthentication no
StrictModes yes
MaxStartups 5:30:25
AllowTcpForwarding no
X11Forwarding no
PermitEmptyPasswords no
#Port 1101        ### Port number 1101 is an example. You need to access to this server to the port 1101 if you do a ssh connection instead of default 22.
#MaxSessions 10
#LoginGraceTime 2m
#ClientAliveInterval 0
#ClientAliveCountMax 3
#ListenAddress x.x.x.x

You can also restrict remote access to configure access to a group or certain users. Add lines to /etc/ssh/sshd_config to permit or deny ssh access:

  • Add a line for AllowUsers or AllowGroups to limit ssh to specific users or groups, respectively.
  • Add a line for DenyUsers or DenyGroups to deny specific users or groups, respectively, from using ssh.

Use TCP Wrappers

Another common adminstrative practice is to configure TCP wrappers to define related rules. tcp_wrappers is installed by default in most of the Linux distributions. To check if it is installed on a CentOS 7 machine, use:

# rpm -qa |grep tcp_wrappers
tcp_wrappers-libs-7.6-77.el7.x86_64
tcp_wrappers-7.6-77.el7.x86_64

If it is not installed, you can install it:

# yum install tcp_wrappers* -y

You can configure tcpwrappers via /etc/hosts.allow and /etc/hosts.deny to signal intrusion attempts from known malicious sources. To deny all ssh access by add below line to /etc/hosts.deny:

# vi /etc/hosts.deny
sshd: ALL

To allow certain trusted hosts to ssh, add the following lines to /etc/hosts.allow, you can use both IP address and FQDN:

# vi /etc/hosts.allow
sshd: xxx.xxx.xxx.xxx, trusteddomain.com

Use Netfilter and IPtables

In CentOS/RHEL, a built-in Kernel Subsystem called Netfilter can act as a packet filtering firewall. The stored filtering rules in kernel tables determine if Netfilter allows packets to be received, dropped, or forwarded. Netfilter applies a chain of rules to every packet. The iptables command is the primary interface for configuring rule chains. You can restrict SSH connection to only allow authorized IP addresses.

To allow SSH connections only from xxx.xxx.xxx.xxx run the following command:

# iptables -A INPUT -p tcp -m state --state NEW --source xxx.xxx.xxx.xxx --dport 22 -j ACCEPT

To disable SSH connection from all other hosts run the following command:

# iptables -A INPUT -p tcp --dport 22 -j DROP

Save your new rules using following command:

# service iptables save