System Hardening
Patch Management
Keeping packages current and knowing what is vulnerable.
Most successful intrusions do not use novel exploits. They use bugs that were fixed weeks or months ago against hosts that never installed the fix. Patch management is the least glamorous control in this foundation and also the highest value: it closes the largest number of real attack paths for the least effort. The goal is not just to run apt upgrade occasionally but to build a system where security fixes land quickly, predictably, and without you having to remember.
This page covers three things: applying updates automatically with sensible guardrails, checking which installed packages carry known vulnerabilities, and handling the special case of the kernel, which normally needs a reboot to take effect.
Update channels on Ubuntu
Ubuntu splits fixes across pockets so you can treat security separately from feature updates. Understanding the split is what lets you auto-apply security patches while holding back riskier changes.
| Contents | Auto-apply by default | |
|---|---|---|
noble-security | Security fixes backported by the security team | Yes |
noble-updates | Bug fixes and non-security stable updates | No (recommended off for prod) |
noble | The release as shipped, no changes | N/A |
noble-backports | Newer features backported on request | No |
The important line is that unattended-upgrades can be scoped to just the security pocket, giving you fast patching of the fixes that matter with minimal risk of a feature update breaking a workload.
Automatic security updates
The unattended-upgrades package applies patches on a timer without human involvement. On Ubuntu 24.04 it is usually installed already; the config that controls it lives in /etc/apt/apt.conf.d/.
sudo apt-get install -y unattended-upgrades
cat /etc/apt/apt.conf.d/50unattended-upgrades | grep -A4 'Allowed-Origins'
Expected output:
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
// "${distro_id}:${distro_codename}-updates";
"${distro_id}ESMApps:${distro_codename}-apps-security";
Only the -security origin is uncommented, which is the safe default. You can trigger a run by hand and read what it would do with a dry run.
sudo unattended-upgrade --dry-run --debug 2>&1 | tail -n 6
Expected output:
Checking: openssl ([<Origin ...noble-security...>])
pkgs that look like they should be upgraded:
openssl libssl3t64
Option --dry-run given, *not* performing real action
Packages that will be upgraded: openssl libssl3t64
The tradeoff
Automatic upgrades trade a small risk of a bad update breaking a service against the much larger, ever-present risk of an unpatched CVE. For most hosts the trade is clearly worth it, but two guardrails make it safer: scope to the security pocket only, and configure reboot behavior deliberately. Leaving Automatic-Reboot "false" means kernel fixes stage but do not activate until you reboot, which is the usual choice for servers you do not want rebooting at 3am.
grep -E 'Automatic-Reboot|Automatic-Reboot-Time' /etc/apt/apt.conf.d/50unattended-upgrades
Expected output:
Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";
Matching packages against CVEs
Applying updates is half the job. The other half is knowing what is still vulnerable right now. Ubuntu ships pro (the Ubuntu Pro client) which surfaces CVE coverage, and the unattended-upgrades timer alone does not tell you what remains open.
pro security-status --format text | head -n 8
Expected output:
2841 packages installed:
1802 packages from Ubuntu Main/Restricted repository
1039 packages from Ubuntu Universe/Multiverse repository
To get more information about the packages, run
pro security-status --help
Ubuntu Pro is not attached to this machine.
For a specific advisory, apt-get changelog shows whether the fix for a named CVE is present in the installed version.
apt changelog openssl 2>/dev/null | grep -m1 CVE-2024
Expected output:
- Fix CVE-2024-6119: possible denial of service in X.509 name checks.
Larger environments feed a package inventory into a dedicated scanner, but the principle is the same everywhere: reconcile the installed version list against a CVE feed and act on the delta.
Kernel updates and live patching
Kernel fixes are the awkward case because activating a new kernel normally requires a reboot, and a reboot is exactly what a busy server owner wants to avoid. Two facts help. First, a staged kernel is inert until reboot, so needrestart will tell you the running kernel is stale.
sudo needrestart -k -b
Expected output:
NEEDRESTART-VER: 3.6
NEEDRESTART-KCUR: 6.8.0-45-generic
NEEDRESTART-KEXP: 6.8.0-52-generic
NEEDRESTART-KSTA: 3
KSTA: 3 means the expected kernel differs from the running one: a reboot is pending. Second, Ubuntu offers Livepatch (part of Ubuntu Pro) which applies critical kernel security fixes to the running kernel without a reboot, buying time until a maintenance window.
sudo pro status | grep livepatch
Expected output:
livepatch yes enabled Canonical Livepatch service
Livepatch covers only high and critical severity kernel fixes, so it complements rather than replaces regular reboots. Treat it as a way to shorten exposure, not eliminate the reboot.
Practical Guidance
- Enable
unattended-upgradesscoped to the-securityorigin on every host so the highest-value patches land without human action. - Set
Automatic-Reboot "false"on servers and reboot in a controlled window; useneedrestartto see when a reboot is actually pending. - Do not confuse “updates applied” with “nothing vulnerable”: run
pro security-statusor an equivalent scanner to see what remains open. - Enable Livepatch on hosts you cannot reboot quickly, but keep scheduling real reboots because it only covers critical kernel fixes.
- Test auto-updates on the lab VM or a staging host first, then roll them out, so a rare bad package does not surprise production.
- After hardening the boot chain (see Boot & Kernel Hardening) confirm updated kernels still boot, since a signed or restricted boot path can reject an unexpected kernel.