Server hardening doesn't have to be a series of arcane complex commands.
These days, it's more important than ever to tighten up the security on your servers, yet if you were to look at several official hardening guides, they read as though they were written for Red Hat from 2005. That's because they were written for Red Hat in 2005 and updated here and there through the years. I came across one of these guides when I was referring to some official hardening benchmarks for a PCI audit and realized if others new to Linux server administration were to run across the same guide, they likely would be overwhelmed with all of the obscure steps. Worse though, they likely would spend hours performing obscure sysctl tweaks and end up with a computer that was no more protected against a modern attack. Instead, they could have spent a few minutes performing a few simple hardening steps and ended up with a more secure computer at the end. So in this article, I describe a few hardening steps that provide the most bang for the buck. These tips should take only a few minutes, yet for that effort, you should get a much more secure system at the end.
Before I talk about some hardening recommendations, I figured I'd start by highlighting some of those classic security steps you are likely to see in those older hardening guides. Now this isn't to say that all of these steps are necessarily bad advice, it's just that in many cases the advice refers to deprecated systems or describes steps that modern Linux server distributions have taken by default for years.
For instance, many hardening guides spend a lot of time focusing on tcpwrappers, a classic Linux service that lets you restrict which IPs can access particular services. These days, most administrators use iptables firewall rules to restrict access to ports instead. You also will be advised to enable the use of shadow passwords and to disable shells on common role accounts (like the mail, bind, www and mysql users). Although that isn't bad advice, the fact is that all Linux distributions already do this for you out of the box.
Another tip you usually will see in a hardening guide is to disable all unnecessary services, and in particular, the guides will tell you to disable telnet, daytime, chargen and a number of other obscure inetd services that not only haven't been turned on by default in a long time, but in many cases they also aren't even installed by default anymore. The fact is that most server distributions ship with all network services apart from SSH turned off. Speaking of SSH, now that I've talked a bit about some classic hardening tips, let me discuss a few modern hardening tips starting with SSH.
As I mentioned, just about every server you will encounter turns on SSH by default, and there is an assumption that you will use it for remote administration. Here are a few simple changes you can make to your /etc/ssh/sshd_config file that take only a second but make it more secure.
First, disable root logins and make sure that you use only SSH protocol 2 (previous protocols have known vulnerabilities). In many distributions (in particular many cloud images), these steps already may be done for you:
PermitRootLogin no Protocol 2
A lot of people focus way too much, in my opinion, on SSH brute-force attacks when they talk about server hardening. It's true that if you put a Linux server on the internet, one of the first things you will see in your logs is a steady stream of SSH brute-force attempts. Many sysadmins go to lengths that I think fall somewhere between ineffective, absurd and overkill, including moving SSH to some random port (security by obscurity) or using a system like fail2ban. With fail2ban, your system reads failed login attempts and creates firewall rules to block attackers after a few failed attempts. This seems sensible on the surface, but it has a few problems:
This stops only attackers who have one machine—most have botnets and spread brute-force attacks across many IPs.
If you have a weak, easily guessable password and a common user name, they might guess the password before fail2ban kicks in.
It's risky to let attackers perform an action that automatically updates your system's firewall rules.
Usually internal networks are whitelisted—attackers still can brute-force attack you from a different compromised machine on your network.
Instead of going through all of those steps to mitigate SSH brute-force attacks, I recommend that you eliminate the attack entirely: disable password authentication and rely on SSH keys only. Before you enable this option, be sure that everyone who logs in to this machine (or at least the administrators) have generated and tested logging in using SSH keys—you wouldn't want to get locked out. When you are ready, change the PasswordAuthentication parameter in your sshd_config to:
PasswordAuthentication no
The final quick SSH hardening step is to restrict which cryptography cipher suites and algorithms to use, so that you use only the ones that are considered to be safe by today's standards. I'm no cryptographer, but I don't have to be one to look at the recommendations from cryptographers and copy and paste them into my SSH config:
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com, aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr KexAlgorithms curve25519-sha256@libssh.org, ↪diffie-hellman-group-exchange-sha256 MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com, hmac-ripemd160-etm@openssh.com,umac-128-etm@openssh.com, ↪hmac-sha2-512, hmac-sha2-256,hmac-ripemd160,umac-128@openssh.com
Once all of these settings are in place, restart the SSH service to use them.
For general hardening of the system accounts, the best recommendation I can make is to disable the root account altogether and use only sudo. You also should avoid direct login to any shared accounts, whether it's the root account or some role account like a user that manages your application or web server. By requiring users to log in as themselves and then sudo up to root or role accounts, you provide a nice audit trail for who did what, and you make revoking access simpler when users no longer need an account—since the shared accounts won't have a password, you don't have to change them every time a member of the team leaves; instead, you can just remove that user's account.
Most distributions currently include sudo, and some also either disable the root account by default or allow you to disable it during installation. Otherwise, you simply can edit your /etc/shadow file and replace whatever password you have in place for the root user with a * symbol. Just make sure you do have sudo working first with at least one account so you don't lock yourself out.
When using sudo there are a few practices you should follow to help keep it secure. First, while the use of NOPASSWD sudo rules (rules that don't require you to enter a password) are somewhat unavoidable for dæmons that may run cron jobs like backup jobs, you should restrict any NOPASSWD sudo rules to just those dæmon role accounts and require all real users to type in a password. As much as possible, you also should follow the principle of least privilege and grant users sudo access only to the specific commands they need instead of granting them access to run all commands as a particular user (especially the root user). Finally, if you find yourself granting users access to a general-purpose command to do something specific (like granting them access to service or systemctl so they can restart just one service), consider creating a simple shell script that runs the command with only the specific parameters you want and granting them sudo access to that script instead.
Although these hardening steps aren't the only things you should do to lock down your server, they are a good start and should take only a few minutes. In my next article, I'll add another round of simple hardening tips, including SSH client hardening and cloud hardening steps, and I'll finish up with some general-purpose recommendations.