How To Secure A Linux Server
An evolving how-to guide for securing a Linux server that, hopefully, also teaches you a little about security and why it matters.
Table of Contents
- Introduction
- Guide Overview
- Before You Start
- The SSH Server
- The Basics
- The Network
- The Auditing
- File/Folder Integrity Monitoring With AIDE (WIP)
- Anti-Virus Scanning With ClamAV (WIP)
- Rootkit Detection With Rkhunter (WIP)
- Rootkit Detection With chrootkit (WIP)
- logwatch - system log analyzer and reporter
- ss - Seeing Ports Your Server Is Listening On
- Lynis - Linux Security Auditing
- OSSEC - Host Intrusion Detection
- The Danger Zone
- The Miscellaneous
- Left Over
(TOC made with nGitHubTOC)
Introduction
Guide Objective
This guides purpose is to teach you how to secure a Linux server.
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.
Ansible playbooks of this guide are available at How To Secure A Linux Server With Ansible by moltenbit.
Why Secure Your Server
I assume you're using this guide because you, hopefully, already understand why good security is important. That is a heavy topic onto itself and breaking it down is out-of-scope for this guide. If you don't know the answer to that question, I advise you research it first.
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 your data, or to use your server as another node for their large-scale DDOS attacks.
What's worse is, without good security, you may never know if your server has been compromised. A bad-actor may have gained unauthorized access to your server and copied your data without changing anything, so you'd never know. Or your server may have been part of a DDOS attack, and you wouldn't know. Look at many of the large scale data breaches in the news -- the companies often did not discover the data leak or intrusion until long after the bad-actors were gone.
Contrary to popular belief, bad-actors don't always want to change something or lock you out of your data for money. Sometimes they just want the data on your server for their data warehouses (there is big money in big data) or to covertly use your server for their nefarious purposes.
Why Yet Another Guide
This guide may appear duplicative/unnecessary because there are countless articles online that tell you 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.
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.
Other Guides
There are many guides provided by experts, industry leaders, and the distributions themselves. It is not practical, and sometimes against copyright, to include everything from those guides. I recommend you check them out before starting with this guide.
- The Center for Internet Security (CIS) provides benchmarks that are exhaustive, industry trusted, step-by-step instructions for securing many flavors of Linux. Check their About Us page for details. My recommendation is to go through this guide (the one you're reading here) first and THEN CIS's guide. That way their recommendations will trump anything in this guide.
- For distribution specific hardening/security guides, check your distributions documentation.
- https://security.utexas.edu/os-hardening-checklist/linux-7 - Red Hat Enterprise Linux 7 Hardening Checklist
- https://cloudpro.zone/index.php/2018/01/18/debian-9-3-server-setup-guide-part-1/ - # Debian 9.3 server setup guide
- https://blog.vigilcode.com/2011/04/ubuntu-server-initial-security-quick-secure-setup-part-i/ - Ubuntu Server Initial Security guide
- https://www.tldp.org/LDP/sag/html/index.html
- https://seifried.org/lasg/
- https://news.ycombinator.com/item?id=19178964
- https://wiki.archlinux.org/index.php/Security - many folks have also recommended this one
- https://securecompliance.co/linux-server-hardening-checklist/
To Do / To Add
- Custom Jails for Fail2ban
- MAC (Mandatory Access Control) and Linux Security Modules (LSMs)
- https://wiki.archlinux.org/index.php/security#Mandatory_access_control
- Security-Enhanced Linux / SELinux
- AppArmor
- disk encryption
- Rkhunter and chrootkit
- shipping/backing up logs - https://news.ycombinator.com/item?id=19178681
- CIS-CAT - https://learn.cisecurity.org/cis-cat-landing-page
- debsums - https://blog.sleeplessbeastie.eu/2015/03/02/how-to-verify-installed-packages/
Guide Overview
About This Guide
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, how to install Linux, or how to use it. Check https://linuxjourney.com/ if you're new to Linux.
- ...is meant to be Linux distribution agnostic.
- ...does not teach you everything you need to know about security nor does it get into all aspects of system/server security. For example, physical security 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 -- enough to whet your appetite and make you hungry enough to want to go and learn more.
- ...aims to make it easy by providing code you can copy-and-paste. You might need to modify the commands before you paste so keep your favorite text editor handy.
- ...is organized in an order that makes logical sense to me -- i.e. securing SSH before installing a firewall. As such, this guide is intended to be followed in the order it is presented, but it is not necessary to do so. Just be careful if you do things in a different order -- some sections require previous sections to be completed.
My Use-Case
There are many types of servers and different use-cases. While I want this guide to be as generic as possible, there will be some things that may not apply to all/other use-cases. Use your best judgement when going through this guide.
To help put context to many of the topics covered in this guide, my use-case/configuration is:
- A desktop class computer...
- With a single NIC...
- Connected to a consumer grade router...
- Getting a dynamic WAN IP provided by the ISP...
- With WAN+LAN on IPV4...
- And LAN using NAT...
- That I want to be able to SSH to remotely from unknown computers and unknown locations (i.e. a friend's house).
Editing Configuration Files - For The Lazy
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.
Contributing
I wanted to put this guide 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.
Before You Start
Identify Your Principles
Before you start you will want to identify what your Principles are. What is your threat model? Some things to think about:
- Why do you want to secure your server?
- How much security do you want or not want?
- How much convenience are you willing to compromise for security and vice-versa?
- What are the threats you want to protect against? What are the specifics to your situation? For example:
- Is physical access to your server/network a possible attack vector?
- Will you be opening ports on your router so you can access your server from outside your home?
- Will you be hosting a file share on your server that will be mounted on a desktop class machine? What is the possibility of the desktop machine getting infected and, in turn, infecting the server?
- Do you have a means of recovering if your security implementation locks you out of your own server? For example, you disabled root login or password protected GRUB.
These are just a few things to think about. Before you start securing your server you will want to understand what you're trying to protect against and why so you know what you need to do.
Picking A Linux Distribution
This guide is intended to be distribution agnostic so users can use any distribution they want. With that said, there are a few things to keep in mind:
You want a distribution that...
- ...is stable. Unless you like debugging issues at 2 AM, you don't want an unattended upgrade, or a manual package/system update, to render your server inoperable. But this also means you're okay with not running the latest, greatest, bleeding edge software.
- ...stays up-to-date with security patches. You can secure everything on your server, but if the core OS or applications you're running have known vulnerabilities, you'll never be safe.
- ...you're familiar with. If you don't know Linux, I would advise you play around with one before you try to secure it. You should be comfortable with it and know your way around, like how to install software, where configuration files are, etc...
- ...is well-supported. Even the most seasoned admin needs help every now and then. Having a place to go for help will save your sanity.
Installing Linux
Installing Linux is out-of-scope for this guide because each distribution does it differently and the installation instructions are usually well documented. 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
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. Also, tick the Disk Encryption option.
Pre/Post Installation Requirements
- 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.
- Unless you're doing everything physically connected to your server, you'll need remote access so be sure SSH works.
- Keep your system up-to-date (i.e.
sudo apt update && sudo apt upgradeon Debian based systems). - Make sure you perform any tasks specific to your setup like:
- Configuring network
- Configuring mount points in
/etc/fstab - Creating the initial user accounts
- Installing core software you'll want like
man - 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 Gmail and Exim4 As MTA With Implicit TLS.
- I would also recommend you read through the CIS Benchmarks before you start with this guide just to digest/understand what they have to say. My recommendation is to go through this guide (the one you're reading here) first and THEN CIS's guide. That way their recommendations will trump anything in this guide.
Other Important Notes
- This guide is being written and tested on Debian. Most things below should work on other distributions. If you find something that does not, please contact me. The main thing that separates each distribution will be its package management system. Since I use Debian, I will provide the appropriate
aptcommands that should work on all Debian based distributions. If someone is willing to provide the respective commands for other distributions, I will add them. - File paths and settings also may differ slightly -- check with your distribution's documentation if you have issues.
- Read the whole guide before you start. Your use-case and/or principals may call for not doing something or for changing the order.
- 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.
Using Ansible playbooks to secure your Linux Server
Ansible playbooks of this guide are available at How To Secure A Linux Server With Ansible.
Make sure to edit the variables according to your needs and read all tasks beforehand to confirm it does not break your system. After running the playbooks ensure that all settings are configured to your needs!
- Install Ansible
- git clone How To Secure A Linux Server With Ansible
- Create SSH-Public/Private-Keys
ssh-keygen -t ed25519
- Change all variables in group_vars/variables.yml according to your needs.
- Enable SSH root access before running the playbooks:
nano /etc/ssh/sshd_config
[...]
PermitRootLogin yes
[...]
- Recommended: configure static IP address on your system.
- Add your systems IP address to hosts.yml.
Run the requirements playbook using the root password you specified while installing the server:
ansible-playbook --inventory hosts.yml --ask-pass requirements-playbook.yml
Run the main playbook with the new users password you specified in the variables.yml file:
ansible-playbook --inventory hosts.yml --ask-pass main-playbook.yml
If you need to run the playbooks multiple times remember to use the SSH key and the new SSH port:
ansible-playbook --inventory hosts.yml -e ansible_ssh_port=SSH_PORT --key-file /PATH/TO/SSH/KEY main-playbook.yml
The SSH Server
Important Note Before You Make SSH Changes
It is highly advised you keep a 2nd terminal open to your server before you make and apply SSH configuration changes. This way if you lock yourself out of your 1st terminal session, you still have one session connected so you can fix it.
Thank you to Sonnenbrand for this idea.
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.
How It Works
Check the references below for more details but, at a high level, public/private keys work by using a pair of keys to verify identity.
- 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. You want to keep both keys secure, especially the private key. Even though the public key is meant to be public, it is wise to make sure neither keys fall in the wrong hands.
When you connect to an SSH server, SSH will look for a public key that matches the client you're connecting from in the file ~/.ssh/authorized_keys on the server you're connecting to. Notice the file is in the home folder of the ID you're trying to connect to. So, after creating the public key, you need to append it to ~/.ssh/authorized_keys. One approach is to copy it to a USB stick and physically transfer it to the server. Another approach is to use ssh-copy-id to transfer and append the public key.
After the keys have been created and the public key has been appended to ~/.ssh/authorized_keys on the host, SSH uses the public and private keys to verify identity and then establish a secure connection. How identity is verified is a complicated process but Digital Ocean has a very nice write-up of how it works. At a high level, identity is verified by the server encrypting a challenge message with the public key, then sending it to the client. If the client cannot decrypt the challenge message with the private key, the identity can't be verified and a connection will not be established.
They are considered more secure because you need the private key to establish an SSH connection. If you set PasswordAuthentication no in /etc/ssh/sshd_config, then SSH won't let you connect without the private key.
You can also set a pass-phrase for the keys which would require you to enter the key pass-phrase when connecting using public/private keys. Keep in mind doing this means you can't use the key for automation because you'll have no way to send the passphrase in your scripts. ssh-agent is a program that is shipped in many Linux distros (and usually already running) that will allow you to hold your unencrypted private key in memory for a configurable duration. Simply run ssh-add and it will prompt you for your passphrase. You will not be prompted for your passphrase again until the configurable duration has passed.
We will be using Ed25519 keys which, according to https://linux-audit.com/:
It is using an elliptic curve signature scheme, which offers better security than ECDSA and DSA. At the same time, it also has good performance.
Goals
- Ed25519 public/private SSH keys:
- private key on your client
- public key on your server
Notes
- You'll need to do this step for every computer and account you'll be connecting to your server from/as.
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/
- https://www.digitalocean.com/community/tutorials/understanding-the-ssh-encryption-and-connection-process
- https://wiki.archlinux.org/index.php/SSH_Keys
- https://www.ssh.com/ssh/copy-id
man ssh-keygenman ssh-copy-idman ssh-add
Steps
-
From the computer you're going to use to connect to your server, the client, not the server itself, create an Ed25519 key with
ssh-keygen:ssh-keygen -t ed25519
Generating public/private ed25519 key pair. Enter file in which to save the key (/home/user/.ssh/id_ed25519): Created directory '/home/user/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/user/.ssh/id_ed25519. Your public key has been saved in /home/user/.ssh/id_ed25519.pub. The key fingerprint is: SHA256:F44D4dr2zoHqgj0i2iVIHQ32uk/Lx4P+raayEAQjlcs user@client The key's randomart image is: +--[ED25519 256]--+ |xxxx x | |o.o +. . | | o o oo . | |. E oo . o . | | o o. o S o | |... .. o o | |.+....+ o | |+.=++o.B.. | |+..=**=o=. | +----[SHA256]-----+Note: If you set a passphrase, you'll need to enter it every time you connect to your server using this key, unless you're using
ssh-agent. -
Now you need to append the public key
~/.ssh/id_ed25519.pubfrom your client to the~/.ssh/authorized_keysfile on your server. Since we're presumable still at home on the LAN, we're probably safe from MIM attacks, so we will usessh-copy-idto transfer and append the public key:ssh-copy-id user@server
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/user/.ssh/id_ed25519.pub" The authenticity of host 'host (192.168.1.96)' can't be established. ECDSA key fingerprint is SHA256:QaDQb/X0XyVlogh87sDXE7MR8YIK7ko4wS5hXjRySJE. Are you sure you want to continue connecting (yes/no)? yes /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 user@host's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh 'user@host'" and check to make sure that only the key(s) you wanted were added.
Now would be a good time to perform any tasks specific to your setup.
Create SSH Group For AllowGroups
Why
To make it easy to control who can SSH to the server. By using a group, we can quickly add/remove accounts to the group to quickly allow or not allow SSH access to the server.
How It Works
We will use the AllowGroups option in SSH's configuration file /etc/ssh/sshd_config to tell the SSH server to only allow users to SSH in if they are a member of a certain UNIX group. Anyone not in the group will not be able to SSH in.
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 prerequisite 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.
How It Works
/etc/ssh/sshd_config is the default configuration file that the SSH server uses. We will use this file to tell what options the SSH server should use.
Goals
- a secure SSH configuration
Notes
- Make sure you've completed Create SSH Group For AllowGroups first.
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/ (broken; try http://web.archive.org/web/20200413100933/https://www.techbrown.com/harden-ssh-secure-linux-vps-server/)
- https://serverfault.com/questions/660160/openssh-difference-between-internal-sftp-and-sftp-server/660325
man sshd_config- Thanks to than0s for how to find duplicate settings.
Steps
-
Make a backup of OpenSSH server's configuration file
/etc/ssh/sshd_configand remove comments to make it easier to read:sudo cp --archive /etc/ssh/sshd_config /etc/ssh/sshd_config-COPY-$(date +"%Y%m%d%H%M%S") sudo sed -i -r -e '/^#|^$/ d' /etc/ssh/sshd_config
-
Edit
/etc/ssh/sshd_configthen find and edit or add these settings that should be applied regardless of your configuration/setup:Note: SSH does not like duplicate contradicting settings. For example, if you have
KbdInteractiveAuthentication noand thenKbdInteractiveAuthentication yes, SSH will respect the first one and ignore the second. Your/etc/ssh/sshd_configfile may already have some of the settings/lines below. To avoid issues you will need to manually go through your/etc/ssh/sshd_configfile and address any duplicate contradicting settings.Note: If you are running OpenSSH 9.1 or later, uncomment the
RequiredRSASize 3072line in the configuration below. This enforces a minimum RSA key size of 3072 bits and will reject smaller RSA keys during authentication. This only affects RSA keys. If you use ED25519 or ECDSA keys, you are not affected. You can check your key type and size withssh-keygen -l -f ~/.ssh/id_rsa. On older OpenSSH versions, leave the line commented out as it will prevent sshd from starting.######################################################################################################## # 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,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 # Use kernel sandbox mechanisms where possible in unprivileged processes # Systrace on OpenBSD, Seccomp on Linux, seatbelt on MacOSX/Darwin, rlimit elsewhere. # Note: This setting is deprecated in OpenSSH 7.5 (https://www.openssh.com/txt/release-7.5) # UsePrivilegeSeparation sandbox ######################################################################################################## # end settings from https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67 as of 2019-01-01 ######################################################################################################## # don't let users set environment variables PermitUserEnvironment no # Log sftp level file access (read/write/etc.) that would not be easily logged otherwise. Subsystem sftp internal-sftp -f AUTHPRIV -l INFO # 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 yes Compression no # TCP keepalive is spoofable (runs outside the encrypted channel) # Use ClientAlive instead (runs inside the encrypted channel) TCPKeepAlive no AllowAgentForwarding no PermitRootLogin no # don't allow .rhosts or /etc/hosts.equiv HostbasedAuthentication no # OpenSSH 9.1 and later # Enforce a minimum RSA key size of 3072 bits # https://www.keylength.com/en/compare/ # RequiredRSASize 3072 -
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 3maximum number of client alive messages sent without response ClientAliveInterval number of seconds ClientAliveInterval 15timeout 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 onSee Issue #1 for important details. LoginGraceTime 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 or start:rate:fullMaxStartups 10:30:60maximum number of unauthenticated SSH connections PasswordAuthentication yesornoPasswordAuthentication noif login with a password is allowed Port any open/available port number Port 22port that sshdshould listen onCheck
man sshd_configfor more details what these settings mean. -
Make sure there are no duplicate settings that contradict each other. The below command should not have any output.
awk 'NF && $1!~/^(#|HostKey)/{print $1}' /etc/ssh/sshd_config | sort | uniq -c | grep -v ' 1 '
-
Validate the OpenSSH server configuration before restarting:
sudo sshd -t
-
Restart ssh:
sudo service ssh restart
-
You can check verify the configurations worked with
sshd -Tand verify the output:sudo sshd -T
port 22 addressfamily any listenaddress [::]:22 listenaddress 0.0.0.0:22 usepam yes logingracetime 30 x11displayoffset 10 maxauthtries 2 maxsessions 2 clientaliveinterval 15 clientalivecountmax 3 streamlocalbindmask 0177 permitrootlogin no ignorerhosts yes ignoreuserknownhosts no hostbasedauthentication no ... subsystem sftp internal-sftp -f AUTHPRIV -l INFO maxstartups 2:30:2 permittunnel no ipqos lowdelay throughput rekeylimit 0 0 permitopen any
Remove Short Diffie-Hellman Keys
Why
Per Mozilla's OpenSSH guidelines for OpenSSH 6.7+, "all Diffie-Hellman moduli in use should be at least 3072-bit-long".
The Diffie-Hellman algorithm is used by SSH to establish a secure connection. The larger the moduli (key size) the stronger the encryption.
Goals
- remove all Diffie-Hellman keys that are less than 3072 bits long
References
- Mozilla's OpenSSH guidelines for OpenSSH 6.7+ at https://infosec.mozilla.org/guidelines/openssh#modern-openssh-67
- https://infosec.mozilla.org/guidelines/key_management
man moduli
Steps
-
Make a backup of SSH's moduli file
/etc/ssh/moduli:sudo cp --archive /etc/ssh/moduli /etc/ssh/moduli-COPY-$(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
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. Requiring two factors adds an extra layer of security.
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, access to your system is dependent on the accompanying authenticator app that generates the code.
How It Works
On Linux, PAM is responsible for authentication. There are four tasks to PAM that you can read about at https://en.wikipedia.org/wiki/Linux_PAM. This section talks about the authentication task.
When you log into a server, be it directly from the console or via SSH, the door you came through will send the request to the authentication task of PAM and PAM will ask for and verify your password. You can customize the rules each doors use. For example, you could have one set of rules when logging in directly from the console and another set of rules for when logging in via SSH.
This section will alter the authentication rules for when logging in via SSH to require both a password and a 6 digit code.
We will use Google's libpam-google-authenticator PAM module to create and verify a TOTP key. https://fastmail.blog/2016/07/22/how-totp-authenticator-apps-work/ and https://jemurai.com/2018/10/11/how-it-works-totp-based-mfa/ have very good writeups of how TOTP works.
What we will do is tell the server's SSH PAM configuration to ask the user for their password and then their numeric token. PAM will then verify the user's password and, if it is correct, then it will route the authentication request to libpam-google-authenticator which will ask for and verify your 6 digit token. If, and only if, everything is good will the authentication succeed and user be allowed to log in.
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 if they are using SSH public/private keys. If you want public key authentication to also require a TOTP code, configure
AuthenticationMethodsto requirekeyboard-interactiveafterpublickey. - The
nullokoption lets users without a~/.google_authenticatorfile log in without a code. Removenullokafter all intended SSH users are enrolled if MFA must be mandatory for every account.
References
- https://github.com/google/google-authenticator-libpam
- https://en.wikipedia.org/wiki/Linux_PAM
- https://en.wikipedia.org/wiki/Time-based_One-time_Password_algorithm
- https://fastmail.blog/2016/07/22/how-totp-authenticator-apps-work/
- https://jemurai.com/2018/10/11/how-it-works-totp-based-mfa/
Steps
-
Install it libpam-google-authenticator.
On 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-authenticatorto create the necessary token data:google-authenticator
Do you want authentication tokens to be time-based (y/n) y https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/user@host%3Fsecret%3DR4ZWX34FQKZROVX7AGLJ64684Y%26issuer%3Dhost ... Your new secret key is: R3NVX3FFQKZROVX7AGLJUGGESY Your verification code is 751419 Your emergency scratch codes are: 12345678 90123456 78901234 56789012 34567890 Do you want me to update your "/home/user/.google_authenticator" file (y/n) y Do you want to disallow multiple uses of the same authentication token? This restricts you to one login about every 30s, but it increases your chances to notice or even prevent man-in-the-middle attacks (y/n) Do you want to disallow multiple uses of the same authentication token? This restricts you to one login about every 30s, but it increases your chances to notice or even prevent man-in-the-middle attacks (y/n) y By default, tokens are good for 30 seconds. In order to compensate for possible time-skew between the client and the server, we allow an extra token before and after the current time. If you experience problems with poor time synchronization, you can increase the window from its default size of +-1min (window size of 3) to about +-4min (window size of 17 acceptable tokens). Do you want to do so? (y/n) y If the computer that you are logging into isn't hardened against brute-force login attempts, you can enable rate-limiting for the authentication module. By default, this limits attackers to no more than 3 login attempts every 30s. Do you want to enable rate-limiting (y/n) yNotice 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.
-
Make a backup of PAM's SSH configuration file
/etc/pam.d/sshd:sudo cp --archive /etc/pam.d/sshd /etc/pam.d/sshd-COPY-$(date +"%Y%m%d%H%M%S") -
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 nullokNote: Check here for what
nullokmeans.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
-
Tell SSH to leverage it by adding or editing this line in
/etc/ssh/sshd_config:KbdInteractiveAuthentication yessudo sed -i -r -e "s/^(kbdinteractiveauthentication|challengeresponseauthentication)( .*)$/# \1\2 # commented by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")/I" /etc/ssh/sshd_config echo -e "\nKbdInteractiveAuthentication yes # added by $(whoami) on $(date +"%Y-%m-%d @ %H:%M:%S")" | sudo tee -a /etc/ssh/sshd_config
-
Validate the OpenSSH server configuration before restarting:
sudo sshd -t
-
Restart ssh:
sudo service ssh restart
The Basics
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
- sudo privileges limited to those who are in a group we specify
Notes
- Your installation may have already done this, or may already have a special group intended for this purpose so check first.
-
Debian creates the sudo group. To view users that are part of this group (thus have sudo privileges):
cat /etc/group | grep "sudo" -
RedHat creates the wheel group
-
- See #39 for a note on some distributions making it so
sudodoes not require a password. Thanks to sbrl for sharing.
Steps
-
Create a group:
sudo groupadd sudousers
-
Add account(s) to the group:
sudo usermod -a -G sudousers user1 sudo usermod -a -G sudousers user2 sudo usermod -a -G sudousers ...
You'll need to do this for every account on your server that needs sudo privileges.
-
Make a backup of the sudo's configuration file
/etc/sudoers:sudo cp --archive /etc/sudoers /etc/sudoers-COPY-$(date +"%Y%m%d%H%M%S") -
Edit sudo's configuration file
/etc/sudoers:sudo visudo
-
Tell sudo to only allow users in the
sudousersgroup to use sudo by adding this line if it is not already there:%sudousers ALL=(ALL:ALL) ALL
Limit Who Can Use su
Why
su also lets accounts run commands as other accounts, including root. We want to make sure that only the accounts we want can use su.
Goals
- su privileges limited to those who are in a group we specify
References
Steps
-
Create a group:
sudo groupadd suusers
-
Add account(s) to the group:
sudo usermod -a -G suusers user1 sudo usermod -a -G suusers user2 sudo usermod -a -G suusers ...
You'll need to do this for every account on your server that needs sudo privileges.
-
Make it so only users in this group can execute
/bin/su:sudo dpkg-statoverride --update --add root suusers 4750 /bin/su
Run applications in a sandbox with FireJail
Why
It's absolutely better, for many applications, to run in a sandbox.
Browsers (even more the Closed Source ones) and eMail Clients are highly suggested.
Goals
- confine applications in a jail (few safe directories) and block access to the rest of the system
References
- Thanks to FireJail
Steps
-
Install the software:
sudo apt install firejail firejail-profiles
Note: for Debian 10 Stable, official Backport is suggested:
sudo apt install -t buster-backports firejail firejail-profiles
-
Allow an application (installed in
/usr/binor/bin) to run only in a sandbox (see few examples below here):sudo ln -s /usr/bin/firejail /usr/local/bin/google-chrome-stable sudo ln -s /usr/bin/firejail /usr/local/bin/firefox sudo ln -s /usr/bin/firejail /usr/local/bin/chromium sudo ln -s /usr/bin/firejail /usr/local/bin/evolution sudo ln -s /usr/bin/firejail /usr/local/bin/thunderbird
-
Run the application as usual (via terminal or launcher) and check if it's running in a jail:
firejail --list
-
Allow a sandboxed app to run again as it was before (example: firefox)
sudo rm /usr/local/bin/firefox
NTP Client
Why
Many security protocols leverage the time. If your system time is incorrect, it could have negative impacts to your server. An NTP client can solve that problem by keeping your system time in-sync with global NTP servers
How It Works
NTP stands for Network Time Protocol. In the context of this guide, an NTP client on the server is used to update the server time with the official time pulled from official servers. Check https://www.pool.ntp.org/en/ for all of the public NTP servers.
Note: Starting with Debian 13 (Trixie), the classic
ntppackage has been removed. Runningsudo apt install ntpwill fail with "Package ntp has no installation candidate". Since this guide only uses NTP as a client (to sync the server's clock), the recommended approach on Debian 13+ is to usesystemd-timesyncd, which is already pre-installed and requires no additional packages. See the Debian 13+ steps below.
Go
(README truncated)
