In a previous article I explained how to create and manage Linux user accounts. For better security, root access and password authentication should be disabled, and Fail2Ban should be installed and configured. These steps will significantly reduce the odds of a successful brute-force SSH attack on your server.
Disable root access
Stopping anyone from being able to SSH into a Linux box as the
root user is all that is needed to prevent the most common form of brute-force attack.
Before you disable root access, be sure to create for yourself a limited user account with root-level privileges. Follow these instructions.
SSH into the box using your limited user account. Elevate to root and edit the SSH configuration file in your favourite text editor.
sudo su - vi /etc/ssh/sshd_config
PermitRootLogin setting and change its value to
Save your changes.
Restart the SSH service.
systemctl restart sshd.service
Logout of your limited user account and try logging in again as
root. It should fail with an "Access Denied" message.
Disable password authentication
Now all users must login to the server using their individual limited user accounts. Brute-force attacks are still possible, so for the ultimate security users should be required to submit passphrase-protected private key files, in place of traditional passwords, when they SSH into the box.
Implement the following steps for your own user account, then repeat these steps for every other user. Be sure to generate a unique public/private cryptographic key pair for each user.
Public and private key pairs can be generated on the server, but in these instructions I'll explain how to generate them on a desktop computer using PuTTYgen. This is a free Windows application, but similar tools are available for other operating systems.
Download PuTTYgen from here: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
Open PuTTYgen. Leave the defaults in place and click Generate. Follow the instructions about wriggling your mouse around to create some randomness. PuTTYgen will generate a strong public key, which you can see at the top of the dialog box.
In the "Key comment" field add a comment that describes the key. I like to use this to write the user's full name and the current date, e.g. "Kieran Potts 2017-04-01". It tells me who the key was for and when it was made. This comment will be embedded within both the public and private keys, and it will be shown to the user when he tries to login to the server.
Copy the public key from the top of the PuTTYgen dialog box into a text file, and save it to your desktop. You will need it later. Do not use the "Save public key" option, which exports the public key string in the wrong format. Instead, copy the text at the top of the PuTTYgen window, and be sure to copy the full text. The public key will look something like this:
ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAQEAklmPYUPtR8nn+pDj/LoSXG....094vw== Kieran Potts 2017-04-01
Now to generate the accompanying private key. Whereas the public key will be stored on the server, the private key will be issued to the user, who will use it to SSH into the box. For ultimate security, private keys should be protected with a strong passphrase.
Enter a passphrase in the "Key passphrase" text field, and enter it a second time to confirm. The passphrase can be any combination of letters and numbers. Make it a good one.
Click on the "Save private key" button. This will save the private key, which is passphrase protected, to your desktop as a
.ppk file. I tend to use the Linux username as the filename, e.g.
Login to your limited user account using PuTTY or KiTTY or an SSH client of your choice. Elevate yourself to root.
sudo su -
Navigate to the relevant user's home directory. Use the following command, replacing
<username> with the correct username.
The combination of commands shown below will create directory called
.ssh in the user's home directory, add a blank file called
authorized_keys to it, and set appropriate access permissions and ownership.
mkdir .ssh touch .ssh/authorized_keys chmod 700 .ssh chmod 600 .ssh/authorized_keys chown -R <username>:<username> .ssh
Edit the newly-created
authorized_keys file with a text editor such as vi.
Copy the contents of the public key, which you saved to your desktop earlier, into the
authorized_keys file. Again, be sure to copy-and-paste the full text of the public key. If you miss a bit, the key will be corrupted. (Multiple keys may be entered into this file. Start each key on a new line.)
authorized_keys file and
logout of the box. Now try logging in again. This time, login to the user account that you are hardening, which may or may not be your own account. And this time, use the private key to connect. To do that, you need to tell your SSH client about the private key file. In PuTTY or KiTTY, go to Connection > SSH > Auth, and type the local path to the "private key for authentication".
SSH into the box with the username for the account for which you are applying the cryptographic key pair. You should see a message similar to "Authenticating with public key 'Kieran Potts 2017-04-01'", and then you will be prompted for the "Passphrase for key 'Kieran Potts 2017-04-01'" rather than being asked for the user's normal password. Type the passphrase that you used earlier to encrypt the private key. You should now be logged in. If instead you see the message "Server refused our key", something is wrong will the configuration and you should repeat the steps above to resolve the issue. For now, you can still login with the user's normal password.
The public/private key pair and associated passphrase act as a proxy for the user's true password. However, users who
sudo into root privileges will still be prompted for their normal password to confirm the action. So, for each user account there will be a password an a passphrase-protected private key file. It is important to understand that the user's password and key passphrase are different things. All of this information needs to be stored securely locally. Ideally, private key files and their corresponding passphrases should be kept separate. Public keys need only be stored on the server – there's no need to keep local copies of these.
Repeat the steps above for every user account. Be sure to generate a new public/private key pair for each user. When everyone has been issued with their private keys and passphrases, and you have tested that everyone can SSH into the box successfully with these credentials, you can safely disable password authentication. This will prevent anyone from being able to SSH into the box using their normal password. After this step, all users will need to use their private key and passphrase for SSH access. (They will use their password only to confirm root-level commands.)
With root privileges, open the SSH configuration file in vi.
PasswordAuthentication setting and change its value to
no. Check that the line is un-commented by removing the
# in front of it, if there is one.
Restart the SSH service.
systemctl restart sshd.service
Logout of the box, and try logging in again to a limited user account using the user's standard password (do not submit the private key). It should fail with the message "No supported authentication methods available".
At this juncture, it is worth me mentioning Pageant.
Pageant is a handy Windows tool that makes it simpler to authenticate with servers when you've got lots of SSH keys to manage. Pageant runs in the background and holds one or more private keys in memory. Several popular SSH clients including PuTTY, FileZilla and WinSCP will automatically read private keys from Pageant when it is running. The effect is that you don't need to remember to provide the relevant key file and passphrase every time that you connect to a server.
You can download Pageant from here: http://www.chiark.greenend.org.uk/~sgtatham/putty/download.html
On startup, Pageant is immediately minimized to the Windows system tray. Right click on its icon and select Add Key. Choose a
.ppk file. If the private key is passphrase protected, you will be prompted to enter the passphrase.
That's all there is to it. You can add as many private keys as you wish, one for each server that you manage. Try connecting to your server using PuTTY, but don't give PuTTY the private key file. You will be prompted to provide your username, then PuTTYgen will automatically supply the passphrase for the private key. You will be logged in immediately.
Fail2Ban provides further protection against brute-force SSH attacks. It will automatically blacklist clients by their IP address, preventing them from logging in to a server after too many failed attempts. It works by monitoring system logs, looking for symptoms of automated attacks based on rules that you configure. It will automatically add new rules to iptables, blocking the IP addresses of suspected attackers, either for a set amount of time or permanently. Fail2Ban can also be configured to send email alerts when an attack is suspected.
Fail2Ban can be used to monitor other protocols including HTTP and SMTP, but it is primarily focused on providing protection against SSH attacks.
Fail2Ban is not available from the default CentOS package repositories, but it is available from EPEL (Extra Packages for Enterprise Linux), a repository dedicated to distributing a high quality set of optional packages for Linux Enterprise distributions, including CentOS and Red Hat Enterprise Linux (RHEL).
sudo yum install epel-release
With the EPEL repository added to the Red Hat Package Manager (RPM), you can now install Fail2Ban using the
sudo yum install fail2ban
For email support you will also need to install Sendmail, if it is not installed already.
sudo yum install sendmail
Enable both Fail2Ban and Sendmail as services, and start them up.
sudo systemctl enable fail2ban sudo systemctl enable sendmail sudo systemctl start fail2ban sudo systemctl start sendmail
Fail2Ban uses a cascading configuration system:
.conf files contain the default settings, while
.local files extend and override the defaults. So, any configuration changes should generally be done in
Fail2Ban's configuration files are stored in the
/etc/fail2ban directory. In there you will find a file called
fail2ban.conf. This file configures Fail2Ban logging, defines the socket used to communicate with the Fail2Ban daemon, and sets the location of the PID file that identifies the process ID of the program. The default settings are pretty good and probably won't need changing. If you do want to adjust these settings, do so in a
cd /etc/fail2ban sudo cp fail2ban.conf fail2ban.local sudo vi fail2ban.local
There's another configuration file called
jail.conf. This sets the criteria by which suspected brute-force attacks are identified, and it determines the jail terms of banned clients. You will want to make changes to the default jail settings. Again, first create a
.local clone of the master
.conf file, and make your changes there.
cd /etc/fail2ban sudo cp jail.conf jail.local sudo vi jail.local
backend property to "systemd".
backend = systemd
The main settings to pay attention to are
maxretry setting determines how many invalid login attempts can be made from any one IP address before that IP address is blacklisted. The
findtime setting determines the number of seconds in which
maxtries are allowed. The
bantime setting determines the length of time in seconds for which an IP address remains blacklisted; a negative number makes the ban permanent. Adjust these numbers as you see fit. These are the settings that I tend to use:
bantime = 86400 # 1 day findtime = 3600 # 1 hour maxretry = 3
If you want to be alerted by email whenever a client is banned, use the following settings:
destemail: The email address where you would like to receive the emails.
sender: The "from" email address that Fail2Ban will use when it sends emails. It does not need to be a real, working email address.
destemail = [email protected] sender = [email protected]
action setting defines what actions occur when a client is banned.
%(action_)s: Bans the client.
%(action_mw)s: Bans the client and sends an email with a WHOIS report.
%(action_mwl)s: Bans the client and sends an email with a WHOIS report plus all relevant lines from the log file.
action = %(action_mw)s
Close and save the
jail.local file and restart the Fail2Ban service for the changes to take effect.
sudo systemctl start fail2ban