Ubuntu Server Hardening Guide: Quick and Secure
Ubuntu Server Hardening Guide
The system hardening process of a server is critical during and after installation. It helps the system to perform its duties properly and stay secured as much as possible. This blog post about Ubuntu system hardening will look into the most critical steps to take first. More detailed system hardening steps can be added on top of these, for which we will share some tools and guides at the end.
As most security guides only tell you what to do, we will also go into more detail on why a specific measure is important. This way you can make educated decisions on what steps you want to do, or the ones to skip. After all, each system is different.
Hardening Steps (Installation)
The first few hardening improvements can be done during the installation. If you already have a system running, the most likely these steps can’t be easily applied after the fact. Consider reinstalling the system, or use the hardening measures during future installations.
Use strong passwords
After the first installation steps, the creation of a user account is performed. This user will be added to the administrative group, allowing him or her to become root. For this reason, the password should be a strong password.
Why a strong password matters: weak passwords are still found on systems, both during development and in production. This is a serious risk as automated tools can perform many guesses per second, often discover weak passwords in just a few seconds. So system hardening should also apply to the strength of your passwords.
How to enhance your password: use longer passwords to make brute force password guessing much harder. One trick that is simple yet powerful, is adding a single character many times to your password (e.g. add 10 dollar signs at the beginning). Besides the length, the variety of used characters is important. Add capitals, numbers, and other characters.
Use disk encryption
Enable encrypted LVM volumes during the installation of your Ubuntu server. It is a great measure to hardening the system and data in particular. Although it won’t protect against all attacks, it matters for “data at rest”.
Selected the guided partition method with “use entire disk and set up encrypted LVM”.
Next step is selecting a passphrase. This is used during the boot process, to unlock the disk (or volume).
Why disk encryption matters: Your system may be stolen, even if it is a server. Another possibility is that you have to return a broken disk. In both cases, others should not be able to read data stored on the disk.
Automatic security updates
Every server needs software packages to fulfill its destiny during the lifetime of the system. Ensure that it gets regularly patched and updated by using unattended-upgrades. This is done with the “Install security updates automatically” option during the installation.
Why applying automatic security updates matters: almost daily new weaknesses are detected in software packages. This is no different for Ubuntu servers. Although most administrator rather not update their systems automatically, applying only the security updates is considered to be safe. This is because no new features are introduced, only security flaws are patched. After that is done, a new software update is released to solve the related vulnerability, often linked to a CVE number (Common Vulnerabilities and Exposures).
During the years Ubuntu server has been improved that it already applies the “lean” principle. Only install what is needed, then let the user select additional packages or software groups. There is the possibility to add new software groups at the end of the installation process. Only select the groups and services which are really needed. It is common to select the SSH server role, so OpenSSH is available.
Why a minimal installation matters: Ubuntu has the tendency to enable installed services and start them by default. This means that if you just install a package, it may actually already be running with weak configuration defaults. Security professionals speak often about a footprint or attack surface. This means that the risk of a breach increases if you have more packages you have installed, or services running, or old users enabled. In other words, each package, service, or user is increasing the chance that your security defenses are breached.
Hardening Steps (Usage)
After you have your system installed, it is time to configure the system. This is also the phase in which your security defenses can easily be weakened. So each time you perform activities on your servers, consider what it does for your overall security level of the server.
During the installation, there was the option to select automatic security updates. If you already had a system running, you can add this component easily by installing the unattended-upgrades package
apt install unattended-upgrades
Although this package works fairly well out of the box, you might want to check its configuration. This is because only packages from the security repository are updated. Others are skipped. So look for external repositories that may be available to the system and consider adding those packages to the configuration. The configuration file of unattended-upgrades is /etc/apt/apt.conf.d/50unattended-upgrades. For more details regarding the configuration, have a look at our more in-depth article about unattended-upgrades.
Besides security updates, we suggest to regularly plan a moment to install normal updates. Often they contain improvements to improve system stability. Especially on servers this is of high importance.
Earlier Ubuntu releases:
apt-get update && apt-get upgrade
Ubuntu 16.04 LTS and later:
apt update && apt upgrade
Besides the required software packages, systems can only work if it allows users to make use of it. In some cases, we will be giving them access to the server, especially for system administration purposes. Also for web servers it is common to see that users can access the system directly via SSH and SCP, to allow updating the website of the user.
Related risks to user accounts
There are a few risks with user accounts on systems, especially on servers. Hardening in this area is therefore required. The first risk is that local users may use local exploits to elevate their permissions and become root. Fortunately, this can only happen is there is actually a known weakness and when the user is skilled enough to run the related malicious script or code. Unfortunately, it is common to see Linux servers running for years, without a single reboot. Even when security updates are automatically installed, an update to the kernel still requires a system restart.
The second risk is that old accounts may be lingering on the server too long. Sometimes employees or customers that no longer for the company. When these accounts have a weak password, they might be abused one day. To counter this, set a password policy and delete accounts when they are no longer needed. This last one is a difficult one, as you may need a strict process to control who can access the system and a way to determine the user has no business on the related system anymore.
Configure PAM: pwquality
PAM is an abbreviation for pluggable authentication module. It extends the existing functionality of the authentication steps, allowing for a very fine-grained configuration. PAM is usually a little bit scary for those who are new to its configuration, as there is not a clear path it follows. Files are including each other and have sometimes cryptic names. Still, don’t be scared and test your changes first on a virtual system where you always have root access. Create an additional test user and log in with that, to help with testing.
The first step is to install the PAM component “pwquality”, short for password quality.
apt install libpam-pwquality
One of the things we learned earlier is that a longer password is more secure. This is because it usually takes more time to crack by automated tools. So if you want to increase the minimal password length for all users, we have to configure that in the PAM configuration.
Open the file /etc/pam.d/common-password in a text editor and search for the line that has the pam_pwquality.so reference in it. By default it only includes “retry=3”. This number refers to the retries a user has before PAM will show that the authentication has failed and disallow access.
As we want to increase the minimal password length, we add “minlen=10” just before the retry parameter.
password requisite pam_pwquality.so minlen=10 retry=3
Save the file and then switch to your test user in the other terminal. Now use the passwd command and try to use a short password like 123456. If things are properly configured, that should fail.
Next step is to add complexity rules to pwquality module. This can be done with the parameters: dcredit, ucredit, lcredit, and ocredit. See the man page for their details and again test your changes.
Besides this password length and complexity, we can also configure how often an user should change his or her password. This is done via /etc/login.defs with the options PASS_MIN_DAYS and PASS_MAX_DAYS. By default, the maximum days are set to 99999 days and might need to be tuned down. For more sensitive systems this number should be fairly low, like every 30 days.
Firewall installation and configuration
Now that we implemented a few measures, it is time to look at the network services. Even systems that are already filtered by a network-based firewall, might still benefit from a local firewall. The first reason is to protect against other systems in the local subnet. Let’s say you enabled SSH on all your servers and filtered SSH traffic on your network firewall. Other systems could still use the service internally. In case one system is breached, others might get breached as a result. So one option could be to allow SSH only from predefined systems, like your bastion hosts (a.k.a jump server or stepping stone).
Another reason to use iptables or other firewall solutions, is to block bad traffic. Sure, it is better if you can do this on a network level, but sometimes only the receiving system can make the decision what traffic is good or bad. Especially when traffic is encrypted, like HTTPS. The receiving server has a better idea on what is going and may decide to start blocking a particular client when it had too many invalid or malicious requests.
A basic iptables configuration could be looking something like this:
# Accept all incoming traffic on local interface
iptables -A INPUT -I lo -j ACCEPT
Next step is to allow traffic to our services:
# Allow traffic to SSH (to port 2222), SMTP (25), and our web server (80, 443)
iptables -A INPUT -p tcp -m tcp –dport 2222 -m state –state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -p tcp -m tcp –dport 25 -m state –state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -p tcp -m tcp –dport 80 -m state –state NEW,ESTABLISHED -j ACCEPT
iptables -A INPUT -p tcp -m tcp –dport 443 -m state –state NEW,ESTABLISHED -j ACCEPT
Finally drop all other traffic:
# Drop all traffic in input chain
iptables -A INPUT -j DROP
This simple configuration is just a start. It still allows outgoing traffic, which might need some filtering as well.
Using AppArmor security framework
Two common security frameworks are SELinux and AppArmor. The choice for which framework on systems running Debian and Ubuntu is easy. Only AppArmor is available. This is because only support for this framework is compiled into the Linux kernel.
If you really want to harden your Ubuntu systems, then AppArmor is a great addition. This framework defines what running processes can do, or access. Think of it like a prison guard that continuously monitors its prisoners, to ensure they only do activities that are allowed. The allowed activities are stored in policy files, together with the related processes.
To determine the current status of AppArmor, use the
AppArmor can run three different modes. The first of all is disabled. In this mode, AppArmor will simply ignore the policies and not restrict any process. In complain mode, AppArmor will perform monitoring, and only notify when a process is performing an unauthorized action. The most restricted mode is when AppArmor is enforcing. All unauthorized actions are blocked and logged.
To learn more about AppArmor, have a look at the AppArmor server guide.
Now that you implemented the basic Ubuntu server hardening measures, it is time for the next steps. These steps include:
- Implementing sudo
- Hardening of SSH
- Hardening of compilers and development tools
- Check for malware
- Web server hardening
- Detection of malicious traffic
- Install file integrity monitoring
- Configure backups
- Create AppArmor profiles for programs
- Perform an in-depth Linux security audit
We will be adding more links for these subjects with step-by-step instructions.
The web has a lot of resources available when it comes to system hardening, including for Ubuntu Linux. Our experience is that there are a lot of low-quality articles, with just some steps to apply and without any reasoning behind it. Avoid those, as they usually have bad examples that can even introduce weak security weaknesses!
Useful learning resources
Ubuntu security tools
If you like to learn what can be improved on your system, use the open source tool Lynis. It has hundreds of tests to detect possible weaknesses and shows room for improvement.
Do you like this guide? You can help by sharing it in your social network or share a comment.