Linux Server Hardening — CIS Benchmarks & Security Best Practices
In this tutorial, you'll learn about Linux Server Hardening. We cover key concepts, practical examples, and best practices to help you understand and apply this topic effectively.
CIS Benchmarks provide globally recognized, consensus-based guidelines for securing Linux servers, covering kernel parameters, user access, network configuration, logging, and file integrity monitoring.
What You'll Learn
How to apply CIS Benchmark controls to Linux systems: configure kernel hardening via sysctl, audit services and disable unnecessary ones, enforce password policies through PAM, set up file integrity monitoring with AIDE, blacklist unused kernel modules, and automate Compliance checks with OpenSCAP.
Why CIS Benchmarks Matter
Security hardening guides are only useful if they follow a recognized standard. CIS Benchmarks are the most widely adopted — used by banks, governments, and Compliance frameworks (PCI DSS, HIPAA, SOC 2). Following CIS controls reduces attack surface systematically rather than ad-hoc. Durga Antivirus Pro's deployment pipeline validates every build against CIS Level 2 benchmarks before promotion to production.
Learning Path
flowchart LR A[journalctl Guide] --> B[Server Hardening CIS
You are here] B --> C[LXC Containers] B --> D[Security Hardening] style B fill:#f90,color:#fff
Kernel Hardening (CIS Control 1)
# Hardened sysctl configuration
sudo tee /etc/sysctl.d/99-cis-hardening.conf << 'EOF'
# 1.1.1 Disable unused filesystems
fs.squashfs = 0
fs.vfat = 0
fs.cramfs = 0
# 1.2.1 Restrict core dumps
fs.suid_dumpable = 0
# 1.3.1 IP forwarding (disable unless needed)
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0
# 1.3.2 Source routed packets
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
# 1.3.3 ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
# 1.3.4 Ignore broadcast pings
net.ipv4.icmp_echo_ignore_broadcasts = 1
# 1.3.5 TCP SYN cookies
net.ipv4.tcp_syncookies = 1
# 1.3.6 Log martian packets
net.ipv4.conf.all.log_martians = 1
# 1.4.1 Reverse path filtering
net.ipv4.conf.all.rp_filter = 1
# 1.5.1 Address space layout randomization
kernel.randomize_va_space = 2
# 1.5.2 Restrict perf events
kernel.perf_event_paranoid = 3
# 1.5.3 Restrict kptr
kernel.kptr_restrict = 2
# 1.6.1 Disable sysrq
kernel.sysrq = 0
EOF
sudo sysctl -p /etc/sysctl.d/99-cis-hardening.conf
Service Auditing (CIS Control 2)
# List all listening services
sudo ss -tulpn
# Disable unnecessary services
sudo systemctl disable --now avahi-daemon
sudo systemctl disable --now cups
sudo systemctl disable --now rpcbind
sudo systemctl disable --now bluetooth
sudo systemctl disable --now isc-dhcp-server
sudo systemctl disable --now slapd
# Ensure only essential services remain:
# sshd, systemd-journald, rsyslog (or journald), cron, ntp/chrony, auditd
Service Inventory Checklist
# Create a service inventory
for unit in $(systemctl list-units --type=service --state=running --no-legend | awk '{print $1}'); do
desc=$(systemctl show "$unit" -p Description --value)
echo "$unit | $desc"
done | sort
Filesystem Partitioning (CIS Control 3)
# Ensure separate partitions for critical directories
# /tmp — nosuid, noexec, nodev
# /var — separate partition
# /var/tmp — nosuid, noexec, nodev
# /var/log — separate partition
# /var/log/audit — separate partition
# /home — nosuid, nodev
# Apply mount options
sudo tee -a /etc/fstab << 'EOF'
tmpfs /tmp tmpfs defaults,nosuid,noexec,nodev 0 0
tmpfs /var/tmp tmpfs defaults,nosuid,noexec,nodev 0 0
EOF
# Secure /boot mount (prevent unauthorized kernel updates)
sudo mount -o remount,rw,nosuid,nodev /boot
PAM Password Policies (CIS Control 5)
# Password quality requirements
sudo tee /etc/security/pwquality.conf << 'EOF'
minlen = 14
dcredit = -1
ucredit = -1
ocredit = -1
lcredit = -1
minclass = 4
maxrepeat = 3
difok = 5
usercheck = 1
enforce_for_root
EOF
# Password expiration
sudo tee -a /etc/login.defs << 'EOF'
PASS_MAX_DAYS 90
PASS_MIN_DAYS 7
PASS_WARN_AGE 14
EOF
# Lock account after failed attempts
sudo tee /etc/pam.d/common-auth << 'EOF'
auth required pam_faillock.so preauth audit silent deny=5 unlock_time=900
auth [default=die] pam_faillock.so authfail audit deny=5 unlock_time=900
auth sufficient pam_unix.so
auth required pam_deny.so
EOF
# Ensure root PATH is safe
echo 'Defaults secure_path="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"' | \
sudo tee /etc/sudoers.d/secure_path
File Integrity Monitoring with AIDE (CIS Control 6)
# Install AIDE
sudo apt install aide
# Initialize the database
sudo aideinit
sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
# Custom configuration
sudo tee -a /etc/aide/aide.conf << 'EOF'
# Critical system binaries
/etc/group PERMS
/etc/gshadow PERMS
/etc/passwd PERMS
/etc/shadow PERMS
/etc/ssh/sshd_config PERMS
/bin Content
/sbin Content
/usr/bin Content
/usr/sbin Content
# Configuration files
/etc Content
# Exclude transient files
!/var/log
!/tmp
!/proc
!/sys
EOF
# Run a check
sudo aide --check
# Run daily via cron
sudo tee /etc/cron.daily/aide-check << 'EOF'
#!/bin/bash
/usr/bin/aide --check | /usr/bin/mail -s "AIDE Daily Check" root
EOF
sudo chmod +x /etc/cron.daily/aide-check
Expected AIDE check output:
AIDE found differences between database and filesystem!!
Start timestamp: 2026-06-24 03:00:00
Summary:
Total number of files: 34567
Added files: 2
Removed files: 0
Changed files: 12
Changed attributes:
/etc/nginx/nginx.conf Size, MD5, SHA256
/etc/hostname Content
/var/log/syslog ...
Kernel Module Blacklisting (CIS Control 7)
# Blacklist unused kernel modules
sudo tee /etc/modprobe.d/blacklist-cis.conf << 'EOF'
# Unused filesystem modules
blacklist cramfs
blacklist freevxfs
blacklist jffs2
blacklist hfs
blacklist hfsplus
blacklist squashfs
blacklist udf
blacklist vfat
# Unused network protocols
blacklist dccp
blacklist sctp
blacklist rds
blacklist tipc
# Unused hardware drivers
blacklist bluetooth
blacklist btusb
blacklist thunderbolt
blacklist firewire-core
EOF
# Verify no modules are loaded
lsmod | grep -E "cramfs|freevxfs|jffs2|hfs|squashfs|udf|dccp|sctp|rds|tipc"
Automated Compliance with OpenSCAP
# Install OpenSCAP
sudo apt install libopenscap8 scap-security-guide
# Run a CIS Benchmark scan
sudo oscap xccdf eval \
--profile xccdf_org.ssgproject.content_profile_cis \
--results results.xml \
--report report.html \
/usr/share/xml/scap/ssg/content/ssg-ubuntu2204-ds.xml
# Open the HTML report
xdg-open report.html
Hardening Script Generator
# Generate a remediation script from scan results
sudo oscap xccdf generate fix \
--profile xccdf_org.ssgproject.content_profile_cis \
--output remediation.sh \
/usr/share/xml/scap/ssg/content/ssg-ubuntu2204-ds.xml
Automated Hardening Checklist
#!/bin/bash
# cis-audit.sh — Check CIS Level 1 and 2 compliance
# Run as root
echo "=== CIS Compliance Audit ==="
echo "Date: $(date)"
echo
# 1. File permissions
echo "--- Critical File Permissions ---"
for f in /etc/passwd /etc/shadow /etc/group /etc/gshadow /etc/sudoers; do
perms=$(stat -c "%a %u:%g %n" "$f" 2>/dev/null)
echo "$perms"
done
# 2. SSH config
echo
echo "--- SSH Configuration ---"
grep -E "^(PermitRootLogin|PasswordAuthentication|PubkeyAuthentication|Protocol)" /etc/ssh/sshd_config
# 3. Listening ports
echo
echo "--- Listening Ports ---"
ss -tulpn4
# 4. Kernel parameters
echo
echo "--- Kernel Security Parameters ---"
for param in kernel.randomize_va_space net.ipv4.tcp_syncookies net.ipv4.conf.all.rp_filter kernel.perf_event_paranoid; do
val=$(sysctl -n "$param" 2>/dev/null)
echo "$param = $val"
done
# 5. Password policy
echo
echo "--- Password Policy ---"
grep -E "PASS_MAX_DAYS|PASS_MIN_DAYS|PASS_WARN_AGE" /etc/login.defs
# 6. Running services
echo
echo "--- Non-Essential Services Running ---"
for svc in avahi-daemon cups bluetooth rpcbind; do
if systemctl is-active --quiet "$svc" 2>/dev/null; then
echo "WARNING: $svc is running"
fi
done
echo
echo "=== Audit Complete ==="
Common Errors
1. sysctl "Permission denied" at Boot
Some distributions restrict sysctl writes for security-related keys. Add kernel.kptr_restrict=2 to /etc/sysctl.d/ but it may need sysctl --system after boot if systemd-sysctl does not apply it.
2. AIDE Database Out of Sync After Updates
Every package update changes system binaries. Run sudo aideinit && sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db after each update cycle.
3. OpenSCAP Profile Not Found
The SCAP security guide package version may not include the CIS profile for your distribution. Check available profiles: oscap info /usr/share/xml/scap/ssg/content/ssg-ubuntu2204-ds.xml | grep Profile.
4. PAM Lockout Locks Admin Out
If you misconfigure PAM, all users including root may be locked out. Always keep a root shell open when testing PAM changes. Have a recovery plan (rescue mode, live USB).
5. Blacklisted Modules Still Loading
Some modules load via initramfs. Rebuild initramfs after changing modprobe.d: sudo update-initramfs -u -k all.
6. Firewall Rules Ineffective Without IPv6
Many services listen on IPv6 by default. CIS requires both ip6tables and iptables rules, or use nftables with inet family that covers both protocols.
7. /tmp Mount Options Not Applied After Reboot
The tmp.mount systemd unit may override fstab entries for /tmp. Mask the unit: sudo systemctl mask tmp.mount.
Practice Questions
1. What CIS control disables core dumps?
Control 1.2.1: set fs.suid_dumpable = 0 in sysctl configuration.
2. Which kernel parameter enables ASLR?
kernel.randomize_va_space = 2 — full randomization for all memory mappings.
3. How does AIDE detect unauthorized file changes? It creates a baseline database of file checksums (SHA256, MD5) and compares current files against it. Any mismatch triggers an alert.
4. What is the CIS recommended minimum password length? 14 characters, with at least one uppercase, lowercase, digit, and special character each.
5. How do you generate a remediation script from an OpenSCAP scan?
sudo oscap xccdf generate fix --profile cis --output remediate.sh <data-stream.xml>
Challenge: Set up a fresh Ubuntu 22.04 server and apply CIS Level 2 hardening controls. Run OpenSCAP before and after to get a Compliance score. Your target is 90%+ Compliance. Document each control you change, the rationale, and any trade-offs (e.g., controls that break specific applications). Create a cron job that runs AIDE daily and emails the report.
What's Next
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro. Updated 2026-06-24.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro