Securing Your System Print

  • 89

Securing your Linux system should be one of the first tasks carried out upon initial log into the system. Misconfiguration during this stage could potentially mean locking yourself out of your server so it is usually a good idea to have a second session open at the same time to ensure you are still logged in in the second session to revert any changes if you find yourself logged out of the first session.

We also provide a VNC console for dedicated servers or KVM over IP for dedicated servers for remote access should you find yourself locked out.

To secure you system, simply follow the following steps:

Step 1 — Creating a New User

Once you are logged in as root, you’ll be able to add a new user account. It is best pratice to use a privileged account to carry out tasks rather than using root directly. Using the useradd and passwd command, create a new user and change their password.

useradd -m <new-user>
passwd <new-user>

Step 2 — Granting Administrative Privileges

Now we have a new user account with regular account privileges, we can set up what is known as superuser or root privileges for our normal account. This will allow our normal user to run commands with administrative privileges by putting the word sudo before the command.

To add these privileges to our new user, we need to add the user to the wheel or sudo group dependant on distribution.

RHEL/CentOS/AlmaLinux/RockyLinux/Fedora

usermod -aG wheel <new-user>

Debian/Ubuntu

usermod -aG sudo <new-user>

Now, when logged in as your regular user, you would need to type sudo before commands to run them with superuser privileges.

Step 3 — Create SSH Keys

Creation of SSH Keys can be achieved a number of ways:

  • With Putty-gen
  • With an existing Linux Server

Putty-Gen

PuTTYgen is an key generator tool for creating SSH keys for PuTTY. It is analogous to the ssh-keygen tool used in some other SSH implementations.

PuTTYgen download and install

PuTTYgen is normally installed as part of the normal PuTTY .msi package installation. There is no need for a separate PuTTYgen download. Download the PuTTY installation package.

Running PuTTYgen

Go to Windows Start menuAll ProgramsPuTTYPuTTYgen.

PuTTYgen started

Creating a new key pair for authentication

To create a new key pair, select the type of key to generate from the bottom of the screen (using SSH-2 RSA with 2048 bit key size is good for most people; another good well-known alternative is ECDSA).

Then click Generate, and start moving the mouse within the Window. Putty uses mouse movements to collect randomness. The exact way you are going to move your mouse cannot be predicted by an external attacker. You may need to move the mouse for some time, depending on the size of your key. As you move it, the green progress bar should advance.

Once the progress bar becomes full, the actual key generation computation takes place. This may take from several seconds to several minutes. When complete, the public key should appear in the Window. You can now specify a passphrase for the key.

You should save at least the private key by clicking Save private key. It may be advisable to also save the public key, though it can be later regenerated by loading the private key (by clicking Load).

PuTTYgen generating RSA SSH key

We strongly recommended using a passphrase be for private key files intended for interactive use. If keys are needed for automation (e.g., with WinSCP, then they may be left without a passphrase.

puttygen created key and asking for passphase to save private key

Existing Linux Server

The first step is to create a key pair on the client machine (usually your computer):

ssh-keygen

By default, ssh-keygen will create a 2048-bit RSA key pair, which is secure enough for most use cases (you may optionally pass in the -b 4096 flag to create a larger 4096-bit key).

After entering the command, you should see the following prompt:

Output
Generating public/private rsa key pair.
Enter file in which to save the key (/your_home/.ssh/id_rsa):

Press ENTER to save the key pair into the .ssh/ subdirectory in your home directory, or specify an alternate path.

If you had previously generated an SSH key pair, you may see the following prompt:

Output
/home/your_home/.ssh/id_rsa already exists.
Overwrite (y/n)?

If you choose to overwrite the key on disk, you will not be able to authenticate using the previous key anymore. Be very careful when selecting yes, as this is a destructive process that cannot be reversed.

You should then see the following prompt:

Output
Enter passphrase (empty for no passphrase):

Here you optionally may enter a secure passphrase, which is highly recommended. A passphrase adds an additional layer of security to prevent unauthorized users from logging in. To learn more about security, consult our tutorial on How To Configure SSH Key-Based Authentication on a Linux Server.

You should then see the following output:

Output
Your identification has been saved in /your_home/.ssh/id_rsa.
Your public key has been saved in /your_home/.ssh/id_rsa.pub.
The key fingerprint is:
a9:49:2e:2a:5e:33:3e:a9:de:4e:77:11:58:b6:90:26 username@remote_host
The key's randomart image is:
+--[ RSA 2048]----+
|     ..o         |
|   E o= .        |
|    o. o         |
|        ..       |
|      ..S        |
|     o o.        |
|   =o.+.         |
|. =++..          |
|o=++.            |
+-----------------+

You now have a public and private key that you can use to authenticate. The next step is to place the public key on your server so that you can use SSH-key-based authentication to log in.

 

Adding Public keys to servers can be achieved in a number of ways also:

  • Using our Control Panel
  • Using an existing Linux Server
  • Uploading Keys via SSH
  • Manually Uploading

Via Control Panel

Log into your user account. In the left menu tabs, select SSH Keys then select the Add SSH Key tab, give your key a name and paste in the public key.

Via Linux Server

The quickest way to copy your public key to the CentOS host is to use a utility called ssh-copy-id. Due to its simplicity, this method is highly recommended if available. If you do not have ssh-copy-id available to you on your client machine, you may use one of the two alternate methods provided in this section (copying via password-based SSH, or manually copying the key).

The ssh-copy-id tool is included by default in many operating systems, so you may have it available on your local system. For this method to work, you must already have password-based SSH access to your server.

To use the utility, you need only specify the remote host that you would like to connect to and the user account that you have password SSH access to. This is the account to which your public SSH key will be copied.

The syntax is:

ssh-copy-id <username>@<remote-server>
You may see the following message:
Output
The authenticity of host '203.0.113.1 (203.0.113.1)' can't be established.
ECDSA key fingerprint is fd:fd:d4:f9:77:fe:73:84:e1:55:00:ad:d6:6d:22:fe.
Are you sure you want to continue connecting (yes/no)? yes

This means that your local computer does not recognize the remote host. This will happen the first time you connect to a new host. Type yes and press ENTER to continue.

Next, the utility will scan your local account for the id_rsa.pub key that you created earlier. When it finds the key, it will prompt you for the password of the remote user’s account:

Output
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
username@203.0.113.1's password:

Type in the password (your typing will not be displayed for security purposes) and press ENTER. The utility will connect to the account on the remote host using the password you provided. It will then copy the contents of your ~/.ssh/id_rsa.pub key into a file in the remote account’s home ~/.ssh directory called authorized_keys.

You should see the following output:

Output
Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'username@203.0.113.1'"
and check to make sure that only the key(s) you wanted were added.


Step 4 — Test Connection, remove password authentication

Now that an SSH key-pair has been set-up for the privileged user, it is best to test the keys before continuing, with a different shell session, try and log into the server. If there was no prompt for a password and no error, then we cab continue.

We now want to remove password authentication and root login so that the root user account will no longer be able to log in via SSH.

If you were able to login to your account using SSH without a password, you have successfully configured SSH-key-based authentication to your account. However, your password-based authentication mechanism is still active, meaning that your server is still exposed to brute-force attacks.

Before completing the steps in this section, make sure that you either have SSH-key-based authentication configured for the root account on this server, or preferably, that you have SSH-key-based authentication configured for a non-root account on this server with sudo privileges. This step will lock down password-based logins, so ensuring that you will still be able to get administrative access is crucial.

Once you’ve confirmed that your remote account has administrative privileges, log into your remote server with SSH keys, either as root or with an account with sudo privileges. Then, open up the SSH daemon’s configuration file:

sudo vi /etc/ssh/sshd_config

Inside the file, search for a directive called PasswordAuthentication & PermitRootLogin. This may be commented out. If it is, press i to insert text, and then uncomment the line by deleting the # in front of the PasswordAuthentication directive. When you find the directive, set the value to no. This will disable your ability to log in via SSH using account passwords:

/etc/ssh/sshd_config
...
PasswordAuthentication no
PermitRootLogin no
...

When you are finished making changes, press ESC and then :wq to write the changes to the file and quit. To implement these changes, you need to restart the sshd service:

sudo systemctl restart sshd.service

As a precaution, open up a new terminal window and test that the SSH service is functioning correctly before closing this session:

ssh <username>@<remote_server>

Once you have verified your SSH service, you can safely close all current server sessions.

The SSH daemon on the server now only responds to SSH keys. Password-based authentication has successfully been disabled.

 

Step 6 — Implementing A basic Firewalls With iptables

Start by resetting your firewall rules so that you can review how policies can be built from the command line. Flush all of your rules by running the following:

sudo iptables -F

Now verify that your rules are reset:

sudo iptables -S

You should have output that shows the rules in the filter table are gone and that the default policy is set to ACCEPT on all chains:

Output
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT

Next, you will create all of your protocol-specific chains. These will be used to hold the rules that create exceptions to your deny policy for services you want to expose:

sudo iptables -N UDP
sudo iptables -N TCP
sudo iptables -N ICMP

Next, add the exception for SSH traffic. SSH uses TCP, so you’ll add a rule to accept TCP traffic destined for port 22 to the TCP chain:

sudo iptables -A TCP -p tcp --dport 22 -j ACCEPT

If you want to add additional TCP services, you can do that now by repeating the command with the port number replaced.

In the INPUT chain, where all incoming traffic begins filtering, we need to add our general purpose rules. These are some common sense rules that set the baseline for our firewall by accepting traffic that’s low risk (local traffic and traffic that’s associated with connections we’ve already checked) and dropping traffic that is clearly not useful (invalid packets).

First, create an exception to accept all traffic that is part of an established connection or is related to an established connection:

sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

This rule uses the conntrack extension, which provides internal tracking so that iptables has the context it needs to evaluate packets as part of larger connections instead of as a stream of discrete, unrelated packets. TCP is a connection-based protocol, so an established connection is fairly well-defined. For UDP and other connectionless protocols, established connections refer to traffic that has seen a response (the source of the original packet will be the destination of the response packet, and vice versa). A related connection refers to a new connection that has been initiated in association with an existing connection. The classic example here is an FTP data transfer connection, which would be related to the FTP control connection that has already been established.

You’ll also want to allow all traffic originating on the local loopback interface. This is traffic generated by the server and destined for the server. It is used by services on the host to communicate with one another

sudo iptables -A INPUT -i lo -j ACCEPT

Finally, deny all invalid packets. Packets can be invalid for a number of reasons. They may refer to connections that do not exist, they may be destined for interfaces, addresses, or ports that do not exist, or they may be malformed. In any case, you’ll drop all invalid packets since there is no proper way to handle them and because they could represent malicious activity:

sudo iptables -A INPUT -m conntrack --ctstate INVALID -j DROP

Creating the Jump Rules to the Protocol-Specific Chains

So far, we’ve created some general rules in the INPUT chain and some rules for specific acceptable services within our protocol-specific chains. However, right now, traffic comes into the INPUT chain and has no way of reaching our protocol-specific chains.

Now you need to direct traffic in the INPUT chain into the appropriate protocol-specific chains. You can match on protocol type to send it to the right chain. Also, ensure that the packet represents a new connection (any established or related connections should already be handled earlier). Start with UDP traffic:

sudo iptables -A INPUT -p udp -m conntrack --ctstate NEW -j UDP

Next, run the following command for TCP traffic. Please note that with TCP packets, you’ll add the additional requirement that the packet is a SYN packet, which is the only valid type to start a TCP connection:

sudo iptables -A INPUT -p tcp --syn -m conntrack --ctstate NEW -j TCP

Then run the following for ICMP traffic:

sudo iptables -A INPUT -p icmp -m conntrack --ctstate NEW -j ICMP

Rejecting All Remaining Traffic

If a packet that was passed to a protocol-specific chain did not match any of the rules within, control will be passed back to the INPUT chain. Anything that reaches this point should not be allowed by your firewall.

You’ll deny the traffic using the REJECT target, which sends a response message to the client. This allows you to specify the outbound messaging so that you can mimic the response that would be given if the client tried to send packets to a regular closed port. The response is dependent on the protocol used by the client.

Attempting to reach a closed UDP port will result in an ICMP message stating “port unreachable”. You can imitate this by running the following:

sudo iptables -A INPUT -p udp -j REJECT --reject-with icmp-port-unreachable

Attempting to establish a TCP connection on a closed port results in a TCP RST response:

sudo iptables -A INPUT -p tcp -j REJECT --reject-with tcp-reset

For all other packets, you can send a ICMP “protocol unreachable” message to indicate that the server doesn’t respond to packets of that type:

sudo iptables -A INPUT -j REJECT --reject-with icmp-proto-unreachable

Adjusting Default Policies

The last three rules you added should handle all remaining traffic in the INPUT chain. However, you should set the default policy to DROP as a precaution, as in the following:

sudo iptables -P INPUT DROP

You should also set this policy in the FORWARD chain if this server isn’t configured as a router to other machines:

sudo iptables -P FORWARD DROP
To match your IPv6 policy of dropping all traffic, you can use the following ip6tables commands, starting with INPUT:
sudo ip6tables -P INPUT DROP

Then run the following for FORWARD:

sudo ip6tables -P FORWARD DROP

Finish up by setting the policy for OUTPUT:

sudo ip6tables -P OUTPUT DROP

This should replicate your rules set fairly closely.

Saving iptables Rules

At this point, you should test your firewall rules and make sure they block the traffic you want to keep out while not hindering your normal access. Once you’re satisfied that your rules are behaving correctly, you can save them so that they will be automatically applied to your system at boot.

Save your current rules (both IPv4 and IPv6) by running the following:

sudo service netfilter-persistent save

This will overwrite your /etc/iptables/rules.v4 and /etc/iptables/rules.v6 files with the policies you crafted on the command line.


Was this answer helpful?

Back