Quick Initial Linux Server Security and Hardening

Computer security - Initial Server Hardening

Once you get an unmanaged server from MGCSpace.com, the first step you should perform is securing the server. In case of managed services, MGCSpace team will take of your server’s security aspect. But if you have a server where you want to manage it yourself then you should perform crucial security measures in order to avoid your server being compromised and exploited by bad actors. Securing your server not only keeps you and your server safe but also deters bad actors and send them to look for other less secure servers.

Although there are plethora of aspects of Linux server security but we suggest you to perform some crucial security measures initially which would serve as base for your Linux server security. You may later enhance and fine tune them as per your use case and requirements.

Why server security is required ?

In short, we need it to keep your server secure from unwanted access and exploitation by malicious actors. If you are not vigilant then many kind of compromises are possible such as using the web server to spread malware or just using it to steal your traffic, creating a spam-sending relay, a web or TCP proxy server, or other malicious activities are possible. When your server is not properly secured, you are not only risking your data but may also helping inadvertently in compromising other servers online.

Basic security measures

So what kind of basic measures you need ? As already mentioned, there are plenty of things you can do to secure your server but we will focus on some initial and crucial things.

Add sudo or Limited user account

In most of the Linux installation, by-default you will have root access. Root user allow to have full and unrestricted privileges. This may prove fatal as any of the mistake or command can render your system unusable if not used wisely. Hence it is recommended to use limited privilege user which can run Administrative commands via elevated privileges using sudo. Another advantage of using sudo user is that you can also log all elevated command perform by such user.

For RHEL/Fedora/Alma and similar linux distribution

  • To add a sudo user for RHEL based distribution, first you need to create a new user on your system.
    useradd -m your_user_name && passwd your_user_name 
    In above replace your_user_name with desired name, you password and you have will have new user added to system.
  • One your new user is added, we need to add it to wheel group which will give it sudo privileges.
    usermod -aG wheel your_user_name

For Debian/Ubuntu and similar linux distribution

  • To add sudo user in Debian or Ubuntu based distribution, again first we need to create a new user (you may also use existing user and skip to next step).
    adduser your_user_name 
    In above replace your_user_name with desired name, you will be asked for couple of details including password and you have will have new user added to the system.
  • One your new user is added, we need to add to sudo group which will give it sudo privileges.
    usermod -aG wheel your_user_name

Note:
Sometimes you may not have sudo installed by default, you can add it easily using dnf install sudo -y on RHEL based systems and apt-get install sudo -y on debian based systems.

Now we have new limited user with sudo privileges added, you should open another terminal or session and login using new user and try to run some Administrative commands without sudo, it should give you permission error. Now if you want to run Administrative commands, you can run following way :

sudo dnf update

OR

sudo apt-get update

It will ask you for user’s password and should be able to run the Administrative commands. If there is no error and you are able to use sudo command with newly created sudo user, you may now logout the previous root user session and now on continue with sudo user session we just used to login a moment ago.

Updating the system

Since you have just created a new limited user with sudo privileges, we will move forward now with updating the system. Keeping your system updated is the most basic yet very important security measure. By updating you are getting most secure and patched version of software as mostly security issues and vulnerability in software are patched quickly and are made available via updates. Although there are various system but most common system can be updated using following methods:

CentOS stream 8 / CentOS 8, AlmaLinux, Rocky Linux, Fedora and other latest RHEL distributions:

sudo dnf upgrade

Debian / Ubuntu based distributions:

sudo apt update && sudo apt upgrade

Hardening SSH access

SSH, (or Secure Shell Protocol) is a remote administration protocol that is used to to manage and access remote resources and service, control, and modify servers on network via secure layer over unsecured network. In short, the SSH is gateway over internet to your server and keeping it secure is essential part. SSH security can be hardened in multiple ways depending upon the use case. Here we will implement basic security measures so that access to your server is more secures through SSH.

Configure key-based SSH authentication

By default, you can login to ssh using password as well ssh-keys, however, password based login is considered relatively unsafe, and hence it is suggested to use key-based authentication. It is enabled by default in SSH.

Before making any changes ssh configuration, we have to generate ssh-keys which works in public and private key pair ie. we generate a private key and then public key based on that key. As as the name suggest, private key should be kept with you and never shared with anyone while the public key need to be copied on remote system which want login.

Generating SSH public-private key pair is easy, first on the system from where you will login to remote system using SSH, you need to run following command to generate the key pair:

ssh-keygen -b 4096 -t rsa

It will ask you for locations to save newly generated files, just press enter and if asks for passphrase then again press enter to choose no passphrase. If you provide any password there, then it will add extra layer of security, along with key will also ask for that password whenever you want to login.

Once done, it will create two files

  • /home/your_user_name/.ssh/id_rsa Your private key, never share with anyone.
  • /home/your_user_name/.ssh/id_rsa.pub Your public key, you need to copy this to remote system where you want to connect.

Note:
Above command will create ssh key pair for the as user you are logged in local system. It has nothing to do with remote system user. For example, if you run above command as root user then keys will be generated in files /root/.ssh/id_rsa.pub and /root/.ssh/id_rsa

Now upload your public key to remote system, ideally we are required copy content of /home/your_user_name/.ssh/id_rsa.pub to remote user’s ~/.ssh/authorized_keys file. Lets have an example, for user “tech1”, it would go in file /home/tech1/.ssh/authorized_keys. You can also use built-in utility ssh-copy-id which can do that part for you easily.

To copy public key to remote server over ssh use following command, it will require that you have access to remote user using password :

ssh-copy-id -i ~/.ssh/id_rsa.pub [email protected]

Once you run above command successfully from your local system where you generated the keys, it will ask for ssh password and then will add entry to remote server’s (here its with ip 1.2.3.4) authorized_keys file for remote user tech1.

Now run following command to test to see if you can login to remote user tech1 on server 1.2.3.4 without providing password.

ssh -p 22 [email protected]

If everything is fine, running above command should allow you to login to remote system ssh without password. In above, -p 22 is default ssh port, if ssh is running on non-standard port for remote server, then replace 22 with desired port. Further, tech1 is user and we are connecting to server with ip 1.2.3.4.

Disable root user login via SSH

As SSH is gateway to your server, it is always best practice to disable direct root access, we have already created sudo user earlier and tested that its able to login. Now we can disable access root via SSH, this way we are making sure that no one can log in using root user even if they are able to guess or obtain root login credentials.

Open sshd configuration file in editor of your choice, we prefer nano.

sudo nano /etc/ssh/sshd_config

In that file look for directive “PermitRootLogin” and set it to no. Although we suggest to disable root login completely, however, in some cases you may want to disable password login but allow key-based authentication which is considered sufficiently secure.

To disable root ssh login completely, make sure “PermitRootLogin” is set to no in ssh configuration file.

PermitRootLogin no

To disable password login but allow key-based access:

PermitRootLogin prohibit-password

Change SSH port

By default, SSH uses port 22, it means there are always bad actors looking for port 22 to break the password using repeat dictionary attack known as brute force attack. We have already made it harder by disabling root access by SSH as now attacker also need to guess the username since root is disabled. Further we can change ssh port to something else so that attacker will have hard time connecting to SSH on this server. We can change to something like “12200”

Open ssh configuration file in editor like nano with command sudo nano /etc/ssh/sshd_config, find Port and change to anything you like :

Port 12200

Note:
It is suggested to use on of the privileged port ie <1024, however you can use any port your prefer as long its not used by any other service on your server.

Also, no matter what port you use, it is easy to find running port through simple port scanning but by changing ports, you will definitely turn away bots those are looking SSH running over port 22.

Disable password authentication for all users

If you have configured key-based authentication successfully, it is recommended to disable password based authentication for all users. To do that, open ssh configuration file in editor like nano with command sudo nano /etc/ssh/sshd_config, and set “PasswordAuthentication” to “no”. Make sure its not commented out.

PasswordAuthentication no

Note:
Although its recommended to disable password authentication completely but you may want to enable password authentication for non-root users so that you can access your server using password where your private key is not available eg. accessing it form some one else’s computer. Since we have already disabled ssh root login, then you may leave PasswordAuthentication yes and only non-root users can access server via SSH.

Once you are done with modifying your /etc/ssh/sshd_config file, to apply the changes, we need to reload the sshd daemon. We also need to make sure there is no errors in config files after we made the changes.

sshd -t 

If there is no error, you can now restart sshd daemon and changes we made so far will be applied. Remember, if there is any mistake, you may get locked out of your system after applying sshd config changes.

sudo systemctl restart sshd

Now after this, you can login to SSH on the server using new port, you can verify using :

ssh -p 12200 [email protected]

In above, -p 12200 tells to use port 12200 which we set earlier, it should login without asking password. tech1 is the user we are using as example, 1.2.3.4 is IP of remote server.

Set up Firewall

Although you have taken basic measures to secure your server but you still need firewall to enhance the security further. A firewall can be piece of software or hardware which control access of services to and from your server from outside. A properly configured firewall helps to reduce security breaches in a server. For example, if you are running a public webserver and a private sql server then using firewall we can make sure only webserver is accessible from outside your network or server.

Firewalls can be comprehensive and depends upon how you want to use them, however we will focus on basic security which you may use as base to start with. Linux primarily uses iptables or more recently nftables for network packet filtering however, instead of manipulating them directly, we will explore ufw (Uncomplicated Firewall) for Debian / Ubuntu / Arch based Linux Distributions and FirewallD for RedHat based system such Fedora, CentOS, AlmaLinux etc. Both UFW and FirewallD act as frontend for lower level iptables / nftables packet filtering system.

Configuring UFW (Uncomplicated Firewall)

UFW is fairly easy and recommended way to configure firewall in Debian and Ubuntu based Linux distributions. UFW comes by default in Ubuntu, however, you will need to install it on Debian and other system. You can verify using following :

sudo ufw status

If you get error like ufw: command not found, you have to install it which is few seconds tasks.

Install in Debian / Ubuntu

sudo apt-get install ufw

Install on Arch Linux

sudo pacman -S ufw

Once installed, running command sudo ufw status should give output like following.

sudo ufw status
Status: inactive

Now we know that ufw firewall is there and it is inactive, time to configure it. First we will set firewall to deny all incoming connections while allowing all outgoing connections. Our goal is to only allow access services those are necessary, we can also fine tune rules further to allow access to certain services from specified hosts etc.

Setting up the default policies of deny all incoming connections to server while allowing all outgoing:

sudo ufw default deny incoming
sudo ufw default allow outgoing

By default, ufw comes with various pre-defined list of applications, for example, allowing http will open port 80, while allowing https will open port 443 on server. You can see list of all predefined application profiles using:

sudo ufw app list 

Now lets allow http (port 80), https (port 443) and FTP (port 21) traffic.

sudo ufw allow http
sudo ufw allow https
sudo ufw allow ftp

We can also enable incoming ssh traffic similar way if your sshd is listening on standard port 22, however, since in this tutorial we changed ssh port (port 12200) earlier, to add custom ports, you can use following method:

sudo ufw allow 12200/tcp

Allow specific port ranges:

Sometimes for services like passive ftp connection, you have to open port range, for example we want to use 34000 to 35000 for passive ftp connection.

sudo ufw allow 34000:35000/tcp

Allow access from specific IP address:

sudo ufw allow from 2.3.4.5

Deny access from specific IP address:

sudo ufw deny from 3.4.5.6

Although we have configured the ufw firewall, it is still not working, we need to enable it.

sudo ufw enable

Now if we check the status of firewall using sudo ufw status verbose, we will get:

Sample output:

Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip

To                         Action      From
--                         ------      ----
22/tcp                     ALLOW IN    Anywhere
80/tcp                     ALLOW IN    Anywhere
443/tcp                    ALLOW IN    Anywhere
21/tcp                     ALLOW IN    Anywhere
20000:21000/tcp            ALLOW IN    Anywhere
Anywhere                   DENY IN     3.4.5.6
Anywhere                   ALLOW IN    2.3.4.5
22/tcp (v6)                ALLOW IN    Anywhere (v6)
80/tcp (v6)                ALLOW IN    Anywhere (v6)
443/tcp (v6)               ALLOW IN    Anywhere (v6)
21/tcp (v6)                ALLOW IN    Anywhere (v6)
34000:35000/tcp (v6)       ALLOW IN    Anywhere (v6)

Configuring Firewalld

Another most commonly used firewall utility or frontend for iptables / nftables is firewalld. Firewalld provides a dynamically managed firewall with support for network/firewall zones that define the trust level of network connections or interfaces. It has support for IPv4, IPv6 firewall settings, ethernet bridges and IP sets. There is a separation of runtime and permanent configuration options. It also provides an interface for services or applications to add firewall rules directly.

If above sounds little complicated, then don’t worry about it, since our objective is to only allow required traffic, we will explore most basic part. You may go for extensive version of firewalld configuration later if you need.

Firewalld is default firewall application for RHEL 7 and newer CentOS 7 and newer, Fedora 18 and newer, SUSE 15 and newer, OpenSUSE 15 and newer. Though you can also install it on most of other distributions.

If firewalld is not installed on your system, then you can install it using dnf.

sudo dnf install firewalld -y

Once installed, you need to enable the firewalld using systemctl and once enabled, it will automatically load not next server boot. Enable and start firewalld:

sudo systemctl enable firewalld
sudo systemctl start firewalld

Note:
You have to be careful before starting the firewall, incorrect configuration may lock you out from your server.

Now, once you have firewall up and running, its time to configure it. its uses firewall-cmd command to carry out manipulation tasks. Firewalld uses zones which can be seen as group of firewall rules, for example, “home” zone can be used for when you are connecting to home network which is more trusted while can use “public” zone for a web-server where it runs public facing services. Firewalld comes with certain built in zones and you can select one which you find most suitable for your use-case.

sudo firewall-cmd --get-zones

Sample Output : List of the available zones in firewalld.

block dmz drop external home internal nm-shared public trusted work

Firewalld comes with “public” zone as default zone, you can verify it using

sudo firewall-cmd --get-default-zone

Sample output :

public

In order to keep it simple, now we will go ahead and configure our firewall for “public” zone which is also our default zone. Any changes made to this will be automatically enforced in our firewall.

Allowing services in firewalld

Firewalld support predefined services like http, https, ftp, samba etc. (see all available services sudo firewall-cmd --get--services). For example, we want to enable access to http (port 80), https (port 443) on our server under public zone.

sudo firewall-cmd --permanent --zone=public --add-service=http --add-service=https

On successful addition, it should greet you with messages success. In above, we are using --permanent so that changes we made to firewall are consistent on next firewall reload or server boot.

In order to apply changes, we have reload the firewall.

sudo firewall-cmd --reload

Now you can verify changes by using following command :

sudo firewall-cmd --zone=public --list-all 

Sample Output: It will show you state of “public” default services, along with the services we just enabled ie. https and http.

public (active)
target: default
icmp-block-inversion: no
interfaces: eth0
sources:
services: cockpit dhcpv6-client http https ssh
ports:
protocols:
forward: no
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:

Removing services from firewalld

The way you have added services to firewall, you can also remove services easily. Just use --remove-service=<services_name> and you are done. For example, removing http service.

sudo firewall-cmd --permanent --zone=public --remove-service=http

Adding or allowing ports in firewalld

The way you added services to firewalld, you can also allow custom ports. For example, we had configured port 12200 for ssh earlier in this tutorial, hence default ssh services will not work here. Hence to add port 12200 permanently in “public” zone:

sudo firewall-cmd --permanent --zone=public --add-port=12200/tcp

If there is no error, then it should greet you with success message. In above, we we need to specify port protocol after port number, generally its either tcp or udp.

Remove ports in firewalld

In same fashion, you can easily remove ports from firewalld. Lets say, we want to remove the port which just added above (12200) from “public” zone.

sudo firewall-cmd --permanent --zone=public --remove-port=12200/tcp 

Add or allow port range in firewalld

Sometimes you need to allow port range, eg. you need to allow port 34000-35000 for your passive ftp connections. Other than allowing ftp service, you can run following command to allow above mentioned port range in firewalld.

sudo firewall-cmd --permanent --zone=public --add-port=34000-35000

Note:
You can omit the --zone=public part, and it will then add those rules to current default zone, in our case it would be “public”.

There are certainly a lot more features in firewalld however, by now we have achieved basic firewall goal. Make sure you run sudo firewall-cmd --reload to apply the changes you made to firewalld so far.

Basic Intrusion detection and blocking using fail2ban

For securing Linux server, you can have firewall, disable unwanted services and also take multiple hardening steps but still there will be some of the public facing services like ssh, ftp etc. And there will always be bots and bad actors trying to gain access. Even though they will have all fail attempts but still hundreds or thousands of bots can eat up significant resources serving those failed requests.

Here Fail2Ban comes in play which is a log-parsing application that bans IP addresses from logging into your server after too many failed login attempts. For example, you can configure Fail2ban to block an IP from access to server if it makes 5 failed consecutive attempts in 30 mins. This way, legit users can still log into the server while bad-actors trying to brute-force will be blocked.

For the sake of clarity, we have covered installation and configuration for various distribution in separate tutorials. Once you have have followed tutorial as per your Linux distribution you are using, mostly under 5 minutes you will be able to configure basic intrusion detection and blocking system ready for most common services like ssh, ftp, http authentication etc. As long as a service is using password based authentication with log files, you can configure fail2ban to monitor them.

Here is the list of Fail2ban installation tutorial for :

  • Configure Fail2ban on RedHat / CentOS / AlmaLinux / RockyLinux 8.x with firewalld integration
  • Configure Fail2ban on Ubuntu / Debian / Arch Linux for brute force protection
  • How to Install and Configure Fail2ban on CentOS 6 / 7.x

Final thought

The methods we used above should be considered as overview of security measures you can implement with your Linux servers. Implementations of above security practices should be considered as your Linux server’s security starting point and then as per your use-case or need you can enhance or tweak it.

There could be many more ways to enhance security like “Enabling Automatic Updates” which will make sure that your system is always using latest packages and updates keeping it safe from most common software vulnerabilities with no or minimal intervention.

You may also use firewall packages like CSF which is a Stateful Packet Inspection (SPI) firewall, Login/Intrusion Detection and Security application. It alone may replace functionalities of firewall like ufw, firewalld and intrusion detection like fail2ban.

Remember, server security is an ongoing process and you have to keep it updated and tweaked as per your modification or configuration of your Linux server environment.

Comments

No comments yet. Why don’t you start the discussion?

Leave a Reply

Your email address will not be published. Required fields are marked *