Implement Linux security hardening with CIS benchmarks and automated compliance scanning

Intermediate 45 min Apr 26, 2026 83 views
Ubuntu 24.04 Debian 12 AlmaLinux 9 Rocky Linux 9

Harden your Linux systems using CIS benchmarks with automated compliance scanning and continuous monitoring. Learn to implement security controls for filesystem permissions, user authentication, network policies, and maintain ongoing compliance with industry standards.

Prerequisites

  • Root or sudo access
  • Basic Linux command line knowledge
  • Understanding of system administration concepts

What this solves

CIS (Center for Internet Security) benchmarks provide industry-standard security configurations for Linux systems. This tutorial implements comprehensive security hardening following CIS guidelines and sets up automated compliance scanning to detect configuration drift. You'll secure filesystem permissions, strengthen authentication controls, configure network security policies, and establish continuous monitoring for compliance violations.

Step-by-step implementation

Update system packages

Start with fully updated packages to ensure you have the latest security patches.

sudo apt update && sudo apt upgrade -y
sudo apt install -y wget curl gnupg software-properties-common
sudo dnf update -y
sudo dnf install -y wget curl gnupg2 yum-utils

Install CIS-CAT assessment tool

Download and configure the CIS-CAT Lite assessment tool for automated benchmark scanning.

cd /opt
sudo mkdir -p cis-cat
cd cis-cat

Download CIS-CAT Lite (replace with latest version URL)

sudo wget https://learn.cisecurity.org/e/799323/CIS-CAT-Lite-v4-22-0-zip/1234567/1234567890 sudo unzip CIS-CAT-Lite-v4-22-0.zip sudo chmod +x CIS-CAT-Lite/cis-cat-lite.sh

Configure filesystem security hardening

Implement secure mount options and filesystem permissions according to CIS benchmarks.

# Add secure mount options to existing filesystems

Example for /tmp with nodev,nosuid,noexec

tmpfs /tmp tmpfs defaults,rw,nosuid,nodev,noexec,relatime 0 0

For existing filesystems, add security options:

/dev/sda1 / ext4 defaults,nodev 0 1

/dev/sda2 /home ext4 defaults,nodev,nosuid 0 1

# Create separate partition for /var/log if not exists
sudo mkdir -p /var/log/audit

Set secure permissions on system directories

sudo chmod 700 /root sudo chmod 750 /home sudo chmod 755 /var/log sudo chmod 750 /var/log/audit

Secure boot directory

sudo chmod 700 /boot sudo chown root:root /boot

Configure user account and authentication controls

Strengthen password policies, account lockout, and user session controls.

# Password complexity requirements
minlen = 14
minclass = 4
maxrepeat = 2
maxclassrepeat = 2
dcredit = -1
ucredit = -1
lcredit = -1
ocredit = -1
difok = 8
reject_username
enforcetype
# Add account lockout policy (insert after auth required pam_unix.so)
auth required pam_faillock.so preauth silent audit deny=3 unlock_time=900 fail_interval=900
auth [default=die] pam_faillock.so authfail audit deny=3 unlock_time=900 fail_interval=900
auth sufficient pam_faillock.so authsucc audit deny=3 unlock_time=900 fail_interval=900
# Configure secure login defaults
PASS_MAX_DAYS 90
PASS_MIN_DAYS 1
PASS_WARN_AGE 7
LOGIN_RETRIES 3
LOGIN_TIMEOUT 60
SHA_CRYPT_MIN_ROUNDS 5000
SHA_CRYPT_MAX_ROUNDS 10000
# Remove unused user accounts and groups
sudo userdel games 2>/dev/null || true
sudo userdel news 2>/dev/null || true
sudo groupdel games 2>/dev/null || true

Lock system accounts

sudo usermod -L -s /sbin/nologin bin sudo usermod -L -s /sbin/nologin daemon sudo usermod -L -s /sbin/nologin adm sudo usermod -L -s /sbin/nologin lp

Configure SSH hardening

Secure SSH access with CIS-compliant configuration settings.

# SSH hardening configuration
Protocol 2
Port 22
AddressFamily inet
ListenAddress 0.0.0.0

Authentication settings

PermitRootLogin no MaxAuthTries 3 MaxSessions 4 MaxStartups 10:30:60 LoginGraceTime 60

Key-based authentication

PubkeyAuthentication yes PasswordAuthentication no PermitEmptyPasswords no ChallengeResponseAuthentication no KerberosAuthentication no GSSAPIAuthentication no

Security options

X11Forwarding no PermitUserEnvironment no Compression no UseDNS no PermitTunnel no AllowTcpForwarding no ClientAliveInterval 300 ClientAliveCountMax 2

Restrict users and groups

AllowUsers user1 user2

AllowGroups ssh-users

Logging

SyslogFacility AUTHPRIV LogLevel INFO
sudo systemctl restart sshd
sudo systemctl status sshd

Configure network and firewall security

Implement network hardening with secure kernel parameters and firewall rules.

# Network security hardening

IP forwarding

net.ipv4.ip_forward = 0 net.ipv6.conf.all.forwarding = 0

Source routing

net.ipv4.conf.all.send_redirects = 0 net.ipv4.conf.default.send_redirects = 0 net.ipv4.conf.all.accept_source_route = 0 net.ipv4.conf.default.accept_source_route = 0 net.ipv6.conf.all.accept_source_route = 0 net.ipv6.conf.default.accept_source_route = 0

ICMP redirects

net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.default.accept_redirects = 0 net.ipv6.conf.all.accept_redirects = 0 net.ipv6.conf.default.accept_redirects = 0

Secure ICMP redirects

net.ipv4.conf.all.secure_redirects = 0 net.ipv4.conf.default.secure_redirects = 0

Log suspicious packets

net.ipv4.conf.all.log_martians = 1 net.ipv4.conf.default.log_martians = 1

Ignore ICMP ping requests

net.ipv4.icmp_echo_ignore_all = 0 net.ipv4.icmp_echo_ignore_broadcasts = 1

TCP SYN flood protection

net.ipv4.tcp_syncookies = 1 net.ipv4.tcp_max_syn_backlog = 2048 net.ipv4.tcp_synack_retries = 2 net.ipv4.tcp_syn_retries = 5

IPv6 router advertisements

net.ipv6.conf.all.accept_ra = 0 net.ipv6.conf.default.accept_ra = 0
# Apply sysctl settings
sudo sysctl -p /etc/sysctl.d/99-cis-hardening.conf

Configure UFW firewall

sudo ufw --force reset sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw allow ssh sudo ufw --force enable
# Apply sysctl settings
sudo sysctl -p /etc/sysctl.d/99-cis-hardening.conf

Configure firewalld

sudo systemctl enable --now firewalld sudo firewall-cmd --set-default-zone=public sudo firewall-cmd --permanent --remove-service=dhcpv6-client sudo firewall-cmd --permanent --remove-service=cockpit sudo firewall-cmd --reload

Configure audit logging

Enable comprehensive audit logging for security events and compliance monitoring.

sudo apt install -y auditd audispd-plugins
sudo dnf install -y audit audit-libs
# Audit daemon configuration
log_file = /var/log/audit/audit.log
log_format = RAW
log_group = adm
priority_boost = 4
flush = INCREMENTAL_ASYNC
freq = 50
num_logs = 5
disp_qos = lossy
dispatcher = /sbin/audispd
name_format = HOSTNAME
max_log_file = 50
max_log_file_action = ROTATE
space_left = 75
space_left_action = SYSLOG
verify_email = yes
admin_space_left = 50
admin_space_left_action = SUSPEND
disk_full_action = SUSPEND
disk_error_action = SUSPEND
use_libwrap = yes
tcp_listen_queue = 5
tcp_max_per_addr = 1
tcp_client_max_idle = 0
enable_krb5 = no
# CIS Audit Rules

Remove any existing rules

-D

Buffer size

-b 8192

Failure mode

-f 1

Audit the auditd configuration files

-w /etc/audit/ -p wa -k auditconfig -w /etc/libaudit.conf -p wa -k auditconfig

Monitor for changes to user and group files

-w /etc/group -p wa -k identity -w /etc/passwd -p wa -k identity -w /etc/gshadow -p wa -k identity -w /etc/shadow -p wa -k identity -w /etc/security/opasswd -p wa -k identity

Monitor login and logout events

-w /var/log/lastlog -p wa -k logins -w /var/run/faillock/ -p wa -k logins

Monitor network configuration changes

-a always,exit -F arch=b64 -S sethostname -S setdomainname -k system-locale -a always,exit -F arch=b32 -S sethostname -S setdomainname -k system-locale -w /etc/issue -p wa -k system-locale -w /etc/issue.net -p wa -k system-locale -w /etc/hosts -p wa -k system-locale -w /etc/network/ -p wa -k system-locale

Monitor system administration events

-w /var/log/sudo.log -p wa -k actions -w /etc/sudoers -p wa -k actions -w /etc/sudoers.d/ -p wa -k actions

Monitor kernel modules

-w /sbin/insmod -p x -k modules -w /sbin/rmmod -p x -k modules -w /sbin/modprobe -p x -k modules -a always,exit -F arch=b64 -S init_module -S delete_module -k modules

Monitor file permission changes

-a always,exit -F arch=b64 -S chmod -S fchmod -S fchmodat -F auid>=1000 -F auid!=4294967295 -k perm_mod -a always,exit -F arch=b32 -S chmod -S fchmod -S fchmodat -F auid>=1000 -F auid!=4294967295 -k perm_mod -a always,exit -F arch=b64 -S chown -S fchown -S fchownat -S lchown -F auid>=1000 -F auid!=4294967295 -k perm_mod -a always,exit -F arch=b32 -S chown -S fchown -S fchownat -S lchown -F auid>=1000 -F auid!=4294967295 -k perm_mod

Make the configuration immutable

-e 2
sudo systemctl enable --now auditd
sudo augenrules --load
sudo systemctl restart auditd

Set up automated compliance monitoring

Create scripts for continuous CIS benchmark compliance checking and reporting.

#!/bin/bash

CIS Compliance Monitoring Script

LOG_DIR="/var/log/cis-compliance" REPORT_FILE="$LOG_DIR/cis-report-$(date +%Y%m%d-%H%M%S).json" CIS_CAT_DIR="/opt/cis-cat/CIS-CAT-Lite"

Create log directory

mkdir -p "$LOG_DIR"

Function to log messages

log_message() { echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" | tee -a "$LOG_DIR/compliance.log" } log_message "Starting CIS compliance check"

Run CIS-CAT assessment

if [ -d "$CIS_CAT_DIR" ]; then cd "$CIS_CAT_DIR" ./cis-cat-lite.sh -a -r "$REPORT_FILE" -rft json log_message "CIS-CAT assessment completed: $REPORT_FILE" else log_message "ERROR: CIS-CAT directory not found at $CIS_CAT_DIR" exit 1 fi

Parse results and check for failures

FAILED_CHECKS=$(jq '.TestResult[] | select(.result == "fail") | .ruleId' "$REPORT_FILE" | wc -l) TOTAL_CHECKS=$(jq '.TestResult | length' "$REPORT_FILE") SCORE=$(jq '.score' "$REPORT_FILE") log_message "Compliance Score: $SCORE%" log_message "Failed Checks: $FAILED_CHECKS/$TOTAL_CHECKS"

Send alert if compliance score is below threshold

THRESHOLD=80 if (( $(echo "$SCORE < $THRESHOLD" | bc -l) )); then log_message "ALERT: Compliance score ($SCORE%) is below threshold ($THRESHOLD%)" # Extract failed checks echo "Failed CIS Controls:" >> "$LOG_DIR/failed-controls.txt" jq -r '.TestResult[] | select(.result == "fail") | "\(.ruleId): \(.description)"' "$REPORT_FILE" >> "$LOG_DIR/failed-controls.txt" # Optional: Send email notification (requires mail setup) # mail -s "CIS Compliance Alert - Score: $SCORE%" admin@example.com < "$LOG_DIR/failed-controls.txt" fi

Cleanup old reports (keep last 30 days)

find "$LOG_DIR" -name "cis-report-*.json" -mtime +30 -delete log_message "CIS compliance check completed"
sudo mkdir -p /opt/cis-monitoring
sudo chmod +x /opt/cis-monitoring/cis-compliance-check.sh
sudo chown root:root /opt/cis-monitoring/cis-compliance-check.sh

Install bc for calculations

sudo apt install -y bc jq || sudo dnf install -y bc jq

Configure automated compliance reporting

Set up systemd timers for regular compliance checks and automated reporting.

[Unit]
Description=CIS Compliance Check
Wants=cis-compliance-check.timer

[Service]
Type=oneshot
User=root
ExecStart=/opt/cis-monitoring/cis-compliance-check.sh
StandardOutput=journal
StandardError=journal
[Unit]
Description=Run CIS compliance check daily
Requires=cis-compliance-check.service

[Timer]
OnCalendar=daily
Persistent=true

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now cis-compliance-check.timer
sudo systemctl status cis-compliance-check.timer

Configure centralized logging integration

Forward security events and compliance reports to centralized logging system.

# CIS Security Event Logging

Forward audit logs to central server (optional)

. @@log.example.com:514

Local security log aggregation

auth,authpriv.* /var/log/auth.log kern.* /var/log/kern.log mail.* /var/log/mail.log cron.* /var/log/cron.log

CIS compliance logs

:programname,isequal,"cis-compliance" /var/log/cis-compliance/compliance.log & stop
sudo systemctl restart rsyslog

Set up log rotation for compliance logs

sudo tee /etc/logrotate.d/cis-compliance << EOF /var/log/cis-compliance/*.log { weekly missingok rotate 12 compress delaycompress notifempty create 644 root root postrotate systemctl reload rsyslog > /dev/null 2>&1 || true endscript } EOF

Verify your setup

Test the security hardening implementation and compliance monitoring system.

# Check SSH configuration
sudo sshd -t
sudo systemctl status sshd

Verify firewall status

sudo ufw status verbose || sudo firewall-cmd --list-all

Check audit daemon

sudo systemctl status auditd sudo auditctl -s

Test audit rules

sudo ausearch -k identity -ts today

Verify sysctl security settings

sudo sysctl net.ipv4.ip_forward sudo sysctl net.ipv4.conf.all.send_redirects

Check compliance monitoring timer

sudo systemctl status cis-compliance-check.timer sudo systemctl list-timers cis-compliance-check.timer

Run manual compliance check

sudo /opt/cis-monitoring/cis-compliance-check.sh

Check compliance logs

sudo tail -f /var/log/cis-compliance/compliance.log
Note: The initial CIS-CAT scan may take 10-15 minutes depending on system size. Monitor /var/log/cis-compliance/compliance.log for progress updates.

Common issues

SymptomCauseFix
SSH login fails after hardeningDisabled password authentication without SSH keysAdd SSH public key to ~/.ssh/authorized_keys before disabling passwords
Applications can't write to logsRestrictive file permissionsCreate dedicated log directories with chmod 755 and correct ownership
CIS-CAT scan failsMissing Java or incorrect permissionsInstall OpenJDK and ensure cis-cat-lite.sh is executable
Audit logs filling diskHigh audit rule verbosityConfigure log rotation and adjust audit rules granularity
Network services unreachableOverly restrictive firewall rulesAdd specific service rules before enabling firewall
System performance degradedExcessive audit loggingTune audit rules to focus on critical events only
Warning: Always test security hardening in a non-production environment first. Some CIS controls may break applications that rely on specific system behaviors. Plan for gradual implementation and thorough testing.

Next steps

Running this in production?

Need compliance handled automatically? Setting this up once is straightforward. Keeping it patched, monitored, backed up and compliant across environments is the harder part. See how we run infrastructure like this for European teams.

Automated install script

Run this to automate the entire setup

Need help?

Don't want to manage this yourself?

We handle infrastructure security hardening for businesses that depend on uptime. From initial setup to ongoing operations.