03 · Linux Security Hardening¶
Level 1 Module 3 covered OS security basics conceptually across platforms. This module goes hands-on with Linux server hardening — the concrete steps a defender takes to reduce a fresh Linux install's attack surface before it goes anywhere near production, using a disposable VM or container so you can break things safely.
Lab setup
Use a disposable VM (VirtualBox/UTM/multipass Ubuntu Server image) or a Docker container for every command below. Never practice hardening commands — especially firewall and SSH changes — on a machine you can't afford to lock yourself out of.
1. The principle: minimize attack surface¶
Every open port, running service, installed package, and enabled user account is something an attacker could potentially abuse. Hardening is systematically removing everything that isn't needed:
# What's listening?
sudo ss -tulpn
# What's installed that you didn't explicitly ask for?
apt list --installed | wc -l # Debian/Ubuntu
rpm -qa | wc -l # RHEL/CentOS
# What services start on boot?
systemctl list-unit-files --state=enabled
2. SSH hardening¶
SSH is the most commonly attacked service on internet-facing Linux hosts.
Edit /etc/ssh/sshd_config:
# Disable direct root login -- forces attackers (and admins) through a
# named account first, which is auditable and can be MFA-protected
PermitRootLogin no
# Disable password auth entirely -- key-based auth resists brute force
PasswordAuthentication no
PubkeyAuthentication yes
# Change the default port -- doesn't stop a targeted attacker, but
# eliminates 95% of untargeted internet-wide scanning noise
Port 2222
# Limit which users/groups may connect over SSH at all
AllowUsers deploy admin
# Disconnect idle sessions
ClientAliveInterval 300
ClientAliveCountMax 2
Generate and deploy a key pair rather than relying on passwords:
3. Firewall configuration (UFW)¶
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 2222/tcp # your new SSH port -- do this BEFORE enabling!
sudo ufw allow 443/tcp # only the services you actually need
sudo ufw enable
sudo ufw status verbose
The order matters: allow your SSH port before enabling the firewall, or you will lock yourself out of a remote box with no console access.
4. Automatic security updates¶
This applies security patches automatically without requiring a human to remember — the single highest-leverage hardening step, since most breaches exploit vulnerabilities that already had a patch available.
5. Least-privilege users and sudo¶
# Create a named, non-root admin account
sudo adduser deploy
sudo usermod -aG sudo deploy
# Audit who can sudo, and to what
sudo cat /etc/sudoers.d/*
# Never share accounts -- every human gets their own, for accountability
6. File permission and integrity basics¶
# Find world-writable files -- a classic privilege escalation vector
find / -xdev -type f -perm -0002 -ls 2>/dev/null
# Find SUID/SGID binaries -- run as the file owner, not the caller;
# unnecessary ones are a privilege-escalation path
find / -xdev \( -perm -4000 -o -perm -2000 \) -ls 2>/dev/null
# File integrity monitoring -- detect unauthorized changes to critical files
sudo apt install aide
sudo aideinit
sudo aide --check
7. Kernel and network hardening (sysctl)¶
# /etc/sysctl.d/99-hardening.conf
net.ipv4.conf.all.rp_filter = 1 # reject spoofed source addresses
net.ipv4.tcp_syncookies = 1 # mitigate SYN flood DoS
net.ipv4.conf.all.accept_redirects = 0 # ignore unsolicited ICMP redirects
net.ipv4.conf.all.log_martians = 1 # log packets with impossible addresses
8. Mandatory access control (AppArmor / SELinux)¶
Discretionary permissions (chmod/chown) only restrict who can access a
file. Mandatory access control restricts what a process is allowed to do
at all, even as root, based on a policy — so a compromised web server
process can't read /etc/shadow even if the web server happens to be
running as root.
# Ubuntu/Debian ships AppArmor by default
sudo aa-status
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx
# RHEL/CentOS ships SELinux by default
getenforce
sudo setenforce 1
sestatus
9. A hardening checklist (CIS Benchmarks)¶
The Center for Internet Security (CIS) Benchmarks are the industry-
standard, freely available hardening checklists for every major OS and
platform. lynis automates auditing a box against these:
Lynis produces a scored report with specific, actionable findings — run it before and after hardening to measure your progress.
How It Actually Works: how AppArmor/SELinux enforce beyond Unix permissions, and what sysctl hardening actually changes in the kernel¶
Standard Unix permissions (Module 3) are discretionary — the file's
owner decides who else can access it, and once a process runs as root, it
can read/write anything regardless of any file's mode bits, because root
bypasses the permission check entirely in the kernel's capable() logic.
Mandatory Access Control (AppArmor, SELinux) closes exactly this gap by
adding a second, independent check that even root cannot bypass by default.
AppArmor works by loading a profile per binary — a whitelist of exact
filesystem paths, capabilities, and network operations that binary is
allowed to perform, enforced via Linux Security Module (LSM) hooks that the
kernel calls at every relevant syscall (open, exec, connect) before
the normal permission check even runs. A profile entry like
/etc/shadow r, grants read-only access to that one path; anything not
explicitly listed is denied, so a compromised nginx process running as
root still cannot read /etc/shadow if the nginx profile never mentions it
— the compromise is contained by policy the attacker's root shell has no
authority to alter, because policy enforcement happens in the kernel LSM
hook chain, a layer beneath any user-space privilege the exploited process
holds. SELinux does the same job with a richer model (type enforcement:
every process and object gets a security type, and policy defines which
type-pairs are allowed to interact) but the enforcement point is identical —
an LSM hook that runs regardless of the calling process's UID.
sysctl hardening changes runtime parameters read directly by kernel
networking code on every packet. net.ipv4.tcp_syncookies = 1 turns on the
SYN-cookie defense described in Module 2 at the exact point the kernel's TCP
stack would otherwise allocate a connection control block.
net.ipv4.conf.all.rp_filter = 1 enables reverse path filtering: for
every incoming packet, the kernel checks whether a route back to the
packet's source IP would actually egress through the same interface the
packet arrived on — if not, the packet is dropped, because a legitimately
routed packet's reply path should be symmetric, and asymmetry is the
signature of a spoofed source address used in reflection/amplification
attacks. These aren't application-level filters; they're single-bit switches
that change branches inside the kernel's already-compiled network stack, which
is why they take effect instantly with zero performance cost for the
non-attack case — the extra check was already cheap enough to always run.
Key terms¶
| Term | Meaning |
|---|---|
| Attack surface | The sum of everything an attacker could potentially interact with or exploit |
| Least privilege | Every account/process gets only the access it strictly needs |
| MAC (Mandatory Access Control) | Kernel-enforced policy restricting process behavior beyond file permissions (AppArmor, SELinux) |
| SUID/SGID | File permission bits that run a binary as its owner/group rather than the caller — a common privilege-escalation vector if misused |
| CIS Benchmark | Industry-standard, vendor-neutral hardening checklist |
| Unattended upgrades | Automatic application of security patches without manual intervention |
Exercise¶
- Spin up a fresh Ubuntu Server VM or container.
- Run
lynis audit systemand record the initial hardening score. - Apply sections 2–7 above, in order (SSH changes last, testing each change in a second terminal session before closing your first one).
- Re-run
lynis audit systemand compare the score. - Find and document (don't remove yet) any SUID binaries on the box you don't recognize — research what each one is for before deciding whether it's actually needed.