DEV Community

Ricardo
Ricardo

Posted on • Originally published at rmauro.dev on

 

8 Actions for Hardening your Linux Server exposed on the internet

Exposing virtual machines to the internet it's not an easy task. Often managed using an SSH connection we must secure our machines as much as we can against hacker attacks.

Let's go through some often and ease configurations that will make it an attacker hard if trying to access your machine.

💬 In this issue

👉 Information used in our lab

User: root
Password: generated with a password generator
Description: Our Root user

User: secondary
Password: generated with a password generator
Description: Non Root user for daily basis access

Operating System: Ubuntu Server 20.04 - but it also working for different flavors of Linux.

Creating a non-root user

First thing first: Never use the root user for non-privilege tasks.

To accomplish that let's create a non-root user and use the sudo command to elevate our privileges only when necessary.

Logged as the root user let's create a non-root user called secondary. Execute the following command in our bash shell.

# create a regular user with name secondary
$ adduser secondary
Enter fullscreen mode Exit fullscreen mode

Creating the Secondary User

We should answer some questions (starting with the password) and we shall have the user.

8 Actions for Hardening your Linux Server exposed on the internet

Now we have a user with fewer privileges. Next step is to grant the use sudo command when necessary.

Add to Sudo Group

Run usermod command to include secondary into sudo group.

# includes the secondary into sudo group
$ usermod -aG sudo secondary
Enter fullscreen mode Exit fullscreen mode

Now we're able to use sudo in front of a command to run as administrative rights.

Enabling UFW Uncomplicated Firewall

UFW is the default firewall system (under the hood is the great IPTables) in Ubuntu Server.

With the use of ufw it's very simple to allow or block a port.

# allow port 22
$ sudo ufw allow 22
Enter fullscreen mode Exit fullscreen mode

Don't forget to use sudo we should be using the secondary user instead of the root

# Deny all incoming by default, allow outgoing, and finally enable the ufw service
$ sudo ufw default deny incoming
$ sudo ufw default allow outgoing
$ sudo ufw enable
Enter fullscreen mode Exit fullscreen mode

Deny all incoming by default, allow outgoing, and finally enable the ufw service

# display status of ufw
$ sudo ufw status
Enter fullscreen mode Exit fullscreen mode

8 Actions for Hardening your Linux Server exposed on the internet
Displaying Status of ufw Service

Great. Now we have ufw up and running.

Adding Unattended Upgrades

Unattended-Upgrade is a service that regularly checks and updates the OS packages.

The purpose of unattended-upgrades is to keep the computer current with the latest security (and other) updates automatically.

https://wiki.debian.org/UnattendedUpgrades

# Install unattended upgrades and enable it

$ sudo apt install unattended-upgrades

$ sudo systemctl status unattended-upgrades.service
Enter fullscreen mode Exit fullscreen mode

After installing just enable the service and we should be good.

8 Actions for Hardening your Linux Server exposed on the internet
Unattended upgrades Status

The default configuration will automatically retrieve new package updates for most of the packages included in the Ubuntu repositories.

Hardening the SSH Configuration

Most Linux servers are administered remotely using SSH using OpenSSH technology. Which is the default SSH server software used within Ubuntu.

This is one of the major vectors of attack by hackers on Linux exposed on the internet. Let's work on improving the configurations of our SSH server.

Using SSH keys instead of passwords

SSH keys are the recommended way to log into any Linux server environment remotely.

Back in our client machine (not on the server) let's create a pair of keys - private and public keys. This also works on Windows 10/11.

$ ssh-keygen
Enter fullscreen mode Exit fullscreen mode

You can specify a different location to save the keys if you like.

8 Actions for Hardening your Linux Server exposed on the internet
Generating the Public and Private Keys

The next step is to copy the SSH key to the Ubuntu server.

$ cat /home/{username}/.ssh/id_rsa.pub
Enter fullscreen mode Exit fullscreen mode

Copy the content output to the transfer area.

Back into our server

# create .ssh if not created
$ sudo mkdir -p ~/.ssh

# copy the public key to authorized_keys file
$ sudo echo public_key_string >> ~/.ssh/authorized_keys

# remove all permissions on .ssh folder
$ sudo chmod -R go= ~/.ssh

# adding read permission to our user - our scenario is secondary - on .ssh folder
$ chown -R secondary:secondary ~/.ssh
Enter fullscreen mode Exit fullscreen mode

Now we have the public key generated by our client machine in the server in the property location and with permissions in place.

This is it. Now we're able to log in using the recently created SSH Key. Let's try.

# ssh -i {key path}
$ ssh -i $HOME/.ssh/id_rsa secondary@{SERVER-IP}
Enter fullscreen mode Exit fullscreen mode

Using SSH Key to log into the Server

Changing default Port for SSH

Open the SSH configuration file sshd_config with a text editor.

$ sudo nano /etc/ssh/sshd_config
Enter fullscreen mode Exit fullscreen mode

Look for the entry Port 22 - it could be commented on. Replace it with the desired value - port between 1024 and 65536

. . .
Port 2222
. . .
Enter fullscreen mode Exit fullscreen mode

Port Configuration

Save and Restart the OpenSSH service.

$ sudo systemctl restart ssh

Enter fullscreen mode Exit fullscreen mode

Restarting the SSH service

Disable Password Authentication over SSH

Change property to PasswordAuthentication no

. . .
PasswordAuthentication no
. . .

Enter fullscreen mode Exit fullscreen mode

Password Authentication Configuration

Disable Root User Login

Change property to PermitRootLogin no

. . .
PermitRootLogin no
. . .
Enter fullscreen mode Exit fullscreen mode

Password Authentication Configuration

Tweaking some other sshd_config Configurations

Open the config file sshd_config one more time

$ sudo nano /etc/ssh/sshd_config

. . .
MaxAuthTries 3
. . .
Enter fullscreen mode Exit fullscreen mode
. . .
PermitEmptyPasswords no
. . .
Enter fullscreen mode Exit fullscreen mode

Test and Restart the SSH Service to reflect the new configuration

# test the configuration changes
$ sudo sshd -t

# restart the service and load the new configuration
$ sudo systemctl restart ssh
Enter fullscreen mode Exit fullscreen mode

Using ssh config file on SSH Client

Adding a config file in the .ssh folder on the ssh client allows us to define the key, host, user, and other configurations by default per connection.

In our Client's machine

Create the config file in ~/.ssh/config location

# THIS IS OUR CLIENT - NOT OUR UBUNTU SERVER
$ nano ~/.ssh/config
Enter fullscreen mode Exit fullscreen mode

Past the following content.

# connection name
Host ssh-server

   # host address (ip or hostname)
   Hostname 192.168.0.100

   # port of ssh server
   Port 2222

   # user
   User secondary

   # private key to use
   IdentityFile ~/.ssh/id_rsa_locaweb_secondary
Enter fullscreen mode Exit fullscreen mode

config file

Then we can connect using only the connection name

$ ssh ssh-server
Enter fullscreen mode Exit fullscreen mode

Final thoughts

Wow, finally we made it. That is enough!

Of course, we can keep going hardening it even more adding more protection - it never stops.

Share in the comments section what you would do to make it even better or different.

Oldest comments (8)

Collapse
 
ccoveille profile image
Christophe Colombier

Good but an rsa key is no longer recommended edt25519 is preferred

ssh-keygen -t ed25519

Also the recommended method to copy the key on server is ssh-copy-id command

Collapse
 
rmaurodev profile image
Ricardo

That is great. I’ll give a try.
Thanks for that

Collapse
 
rmaurodev profile image
Ricardo

I have just read that in GitHub article about generating ssh keys. Use ed25

Collapse
 
phlash profile image
Phil Ashby

Thanks for this excellent start in hardening an Internet-exposed system!

In case folks don't know, the Center for Internet Security provide well-known, trusted benchmark guides for hardening many systems connected to the Internet, including Linux, eg:
cisecurity.org/benchmark/distribut...

(I'm not affiliated with CIS, these benchmarks are widely used, including by myself across multiple of my previous roles in information security)

There are also automated tools to check systems against CIS benchmarks (and NIST ones!), particularly for Unix-like systems. I've previously used Lynis, others are available, eg:

Collapse
 
rmaurodev profile image
Ricardo

That is very nice. Thanks for sharing

Collapse
 
ej_agas profile image
EJ Agas

Hi, when you changed the default SSH port from 22 to 2222, you need to allow also inbound connections from port 2222 in UFW right?

Collapse
 
rmaurodev profile image
Ricardo

You’re correct.

Collapse
 
behrjozef profile image
Jozef Behr

Really helpful article gives lots of Knowledge .

Here is a post you might want to check out:

Regex for lazy developers

regex for lazy devs

Sorry for the callout 😆