Host Hardening
Overview
When maintaining systems, hardening refers to configuring it in such a way that it is as unlikely to contain vulnerabilities as possible. This term encompasses both technical details of setting up specific pieces of software and also general strategies for ensuring systems are as secure as possible.
General principles include:
- Least privilege: allow the smallest set of privileges required for each object, user, or group. If a user does not need access to something, don't give them access.
- Defense in depth: have redundant security measures in place so that a lapse in one can be covered by another.
- Minimize attack surface: Reduce the number of open ports, active services, exposed systems, underused systems, and applications. Fewer targets means fewer potential vulnerabilities
- Effective patching: systems should be kept up-to-date. Monthly updates are usually sufficient, but critical issues should be updated as soon as possible.
Of course one goal in hardening systems is to avoid being victim of a cyber attack. Depending on your organization, it may be mandated by law that you provide certain security configurations. For instance, the following all have such rules:
- PCI-DSS: For systems dealing with payment through cards.
- HIPAA: For systems dealing with storage of medical information
- FedRAMP: For systems that are part of the federal government
- FERPA: For systems storing educational information on students
Securing SSH
SSH is configured through the /etc/ssh/sshd_config. After
making changes to the file, the service must be reloaded or restarted.
Reloading is preferable since it won't kick off people (including perhaps
you) who are connected.
The current configuration can be printed out with the following command:
sudo sshd -T
The following configurations are generally recommended for SSH
PermitRootLogin no
PermitEmptyPasswords no
PasswordAuthentication no # if using keys
The software fail2ban is used to further secure SSH. It
monitors SSH login attempts and blocks users who have submitted an
incorrect password too many times. The number of incorrect passwords
and the amount of time they are blocked is configurable.
It's configured by copying the /etc/fail2ban/jail.conf file to
/etc/fail2ban/jail.local, and then editing the local configuration
file. The file includes configurations for not just SSH, but other services as
well. Make sure the service for fail2ban is enabled and running.
You can check what IPs have been banned with the command:
sudo fail2ban-client status sshd
Host Firewalls
Firewalls are divided into two categories: network and host. Network firewalls are installed as part of a local network (either built into routers or as dedicated devices) and protect all hosts on the network.
A host firewall is installed a particular host and filters packets just from that hosts incoming network traffic. This can provide defense in depth on that particular host.
There are multiple host firewall systems available for Linux. iptables is the traditional, low-level packet filtering framework which works with the kernel's network stack. It is detailed and relatively difficult to set up.
Two simpler front-ends for iptables have been developed:
- firewalld: developed by Red Hat and more widely used on Red Hat based systems.
- ufw: the "uncomplicated firewall", developed by Canonical and more widely used on Debian systems.
UFW can be installed with the ufw package and then managed
like any other service with systemctl. However, even when it's
running ufw needs to be turned off and on:
$ sudo systemctl status ufw
● ufw.service - Uncomplicated firewall
Loaded: loaded (/usr/lib/systemd/system/ufw.service; enabled; preset: enabled)
Active: active (exited) since Mon 2026-04-20 10:33:21 EDT; 1s ago
Invocation: 102818059e194412909cd484ae90c4c5
Docs: man:ufw(8)
Process: 606278 ExecStart=/usr/lib/ufw/ufw-init start quiet (code=exited, status=0/SUCCESS)
Main PID: 606278 (code=exited, status=0/SUCCESS)
Mem peak: 2M
CPU: 11ms
$ sudo ufw status
Status: inactive
$ sudo ufw enable
$ sudo ufw status
Status: active
By default UFW allows all outgoing connections and blocks all incoming
connections. We can explicitly allow services through allowing application
profiles. Available ones can be seen with the ufw app list
command, and turned on using a command such as:
sudo ufw allow "OpenSSH"
This will allow connections on port 22 for our SSH server, but keep blocking
other incoming connections. You could also do sudo ufw allow 22
to allow ports by name instead of application name.
We can also block specific IP addresses or blocks of addresses with ufw:
$ sudo ufw deny from 34.6.217.81 $ sudoe ufw deny from 34.6.217.0/24
Installing a host firewall which only allows traffic on ports you want to support provides good defense in depth.
Passwords
Passwords should be carefully managed, especially for users with sudo privileges. Some general principles are:
- Don't re-use passwords between systems
- Passwords should be of sufficient length
- Passwords should be rotated periodically, but not too much (around 6 months for an administrator)
Password policies can be enforced on Linux with the chage command.
We can get info on passwords by passing the -l flag:
$ sudo chage -l ifinlay Last password change : Feb 17, 2026 Password expires : never Password inactive : never Account expires : never Minimum number of days between password change : 0 Maximum number of days between password change : 99999 Number of days of warning before password expires : 7
It also allows all of these fields to be modified by passing different
flags, on a per-user basis. This can be done to enforce password rules
on users, ensuring their passwords are changed regularly. For example,
to make sure the user susan4 changes her password every
90 days, we could use the following:
$ sudo chage -M 90 susan4
Minimum password length is configured differently, through the PAM (Pluggable Authentication Modules)
system. One must first install the password quality module in the libpam-pwquality
package. Then, we can configure this in the /etc/security/pwquality.conf file. There
are multiple settings available, but a minimum length can be set with:
minlen = 10
AIDE
AIDE is the Advanced Intrusion Detection Environment, and is a host-based intrusion detection system. It essentially scans system files and creates hashes of their contents. It treats this as the baseline of the system and then we can periodically re-scan system files. If there are any deviations from the baseline, we'll know.
The goal is to be notified if system files have been changed without our knowledge which would indicate that the machine has been compromised in some way.
AIDE can be configured with the /etc/aide/aide.conf file. This file pulls in several
other configurations. One helpful change to make is to exclude the /home directory
from scans. We can do that with the line !/home. Then, we can
build the initial baseline of the system with the following command:
$ sudo aide --config /etc/aide/aide.conf --init
This produces a database of hashes for all of our system files. We can tell AIDE to use this going forward for checking by getting rid of the ".new" at the end of the file name:
$ sudo mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz
We can then subsequently perform a check on the sytem with the --check flag:
$ sudo aide --check --config /etc/aide/aide.conf
It will tell us if everything matched up ok, with output like this:
Start timestamp: 2026-04-20 12:33:47 -0400 (AIDE 0.19.1) AIDE found NO differences between database and filesystem. Looks okay!! Ignored e2fs attributes: EINV Number of entries: 3163
Or it will give us output like the following, indicating an error:
Start timestamp: 2026-04-20 12:43:45 -0400 (AIDE 0.19.1) AIDE found differences between database and filesystem!! Ignored e2fs attributes: EINV Summary: Total number of entries: 3163 Added entries: 0 Removed entries: 0 Changed entries: 2 --------------------------------------------------- Changed entries: --------------------------------------------------- d =.... mc.. .. . : /etc/ssh f <.... mci.H.. . : /etc/ssh/sshd_config
If we make a legitimate change to the system (such as updating packages), we can update the database using:
$ sudo aide --update --config /etc/aide/aide.conf $ sudo mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz
For best results the check should be run regularly, which is best
accomplished by putting it in a cron job.
Vulnerabilities
When software vulnerabilities are discovered, they are published so the problem can be mitigated and eventually fixed. The primary authority on vulnerabilities is the Common Vulnerabilities and Exposures (CVE) system. Vulnerabilities are published online at https://cve.mitre.org/, which is run by National Security FFRDC and MITRE.
Vulnerabilities are given a distinct identifier, to make talking about them easier, and also an impact score. based on the Common Vulnerability Scoring System (CVSS). Each vulnerability listed must be:
- Independently Fixable
- Acknowledged by the vendor or documented
- Affecting a single code base (multiple CVEs can come from a single vulnerability)
There are many security-related mailing lists which send messages when vulnerabilities in systems of interest are found. For example, the debian-security-announce list sends messages when vulnerabilities in software packaged by Debian are found. Subscribing to such a mailing list is a good idea for critical systems.