How To Secure A Linux Server
An evolving how-to guide for securing a Linux server.
Table of Contents
- Introduction
- Before You Start
- Securing Linux
- Other Stuff
- Miscellaneous
Introduction
Document Objective
This guide's purpose is to teach you how to secure a Linux server.
Hopefully you already understand why good security is important. That is a heavy topic onto itself and answering it is out-of-scope for this document. If you don't know the answer to that question, I advise you research it.
At a high level, the second a device, like a server, is in the public domain -- i.e visible to the outside world -- it becomes a target for bad-actors. An unsecured device is a playground for bad-actors who want access to confidential data, or more nodes for their coordinated large-scale DDOS attacks.
There are a lot of things you can do to secure a Linux server and this guide will attempt to cover as many of them as possible. More topics/material will be added as I learn, or as folks contribute.
This guide...
- ...is a work in progress.
- ...is focused on at-home Linux servers. All of the concepts/recommendations here apply to larger/professional environments but those use-cases call for more advanced and specialized configurations that are out-of-scope for this guide.
- ...does not teach you about Linux, or how to use it.
- ...does not tell you how to install Linux.
- ...does not teach you everything you need to know about security nor does it get into all aspects of system/server security. Physical security, for example, is out of scope for this guide.
- ...does not talk about how programs/tools work, nor does it delve into their nook and crannies. Most of the programs/tools this guide references are very powerful and highly configurable. The goal is to cover the bare necessities that will get you started. To learn more, read the documentation.
- ...aims to make it easy by providing code you and can copy-and-paste. You might need to modify the commands before you paste so keep your favorite text editor handy.
Why Yet Another Guide
This guide may appear duplicative/unnecessary because there are countless articles online that tell you how to how to secure Linux but the information is spread across different articles, that cover different things, and in different ways. Who has time to scour through hundreds of articles?
As I was going through research for my Debian build, I kept notes. At the end I realized that, along with what I already knew, and what I was learning, I had the makings of a how-to guide. I figured I'd put it online to hopefully help others learn, and save time.
I've never found one guide that covers everything -- this guide is my attempt to remedy that.
Many of the things covered in this guide may be rather basic/trivial, but most of us do not install Linux every day and it is easy to forget those basic things.
IT automation tools like Ansible, Chef, Jenkins, Puppet, etc. help with the tedious task of installing/configuring a server but IMHO they are better suited for multiple or large scale deployments. IMHO, the overhead required to use those kinds of automation tools is wholly unnecessary for a one-time single server install for home use.
Contributing
I wanted to put this document on GitHub to make it easy to collaborate. The more folks that contribute, the better and more complete this guide will become.
To contribute you can fork and submit a pull request or submit a new issue.
For The Lazy - Editing Configuration Files
I am very lazy and do not like to edit files by hand if I don't need to. I also assume everyone else is just like me. :)
So, when and where possible, I have provided code snippets to quickly do what is needed, like add or change a line in a configuration file.
The code snippets use basic commands like echo, cat, sed, awk, and grep. How the code snippets work, like what each command/part does, is out of scope for this guide -- the man pages are your friend.
Note: The code snippets do not validate/verify the change went through -- i.e. the line was actually added or changed. I'll leave the verifying part in your capable hands. The steps in this guide do include taking backups of all files that will be changed.
Not all changes can be automated with code snippets. Those changes need good, old fashioned, manual editing. For example, you can't just append a line to an INI type file. Use your favorite Linux text editor.
Before You Start
Notes
- Debian is my distribution of choice and what this guide was tested on. The lines below will, in most cases, work in other distributions -- although, file paths and settings may differ slightly. Check your distribution's documentation.
- Do not blindly copy-and-paste without understanding what you're pasting. Some commands will need to be modified for your needs before they'll work -- usernames for example.
- Your use-case may call for a different configuration. You'll want to understand what each section does and apply as you deem appropriate. You may not, for example, want to disable root login because you have no means of recovering, or you may not want to password protect GRUB because there is zero risk of a bad actor getting physical access to your server.
Installing Linux
Installing Linux is out-of-scope for this document. If you need help, start with your distribution's documentation. Regardless of the distribution, the high-level process usually goes like so:
- download the ISO
- burn/copy/transfer it to your install medium (e.g. a CD or USB stick)
- boot your server from your install medium
- follow the prompts to install
Pre/Post Installation
- If you're opening ports on your router so you can access your server from the outside, disable the port forwarding until your system is up and secured.
- Where applicable, use the expert install option so you have tighter control of what is running on your server. Only install what you absolutely need. I, personally, do not install anything other than SSH.
- Unless you're doing everything physically connected to your server, you'll need SSH access so be sure it is installed.
- Be sure to keep your system up-to-date (i.e.
sudo apt update && sudo apt upgradeon Debian based systems) - At some point, like maybe right after configuring SSH public/private keys, make sure you perform any tasks specific to your setup like:
- configuring network
- configuring mount points in
/etc/fstab(like mounting/tmpin RAM usingtmpfs) - creating the initial user accounts
- etc...
- Your server will need to be able to send e-mails so you can get important security alerts. If you're not setting up a mail server check Configure Gmail as MTA.
Securing Linux
SSH Public/Private Keys
Why
Using SSH public/private keys is more secure than using a password. It also makes it easier and faster, to connect to our server because you don't have to enter a password.
At a high level, public/private keys work by using two keys to encrypt data:
- One key, the public key, can only encrypt data, not decrypt it
- The other key, the private key, can decrypt the data
For SSH, a public and private key is created on the client. The public key is then securely transferred to the server you want to connect to. After this is done, SSH uses the public and private keys to establish a secure connection.
Goals
- 4096 bit RSA public/private SSH keys
- private key on your client
- public key on your server
References
- https://www.ssh.com/ssh/public-key-authentication
- https://help.ubuntu.com/community/SSH/OpenSSH/Keys
- https://linux-audit.com/using-ed25519-openssh-keys-instead-of-dsa-rsa-ecdsa/
man ssh-keygenman ssh-copy-id
Steps
-
From the computer you're going to use to connect to your server, the client, not the server itself, create an ed25519 key:
ssh-keygen -t ed25519 -
Transfer it to your server:
ssh-copy-id user@serverYou'll need to do this for every computer and account you'll be connecting to your server from/as.
Now would be a good time to perform any tasks specific to your setup.
Linux Kernel sysctl Hardening (WIP)
References
- https://geektnt.com/sysctl-conf-hardening.html
- https://linoxide.com/how-tos/linux-server-protection/
- https://www.cyberciti.biz/faq/linux-kernel-etcsysctl-conf-security-hardening/
- https://github.com/klaver/sysctl/blob/master/sysctl.conf
Change Default umask
Why
umask controls the default permissions of files/folders when they are created. Insecure file/folder permissions give other accounts potentially unauthorized access to your data. This may include the ability to make configuration changes.
- For non-root accounts, there is no need for other accounts to get any access to the account's files/folders by default.
- For the root account, there is no need for the file/folder primary group or other accounts to have any access to root's files/folders by default.
When and if other accounts need access to a file/folder, you want to explicitly grant it using a combination of file/folder permissions and primary group.
Why Not
Changing the default umask can create unexpected problems.
Goals
- set default
umaskfor non-root accounts to 0027 - set default
umaskfor the root account to 0077
References
- https://www.linuxnix.com/umask-define-linuxunix/
- https://serverfault.com/questions/818783/which-umask-is-more-secure-in-linux-022-or-027
- https://www.cyberciti.biz/tips/understanding-linux-unix-umask-value-usage.html
man umask
Steps
-
Set default
umaskfor non-root accounts to 0027 by adding this line to/etc/profileand/etc/bash.bashrc:umask 0027sudo cp --preserve /etc/profile /etc/profile.$(date +"%Y%m%d%H%M%S") sudo cp --preserve /etc/bash.bashrc /etc/bash.bashrc.$(date +"%Y%m%d%H%M%S") echo -e "\numask 0027 # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" | sudo tee -a /etc/profile /etc/bash.bashrc -
We also need to add this line to
/etc/login.defs:UMASK 0027sudo cp --preserve /etc/login.defs /etc/login.defs.$(date +"%Y%m%d%H%M%S") echo -e "\nUMASK 0027 # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" | sudo tee -a /etc/login.defs -
Set default
umaskfor the root account to 0077 by adding this line to/root/.bashrc:umask 0077sudo cp --preserve /root/.bashrc /root/.bashrc.$(date +"%Y%m%d%H%M%S") echo -e "\numask 0077 # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" | sudo tee -a /root/.bashrc
Password Protect GRUB
Why
If a bad actor has physical access to your server, they could use GRUB to gain unauthorized access to your system.
Why Not
If you forget the password, you'll have to go through some work to recover the password.
Goals
- auto boot the default Debian install and require a password for anything else
Notes
- This will only protect GRUB and anything behind it like your operating systems. Check your motherboard's documentation for password protecting your BIOS to prevent a bad actor from circumventing GRUB.
References
- https://selivan.github.io/2017/12/21/grub2-password-for-all-but-default-menu-entries.html
- https://help.ubuntu.com/community/Grub2/Passwords
- https://computingforgeeks.com/how-to-protect-grub-with-password-on-debian-ubuntu-and-kali-linux/
man grubman grub-mkpasswd-pbkdf2
Steps
-
Create a Password-Based Key Derivation Function 2 (PBKDF2) hash of your password:
grub-mkpasswd-pbkdf2 -c 100000The below output is from using
passwordas the password:Enter password: Reenter password: PBKDF2 hash of your password is grub.pbkdf2.sha512.100000.2812C233DFC899EFC3D5991D8CA74068C99D6D786A54F603E9A1EFE7BAEDDB6AA89672F92589FAF98DB9364143E7A1156C9936328971A02A483A84C3D028C4FF.C255442F9C98E1F3C500C373FE195DCF16C56EEBDC55ABDD332DD36A92865FA8FC4C90433757D743776AB186BD3AE5580F63EF445472CC1D151FA03906D08A6D -
Copy everything after
PBKDF2 hash of your password is, starting from and includinggrub.pbkdf2.sha512...to the end. You'll need this in the next step. -
Create the file
/etc/grub.d/01_passwordand add the below code after replacing[hash]with the hash you copied from the first step:#!/bin/sh set -e cat << EOF set superusers="grub" password_pbkdf2 grub [hash] EOFFor example:
#!/bin/sh set -e cat << EOF set superusers="grub" password_pbkdf2 grub grub.pbkdf2.sha512.100000.2812C233DFC899EFC3D5991D8CA74068C99D6D786A54F603E9A1EFE7BAEDDB6AA89672F92589FAF98DB9364143E7A1156C9936328971A02A483A84C3D028C4FF.C255442F9C98E1F3C500C373FE195DCF16C56EEBDC55ABDD332DD36A92865FA8FC4C90433757D743776AB186BD3AE5580F63EF445472CC1D151FA03906D08A6D EOF -
Set the file's execute bit so
update-grubincludes it when it updates GRUB's configuration:sudo chmod a+x /etc/grub.d/01_password -
Make a backup of
/etc/grub.d/10_linuxand unset execute bit soupdate-grubdoesn't try to run it:sudo cp --preserve /etc/grub.d/10_linux /etc/grub.d/10_linux.$(date +"%Y%m%d%H%M%S") sudo chmod a-x /etc/grub.d/10_linux.* -
To make the default Debian install unrestricted (without the password) while keeping everything else restricted (with the password) modify
/etc/grub.d/10_linuxand add--unrestrictedto theCLASSvariable.sudo sed -i -r -e "/^CLASS=/ a CLASS=\"\${CLASS} --unrestricted\" # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" /etc/grub.d/10_linux -
Update GRUB with
update-grub:sudo update-grub
Limit Who Can Use sudo
Why
sudo lets accounts run commands as other accounts, including root. We want to make sure that only the accounts we want can use sudo.
Goals
sudoprivileges limited to those who are in a group we specify
Notes
- Your installation may already have a special group intended for this purpose so check first.
- Debian creates the
sudogroup - RedHat creates the
wheelgroup
- Debian creates the
Steps
-
Create a group:
sudo groupadd sudo -
Add account(s) to the group:
sudo usermod -a -G sudo user1 sudo usermod -a -G sudo user2 sudo usermod -a -G sudo ...You'll need to do this for every account on your server that needs SSH access.
-
Edit
/etc/sudoers:sudo cp --preserve /etc/sudoers /etc/sudoers.$(date +"%Y%m%d%H%M%S") sudo visudo -
Add this line if it is not already there:
%sudo ALL=(ALL:ALL) ALL
Disable Root Login
Why
If you have sudo configured properly, then the root account will mostly never need to log in directly -- either at the terminal or remotely.
Why Not
Be warned, this can cause issues with some configurations!
If your installation uses sulogin (like Debian) to drop to a root console during boot failures, then locking the root account will prevent sulogin from opening the root shell and you will get this error:
Cannot open access to console, the root account is locked.
See sulogin(8) man page for more details.
Press Enter to continue.
To work around this, you can use the --force option for sulogin. Some distributions already include this, or some other, workaround.
Goal
- locked root account that nobody can use to log in as root
Notes
- Some distributions disable root login by default (e.g. Ubuntu) so you may not need to do this step. Check with your distribution's documentation.
References
- https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=806852
- https://github.com/systemd/systemd/issues/7115
7ff1162e67- https://github.com/systemd/systemd/issues/11596
man systemd
Steps
-
Lock the root account:
sudo passwd -l root
Secure SSH
Create SSH Group For AllowGroups
Why
To make it easy to control who can SSH to the server.
Goals
- a UNIX group that we'll use in Secure
/etc/ssh/sshd_configto limit who can SSH to the server
Notes
- This is a per-requisite step to support the
AllowGroupsetting set in Secure/etc/ssh/sshd_config.
References
man groupaddman usermod
Steps
-
Create a group:
sudo groupadd sshusers -
Add account(s) to the group:
sudo usermod -a -G sshusers user1 sudo usermod -a -G sshusers user2 sudo usermod -a -G sshusers ...You'll need to do this for every account on your server that needs SSH access.
Secure /etc/ssh/sshd_config
Why
SSH is a door into your server. This is especially true if you are opening ports on your router so you can SSH to your server from outside your home network. If it is not secured properly, a bad-actor could use it to gain unauthorized access to your system.
Goal
- a secure SSH configuration
Notes
- Make sure you've completed Create SSH Group For
AllowGroupsfirst.
References
- Mozilla's OpenSSH guidelines for OpenSSH 6.7+ at https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67
- https://linux-audit.com/audit-and-harden-your-ssh-configuration/
- https://www.ssh.com/ssh/sshd_config/
- https://www.techbrown.com/harden-ssh-secure-linux-vps-server/
man sshd_config
Steps
-
Make a backup of
/etc/ssh/sshd_config:sudo cp --preserve /etc/ssh/sshd_config /etc/ssh/sshd_config.$(date +"%Y%m%d%H%M%S") -
Edit
/etc/ssh/sshd_configthen find and edit or add these settings that should apply regardless of your configuration/setup:######################################################################################################## # start settings from https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67 as of 2019-01-01 ######################################################################################################## # Supported HostKey algorithms by order of preference. HostKey /etc/ssh/ssh_host_ed25519_key HostKey /etc/ssh/ssh_host_rsa_key HostKey /etc/ssh/ssh_host_ecdsa_key KexAlgorithms curve25519-sha256@libssh.org,ecdh-sha2-nistp521,ecdh-sha2-nistp384,ecdh-sha2-nistp256,diffie-hellman-group-exchange-sha256 Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com,hmac-sha2-512,hmac-sha2-256,umac-128@openssh.com # LogLevel VERBOSE logs user's key fingerprint on login. Needed to have a clear audit track of which key was using to log in. LogLevel VERBOSE # Log sftp level file access (read/write/etc.) that would not be easily logged otherwise. Subsystem sftp /usr/lib/ssh/sftp-server -f AUTHPRIV -l INFO # Use kernel sandbox mechanisms where possible in unprivileged processes # Systrace on OpenBSD, Seccomp on Linux, seatbelt on MacOSX/Darwin, rlimit elsewhere. UsePrivilegeSeparation sandbox ######################################################################################################## # end settings from https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67 as of 2019-01-01 ######################################################################################################## # only use the newer, more secure protocl Protocol 2 # disable X11 forwarding as X11 is very insecure # you really shouldn't be running X on a server anyway X11Forwarding no # disable port forwarding AllowTcpForwarding no AllowStreamLocalForwarding no GatewayPorts no PermitTunnel no # don't allow login if the account has an empty password PermitEmptyPasswords no # ignore .rhosts and .shosts IgnoreRhosts yes # verify hostname matches IP UseDNS no Compression no TCPKeepAlive no AllowAgentForwarding no PermitRootLogin no -
Then find and edit or add these settings, and set values as per your requirements:
Setting Valid Values Example Description Notes AllowGroups local UNIX group name AllowGroups sshusersgroup to allow SSH access to ClientAliveCountMax number ClientAliveCountMax 0maximum number of client alive messages sent without response ClientAliveInterval number of seconds ClientAliveInterval 300timeout in seconds before a response request ListenAddress space separated list of local addresses ListenAddress 0.0.0.0ListenAddress 192.168.1.100
local addresses sshdshould listen onLoginGraceTime number of seconds LoginGraceTime 30time in seconds before login times-out MaxAuthTries number MaxAuthTries 2maximum allowed attempts to login MaxSessions number MaxSessions 2maximum number of open sessions MaxStartups number MaxStartups 2maximum number of login sessions Port any open/available port number Port 22port that sshdshould listen onCheck
man sshd_configfor more details what these settings mean. -
Restart ssh:
sudo service sshd restart
Deactivate Short Moduli
Why
Per Mozilla's OpenSSH guidelines for OpenSSH 6.7+, "all Diffie-Hellman moduli in use should be at least 3072-bit-long".
Goal
- deactivate short moduli
References
- Mozilla's OpenSSH guidelines for OpenSSH 6.7+ at https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67
man moduli
Steps
-
Make a backup of
/etc/ssh/moduli:sudo cp --preserve /etc/ssh/moduli /etc/ssh/moduli.$(date +"%Y%m%d%H%M%S") -
Remove short moduli:
sudo awk '$5 >= 3071' /etc/ssh/moduli | sudo tee /etc/ssh/moduli.tmp sudo mv /etc/ssh/moduli.tmp /etc/ssh/moduli
Force Accounts To Use Secure Passwords
Why
By default, accounts can use any password they want, including bad ones. pwquality/pam_pwquality addresses this security gap by providing "a way to configure the default password quality requirements for the system passwords" and checking "its strength against a system dictionary and a set of rules for identifying poor choices."
Goal
- enforced strong passwords
Steps
-
Install
libpam-pwquality.For Debian based systems:
sudo apt install libpam-pwquality -
Edit
/etc/pam.d/common-passwordand change the line that starts like this:password requisite pam_pwquality.soto this:
password requisite pam_pwquality.so retry=3 minlen=10 difok=3 ucredit=-1 lcredit=-1 dcredit=-1 ocredit=-1 maxrepeat=3 gecoschecThe above options are:
retry=3= prompt user 3 times before returning with error.minlen=10= the minimum length of the password, factoring in any credits (or debits) from these:dcredit=-1= must have at least one digitucredit=-1= must have at least one upper case letterlcredit=-1= must have at least one lower case letterocredit=-1= must have at least one non-alphanumeric character
difok=3= at least 3 characters from the new password cannot have been in the old passwordmaxrepeat=3= allow a maximum of 3 repeated charactersgecoschec= do not allow passwords with the account's name
sudo cp --preserve /etc/pam.d/common-password /etc/pam.d/common-password.$(date +"%Y%m%d%H%M%S") sudo sed -i -r -e "s/^(password\s+requisite\s+pam_pwquality.so)(.*)$/# \1\2 # commented by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")\n\1 retry=3 minlen=10 difok=3 ucredit=-1 lcredit=-1 dcredit=-1 ocredit=-1 maxrepeat=3 gecoschec # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")/" /etc/pam.d/common-password
UFW: Uncomplicated Firewall
Why
Call me paranoid but I want to deny all traffic in and out of my server except what I explicitly allow. Why would my server be sending traffic out that I don't know about? And why would external traffic be trying to access my server if I don't know who or what it is? When it comes to good security, reject/deny by default, and allow by exception.
Ensuring that only traffic we explicitly allow is the job of a firewall. On Linux, the most common firewall is iptables. iptables, however, is rather complicated and confusing (IMHO). This is where UFW comes in. UFW simplifies the process of creating and managing iptables rules.
UFW works by letting you configure rules that:
- allow or deny
- input or output traffic
- to or from ports
You can create rules by explicitly specifying the ports or with application configurations that specify the ports.
Goal
- all network traffic, input and output, blocked except those we explicitly allow
Notes
- As you install other programs, you'll need to enable the necessary ports/applications.
References
Steps
-
Install
ufw.For Debian based systems:
sudo apt install ufw -
Deny all outgoing traffic:
sudo ufw default deny outgoing comment 'deny all outgoing traffic' -
Deny all incoming traffic:
sudo ufw default deny incoming comment 'deny all incoming traffic' -
Obviously we want SSH connections in:
sudo ufw limit in ssh comment 'allow SSH connections in' -
Allow additional traffic as per your needs. Some common use-cases:
# allow traffic out on port 53 -- DNS sudo ufw allow out 53 comment 'allow DNS calls out' # allow traffic out on port 123 -- NTP sudo ufw allow out 123 comment 'allow NTP out' # allow traffic out for HTTP, HTTPS, or FTP # apt might needs these depending on which sources you're using sudo ufw allow out http comment 'allow HTTP traffic out' sudo ufw allow out https comment 'allow HTTPS traffic out' sudo ufw allow out ftp comment 'allow FTP traffic out' # allow mail to go out sudo ufw allow out 'Mail submission' comment 'allow mail out' # allow whois sudo ufw allow out whois comment 'allow whois' # allow traffic out on port 68 -- the DHCP client sudo ufw allow out 68 comment 'allow the DHCP client to update' -
Start
ufw:sudo ufw enable -
If you want to see a status:
sudo ufw statusor
sudo ufw status verbose
Default Applications
ufw ships with some default applications. You can see them with:
sudo ufw app list
To get details about the app, like which ports it includes, type:
sudo ufw app info [app name]
For example:
$ sudo ufw app info DNS
Profile: DNS
Title: Internet Domain Name Server
Description: Internet Domain Name Server
Port:
53
Custom Application
If you don't want to create rules by explicitly providing the port number(s), you can create your own application configurations. To do this, create a file in /etc/ufw/applications.d.
For example, here is what you would use for Plex:
$ cat /etc/ufw/applications.d/plexmediaserver
[PlexMediaServer]
title=Plex Media Server
description=This opens up PlexMediaServer for http (32400), upnp, and autodiscovery.
ports=32469/tcp|32413/udp|1900/udp|32400/tcp|32412/udp|32410/udp|32414/udp|32400/udp
Then you can enable it like any other app:
sudo ufw allow plexmediaserver
Fail2ban: Intrusion Detection And Prevention
Why
A firewall will board up all the doors and windows you don't want anyone using so nobody can see they are even there. But what about the doors and windows you want visible so approved folks can use them? Even if the door is locked, how do you ensure that someone doesn't try to force their way in?
That is where Fail2ban comes in. It will monitor network traffic/logs and prevent intrusions by blocking suspicious activity (e.g. multiple successive failed connections in a short time-span).
Goal
- network monitoring for suspicious activity with automatic banning of offending IPs
Notes
- As of right now, the only thing running on this server is SSH so we'll want Fail2ban to monitor SSH and ban as necessary.
- As you install other programs, you'll need to create/configure the appropriate jails and enable them.
References
Steps
-
Install
fail2ban.For Debian based systems:
sudo apt install fail2ban -
We don't want to edit
/etc/fail2ban/fail2ban.confor/etc/fail2ban/jail.confbecause a future update may overwrite those so we'll update a local copy instead. Add this to/etc/fail2ban/jail.localafter replacing[LAN SEGMENT]and[your email]with the appropriate values:[DEFAULT] # the IP address range we want to ignore ignoreip = 127.0.0.1/8 [LAN SEGMENT] # who to send e-mail to destemail = [your e-mail] # who is the email from sender = [your e-mail] # since we're using exim4 to send emails mta = mail # get email alerts action = %(action_mwl)sNote: Your server will need to be able to send e-mails so Fail2ban an let you know of suspicious activity and when it banned an IP.
-
Create a jail for
sshby adding this to/etc/fail2ban/jail.d/ssh.local:[sshd] enabled = true port = ssh logpath = %(sshd_log)s maxretry = 5 -
Enable
fail2banand the jail for SSH:sudo fail2ban-client start sudo fail2ban-client reload sudo fail2ban-client add sshd -
To check the status:
sudo fail2ban-client status sudo fail2ban-client status sshd
Custom Jails
WIP
2FA/MFA for SSH
Why
Even though SSH is a pretty good security guard for your doors and windows, it is still a visible door that bad-actors can see and try to brute-force in. Fail2ban will monitor for these brute-force attempts but there is no such thing as being too secure.
Using Two Factor Authentication (2FA) / Multi Factor Authentication (MFA) requires anyone entering to have two keys to enter which makes it harder for bad actors. The two keys are:
- Their password
- A 6 digit token that changes every 30 seconds
Without both keys, they won't be able to get in.
Why Not
Many folks might find the experience cumbersome or annoying. And, acesss to your system is dependent on the accompanying authenticator app that generates the code.
Goals
- 2FA/MFA enabled for all SSH connections
Notes
- Before you do this, you should have an idea of how 2FA/MFA works and you'll need an authenticator app on your phone to continue.
- We'll use google-authenticator-libpam.
- With the below configuration, a user will only need to enter their 2FA/MFA code if they are logging on with their password but not not if they are using SSH public/private keys. Check the documentation on how to change this behavior to suite your requirements.
References
Steps
-
Install it
libpam-google-authenticator.For Debian based systems:
sudo apt install libpam-google-authenticator -
Make sure you're logged in as the ID you want to enable 2FA/MFA for and execute
google-authenticator:google-authenticatorNotice this is not run as root.
Select default option (y in most cases) for all the questions it asks and remember to save the emergency scratch codes.
-
Now we need to enable it as an authentication method for SSH by adding this line to
/etc/pam.d/sshd:auth required pam_google_authenticator.so nullokCheck here for what
nullokmeans.sudo cp --preserve /etc/pam.d/sshd /etc/pam.d/sshd.$(date +"%Y%m%d%H%M%S") echo -e "\nauth required pam_google_authenticator.so nullok # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" | sudo tee -a /etc/pam.d/sshd -
Enable it in the SSH settings by adding this line in
/etc/ssh/sshd_config:ChallengeResponseAuthentication yessudo cp --preserve /etc/ssh/sshd_config /etc/ssh/sshd_config.$(date +"%Y%m%d%H%M%S") echo -e "\nChallengeResponseAuthentication yes # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" | sudo tee -a /etc/ssh/sshd_config -
Restart
ssh:sudo service sshd restart
Other Stuff
Mount /tmp In RAM Using tmpfs
Why
RAM is faster than disk, even SSD. By mounting /tmp in RAM using tmpfs, you may notice a performance increase.
Why Not
Using tmpfs will consume RAM. If RAM fills up your system may become unstable. tmpfs may resort to using swap.
References
- https://wiki.archlinux.org/index.php/Tmpfs
- https://wiki.centos.org/TipsAndTricks/TmpOnTmpfs
man mountman tmpfs
Steps
-
Add this line to
/etc/fstab:tmpfs /tmp tmpfs defaults,noatime,rw,nodev,nosuid,nodiratime,mode=1777,size=2GB 0 0Change the value of
sizeto suit your needs. If you remove thesizeoption then it will default to using half of your RAM.sudo cp --preserve /etc/fstab /etc/fstab.$(date +"%Y%m%d%H%M%S") echo -e "\ntmpfs /tmp tmpfs defaults,noatime,rw,nodev,nosuid,nodiratime,mode=1777,size=2G 0 0 # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" | sudo tee -a /etc/fstab
Configure Gmail as MTA
Why
Unless you're planning on setting up your own mail server, you'll need a way to send e-mails from your server. This will be important for system alerts/messages.
Goals
mailconfigured to send e-mails from your server using Gmail
References
Steps
-
Install
exim4.For Debian based systems:
sudo apt install exim4 -
Configure
exim4:For Debian based systems:
sudo dpkg-reconfigure exim4-configYou'll be prompted with some questions:
Prompt Answer General type of mail configuration mail sent by smarthost; no local mailSystem mail name (default) IP-addresses to listen on for incoming SMTP connections 127.0.0.1Other destinations for which mail is accepted (default) Visible domain name for local users (default) IP address or host name of the outgoing smarthost smtp.gmail.com::587Keep number of DNS-queries minimal (Dial-on-Demand)? NoSplit configuration into small files? No -
Add a line like this to
/etc/exim4/passwd.client*.google.com:yourAccount@gmail.com:yourPasswordReplace
yourAccount@gmail.comandyourPasswordwith your details. If you have 2FA/MFA enabled on your Gmail then you'll need to create and use an app password. -
This file has your Gmail password so we need to lock it down:
sudo chown root:Debian-exim /etc/exim4/passwd.client sudo chmod 640 /etc/exim4/passwd.client -
Restart
exim4:sudo service exim4 restart -
Add some mail aliases so we can send e-mails to local accounts by adding lines like this to
/etc/aliases:user1: user1@gmail.com user2: user2@gmail.com ...You'll need to add all the local accounts that exist on your server.
Lynis - Linux Security Auditing
Why
From https://cisofy.com/lynis/:
Lynis is a battle-tested security tool for systems running Linux, macOS, or Unix-based operating system. It performs an extensive health scan of your systems to support system hardening and compliance testing.
Goals
- Lynis installed
Notes
- We will install it from it's GitHub page so we have the latest and greatest.
References
Steps
-
We want it to be installed system wide so go to
/usr/localand clone it from https://github.com/CISOfy/lynis:cd /usr/local sudo git clone https://github.com/CISOfy/lynis -
Update it:
sudo /usr/local/lynis/lynis update info -
Run a security audit:
sudo /usr/local/lynis/lynis audit systemThis will scan your server, report its audit findings, and at the end it will give you suggestions. Spend some time going through the output and address gaps as necessary.
Miscellaneous
Contacting Me
For any questions, comments, concerns, feedback, or issues, submit a new issue.
To Do / To Add
- Custom Jails for Fail2ban
- Linux Kernel
sysctlHardening - Security-Enhanced Linux / SELinux
- full disk encryption
- BIOS password
- Anti-Virus
- use ed25519 keys instead of RSA for SSH public/private keys
Additional References
- https://github.com/pratiktri/server_init_harden - Bash script that automates few of the tasks that you need to perform on a new Linux server to give it basic amount security.
Disclaimer / Warranty
This guide comes with ABSOLUTELY NO WARRANTY. Use with caution.