Back to Articles
Linux Hardening

CIS Benchmark Level 2 on Ubuntu 22.04: A Practical Walkthrough

Most organizations know they need to harden their Linux systems. Fewer actually do it at scale, with documentation, and in a way that survives the next engineer joining the team. This walkthrough gives you a production-ready approach to CIS Level 2 on Ubuntu 22.04 — not just a list of commands, but the reasoning behind each control and how to automate it.

CIS Level 2 is designed for environments where security takes priority over usability or performance. It's the right target for internet-facing servers, systems handling sensitive data, or anything in a PCI-DSS or FedRAMP scope.

1. Filesystem Hardening

The CIS benchmark separates filesystem configuration into partition layout, mount options, and module restrictions. Most default Ubuntu installs fail the partition sections entirely because cloud images typically use a single root partition.

Separate partitions for sensitive directories

CIS L2 requires /tmp, /var, /var/log, /var/log/audit, and /home on separate partitions. In cloud environments, you can achieve this with LVM or by using separate EBS volumes. The key mount options to enforce:

# /etc/fstab entries for hardened mount options
tmpfs   /tmp         tmpfs  defaults,nodev,nosuid,noexec  0 0
/dev/sdb /var/log    ext4   defaults,nodev,nosuid         0 0
/dev/sdc /var/log/audit ext4 defaults,nodev,nosuid        0 0

The noexec flag on /tmp is particularly important — it prevents attackers from executing code dropped into a world-writable temp directory, which is a common post-exploitation technique.

Disable unused filesystems

Several legacy or uncommon filesystems should be explicitly blacklisted to reduce attack surface. Create a modprobe configuration file:

# /etc/modprobe.d/cis-filesystem.conf
install cramfs /bin/true
install squashfs /bin/true
install udf /bin/true
install freevxfs /bin/true
install jffs2 /bin/true
install hfs /bin/true
install hfsplus /bin/true

2. Network Parameter Hardening (sysctl)

Kernel network parameters are one of the most impactful controls you can apply — and they're also easy to automate. Add these to /etc/sysctl.d/99-cis-hardening.conf:

# Disable IP forwarding (unless this is a router)
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0

# Disable packet redirect sending
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0

# Enable source route verification
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Disable ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0

# Log suspicious packets
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

# SYN flood protection
net.ipv4.tcp_syncookies = 1

# Disable IPv6 if not in use
net.ipv6.conf.all.disable_ipv6 = 1

Apply immediately with sysctl --system. These settings persist across reboots.

3. SSH Hardening

The CIS benchmark's SSH controls are extensive. Here are the settings that matter most for Level 2 compliance:

# /etc/ssh/sshd_config — CIS L2 hardened configuration
Protocol 2
PermitRootLogin no
MaxAuthTries 4
IgnoreRhosts yes
HostbasedAuthentication no
PermitEmptyPasswords no
PermitUserEnvironment no
Ciphers aes128-ctr,aes192-ctr,aes256-ctr,[email protected],[email protected]
MACs hmac-sha2-256,hmac-sha2-512,[email protected],[email protected]
KexAlgorithms ecdh-sha2-nistp256,ecdh-sha2-nistp384,ecdh-sha2-nistp521
ClientAliveInterval 300
ClientAliveCountMax 0
LoginGraceTime 60
Banner /etc/issue.net
AllowTcpForwarding no
X11Forwarding no
PrintLastLog yes

4. auditd Configuration

Audit logging is required for both CIS L2 and most compliance frameworks. The CIS benchmark specifies exactly which syscalls and file accesses must be logged:

# /etc/audit/rules.d/cis-audit.rules
# Log all changes to system administration scope
-w /etc/sudoers -p wa -k scope
-w /etc/sudoers.d/ -p wa -k scope

# Monitor privileged command execution
-a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -k privileged
-a always,exit -F path=/usr/sbin/useradd -F perm=x -F auid>=1000 -F auid!=unset -k privileged

# Log login/logout events
-w /var/log/lastlog -p wa -k logins
-w /var/run/faillock/ -p wa -k logins

# File deletion events
-a always,exit -F arch=b64 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=unset -k delete

5. Automated Scanning with Lynis

Once you've applied the controls, use Lynis to measure your compliance score and identify remaining gaps:

apt install lynis -y
lynis audit system --quiet --report-file /var/log/lynis-report.dat

# Extract hardening index score
grep "hardening_index" /var/log/lynis-report.dat

A fully hardened system should score above 80. Cross-reference Lynis output with the CIS benchmark controls to identify any gaps specific to your environment.

Automating It at Scale

If you're applying this to more than a handful of servers, doing it manually is a mistake. I use Ansible playbooks for every CIS hardening engagement — they're idempotent, testable, and give you a baseline you can enforce on every new build automatically. I'll cover the Ansible approach in a follow-up article.

The goal is not to run hardening once. The goal is a baseline that's enforced on every new build, verified on every deployment, and documented for every auditor.

If you're working toward CIS compliance for a specific audit or compliance framework and want a second set of eyes — or want this implemented at scale across your fleet — reach out. This is exactly what I do.

Need this implemented on your systems?

I handle CIS/STIG hardening for teams that need it done right and documented properly for auditors.