Written by Robert Whitney Category: Linux

  1. Introduction
  2. Hardening SSH
    1. What is SSH?
    2. SSH Keys & SSH Key Authentication
      1. Generate SSH Keys
      2. Securing your SSH private key
      3. Disable SSH Password Authentication
  3. Hardening PAM
    1. What is PAM?
    2. Hardening su
    3. Hardening sudo
  4. Files & Backups
    1. Pull not Push backups
    2. Use File/Folder Encryption
    3. Securing your backup server
  5. Hiding Processes & Preventing Fork Bombs
  6. Use your Firewall!
    1. Restrict egress traffic
  7. Conclusion

Introduction

This blog post will not come even close to being everything that you need to do to secure a Linux system. But I try to be as comprehensive as possible without writing a book. Please remember throughout this guide to not just have a more secure system, but be a more secure admin. A computer system can only be so secure, but it is as weak as it's weakest administrator. The human element always remains insecure, and by understanding that you will understand why, as comprehensive as this guide becomes to be, it will never be enough.

I want to start off by saying that these are just tricks that I picked up along the way as a researcher, and hobbyist. While I have worked in the field of IT, and have secured systems while working in the field, I've never actually recieved any sort of diploma or certificate in the realm of cyber security. This guide is entirely based off of real world experience. I will likely update it with new and improved techniques in the future, especially as I work towards my degree in cyber security & data assurance.

Hardening SSH

What is SSH?

SSH is a secure shell into a system via the internet. It allows you to run commands in a terminal to that machine. Certainly this is a service that you will very much like to protect from potential intruders. This guide will go over several steps that you can take to secure your SSH server.

SSH Keys & SSH Key Authentication

The first thing that you should do when setting up SSH for terminal services is generate and use SSH keys for authentication. This will allow you to securily connect via decrypting a message sent by the server and encrypted with your public key. The messages is decrypted with your private key, stored on the client machine. If setup correctly, the SSH server will not allow password authentication, preventing bruteforce attacks from working.

Generate SSH Keys

On Linux, Mac, or Windows type the following command into your terminal, command prompt, or powershell.

$ ssh-keygen -b 8192

This will take you through the steps of generating your very first, 8192 bit SSH private & public key pair. You may choose to generate a 2048 bit (default) or 4096 bit key instead by replacing the argument for -b. By default this keypair will be stored in your home/user directory in the .ssh folder. It is recommended that you back these files up on an external drive in which you will not lose them. This is very important, if you lose access to your SSH keys you may lock yourself out of your server entirely.

Securing your SSH private key

 When prompted, make sure that you set a password on your private key. This password should be something secure, that you will remember. If you lose access to this key, you will likely lose access to your servers! Do not forget your SSH key password! Congratulations, you have taken the first steps towards securing your SSH key!

When handling your SSH keys make sure that you obey the following rules of thumb to make sure that your key, and servers, stay protected.

Disable SSH Password Authentication

Make the following changes to your /etc/ssh/sshd_config file:

PubKeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no

PubKeyAuthentication determines whether or not SSH key authentication is enabled on
the SSH server. It must be set to yes in order to activate SSH key authentication.
PasswordAuthentication determines whether or not password authentication is enabled
on the SSH server. Set this to no to enforce key authentication only.
PermitEmptyPasswords determines whether or not empty passwords are permitted on
the SSH server. This should always be set to no.

Hardening PAM

What is PAM?

PAM stands for Pluggable Authentication Modules, and it provides dynamic authentication support for applications and services on Linux. There are many things that we can do to harden PAM, but this guide will cover a few of the basics.

Hardening su

If you make the following changes to /etc/pam.d/su, then users who are not in the "wheel" group will not be able to login to an account using su even if the password given is correct.

auth sufficient pam_rootok.so
auth required  pam_wheel.so group=wheel

 The first line will allow the user root to use su whenever. The second line will only allow users to use su if they are in the "wheel" group.

Hardening sudo

To make sure that the system administrators are able to use root privileges you may want to setup sudo. This allows someone to type sudo before a command, and it will escalate privileges to root as long as they are listed in the /etc/sudoers file.

Remember that giving sudo privileges is no different from giving users direct access to the root account. Users with sudo will be able to execute specified commands, or all commands as root, depending on what is specified in the /etc/sudoers file.

Files & Backups

Your files are critical, and so therefore it is critical to back them up in a way that they cannot be tampered with. This means making sure that an outside system is able to securely access files from the machine over an encrypted protocol. Suggested here is to use something like rsync.

Pull not Push backups

It is absolutely critical that you pull backups to your backup server, instead of pushing them to the backup server. The reason for this is that if the source system can access the backup files, then the integrity of your backups is already compromised. This can however be prevented by using backup software that appends backups instead of allowing access to overwrite/modify them.

Use File/Folder Encryption

Whenever possible you should use File / Folder encryption for your backups. Some file syncing solutions, such as Ubuntu's backup solution or resilliosync, have encryption options as well. These programs will typically allow you to encrypt backups on the remote end, so that the remote server never sees the plain text files. For a Linux desktop you should use the full disk encryption options which are typically provided by the installation medium of your flavor of Linux. I don't personally set this up on servers, but you may want to do that as well. A con of doing so is that if the server, for whatever reason, reboots then you will need to enter that password at the console or over KVM before the server will fully come back on.

Securing your backup server

Since your backup server will need access to all of your other servers, I provide and recommend the following  tips for securing your backup server:

  1. Your backup server should be behind a firewall / NAT, with no outside access.
  2. Your backup server should be on site, and push to an off-site storage solution when necessary.
  3. The backup server is the only server that should be able to push backups, for the
    purpose of storing them off-site on a solution such as Google’s cold storage.  Given that you read and follow all the tips in this guide this shouldn’t be an issue as this will likely be the most secure server in your infrastructure.

Hiding Processes & Preventing Fork Bombs

If an attacker gains access to your system, then you want to complicate things as much as possible. mount -o remount,rw,hidepid=2 /proc will remount your /proc directory with the option hidepid=2. This means that users will only be able to see their own running processes. To make this change permanent, add the following line to /etc/fstab:

proc    /proc    proc    defaults,hidepid=2     0     0
[email protected]:~$ ps faux
      USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
      dev      10380  0.7  0.4  12476  4432 pts/0    Ss   09:47   0:00 -bash
      dev      10389  0.0  0.1  29800  1564 pts/0    R+   09:47   0:00  \_ ps faux
      dev      10372  0.0  0.5  56404  5340 ?        Ss   09:47   0:00 /lib/systemd/systemd --user

 To prevent fork bombs (never ending process spawning) you will need to add the following to the end of the /etc/security/limits.conf file.

*        hard    nproc           100

This will allow all users to only spawn 100 processes. You may want to increase or decrease that limit depending on what your server is doing.

Use your Firewall!

Most Linux distributions come packaged with iptables. Here is an example allowing access to SSH for a single host and denying everything else:


      iptables -A INPUT -p tcp -s 192.168.1.10/32 --dport 22 -m conntrack --ctstate NEW,ESTABLISHED -j ACCEPT # Allow 192.168.1.10 to port 22/TCP.
      iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT # Allow established outbound connections to port 22/TCP
      iptables -A INPUT -p tcp --dport 22 -j ACCEPT # Allow established inbound connects to port 22/TCP
      iptables -A INPUT -j DROP # Drop all other traffic

Each line of the above example is commented so that you can understand what each line does. It is recommended that you use strict ingress rules.

Restrict egress traffic

It's not typical, but I recommend using very strict egress traffic rules. The following rules will allow the most common traffic on a Linux server, which requires updates via HTTP(S), as well as DNS, NTP, identd, and git over SSH. These rules are setup for IPv4 and IPv6.

iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 80 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 113 -j ACCEPT
iptables -A OUTPUT -p udp --dport 123 -j ACCEPT
iptables -A OUTPUT -p tcp --dport 443 -j ACCEPT
iptables -A OUTPUT -j REJECT
ip6tables -A OUTPUT -p tcp --dport 22 -j ACCEPT
ip6tables -A OUTPUT -p udp --dport 53 -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 80 -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 113 -j ACCEPT
ip6tables -A OUTPUT -p udp --dport 123 -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 443 -j ACCEPT
ip6tables -A OUTPUT -p icmp -j ACCEPT
ip6tables -A OUTPUT -j REJECT

If you want to learn more in depth about iptables take a look at this guide on opensource.com.

Conclusion

I know that I've barely scratched the surface of this topic, so if you have any suggestions as to what to add, or you feel like I missed something, please feel free to leave a comment below. I plan on adding to this guide in the future, so be sure to bookmark it and check back for updates!

Update June 15, 2020: I've updated the guide based on some reddit suggestions.

Next up: