Hardening Linux Endpoint with CIS Benchmark
When to Use
Use this skill when:
- Hardening Linux servers (Ubuntu, RHEL, CentOS, Debian) against CIS benchmarks
- Automating Linux security baselines using Ansible, OpenSCAP, or shell scripts
- Meeting compliance requirements (PCI DSS, HIPAA, SOC 2) for Linux endpoints
- Remediating findings from vulnerability scans or security audits
Do not use for Windows hardening (use hardening-windows-endpoint-with-cis-benchmark).
Common Misconfigurations & Verification
- auditd rules edited but never loaded: writing
/etc/audit/rules.d/cis.rules does nothing until augenrules --load runs and auditctl -l lists them; an earlier -e 2 (immutable) line blocks later additions until reboot. Confirm the identity/scope/perm_mod watches are live, not just on disk.
- sysctl applied at runtime but not persisted: values set with
sysctl -w revert on reboot. Verify the /etc/sysctl.d/99-cis.conf keys actually take effect — e.g. sysctl net.ipv4.conf.all.rp_filter after sysctl --system (some are overridden by cloud-init or a higher-numbered file).
- /tmp and /dev/shm options silently inactive:
mount | grep -E '/tmp|/dev/shm' must show noexec,nosuid,nodev; an fstab typo leaves the partition mounted with defaults. A line in fstab is not proof it is applied.
- Config drift after baseline: re-run OpenSCAP on a schedule — a one-time pass does not catch package updates or an admin re-enabling
PasswordAuthentication. Match the profile to the OS (ssg-ubuntu2204-ds.xml, cis_level1_server); a mismatched data stream reports false passes.
- Verify enforcement, not just config: after hardening, test from a second SSH session (so a bad
sshd_config won't lock you out), then touch /etc/passwd and confirm an auditd identity key event is generated and shipped to the remote rsyslog/SIEM.
Prerequisites
- Root or sudo access on target Linux endpoints
- CIS Benchmark PDF for target distribution (from cisecurity.org)
- OpenSCAP or CIS-CAT for automated assessment
- Ansible for enterprise-scale remediation (optional)
Workflow
Step 1: Filesystem Configuration (Section 1)
# 1.1.1 Disable unused filesystems
cat >> /etc/modprobe.d/CIS.conf << 'EOF'
install cramfs /bin/true
install freevxfs /bin/true
install jffs2 /bin/true
install hfs /bin/true
install hfsplus /bin/true
install squashfs /bin/true
install udf /bin/true
EOF
# 1.1.2 Ensure /tmp is a separate partition with nodev,nosuid,noexec
# /etc/fstab entry:
# tmpfs /tmp tmpfs defaults,rw,nosuid,nodev,noexec,relatime 0 0
systemctl unmask tmp.mount
systemctl enable tmp.mount
# 1.1.8 Ensure nodev option on /dev/shm
mount -o remount,nodev,nosuid,noexec /dev/shm
echo "tmpfs /dev/shm tmpfs defaults,nodev,nosuid,noexec 0 0" >> /etc/fstab
# 1.4 Secure boot settings
chown root:root /boot/grub/grub.cfg
chmod 600 /boot/grub/grub.cfg
# Set GRUB password
grub-mkpasswd-pbkdf2 # Generate hash, add to /etc/grub.d/40_custom
Step 2: Services and Network (Sections 2-3)
# 2.1 Disable unnecessary services
systemctl disable --now avahi-daemon
systemctl disable --now cups
systemctl disable --now rpcbind
systemctl disable --now xinetd
# 2.2 Ensure NTP is configured
apt install chrony -y # or systemd-timesyncd
systemctl enable --now chrony
# 3.1 Network parameters (host only, not router)
cat >> /etc/sysctl.d/99-cis.conf << 'EOF'
net.ipv4.ip_forward = 0
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.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.tcp_syncookies = 1
net.ipv6.conf.all.accept_ra = 0
net.ipv6.conf.default.accept_ra = 0
EOF
sysctl --system
# 3.4 Configure firewall (UFW or firewalld)
ufw enable
ufw default deny incoming
ufw default allow outgoing
ufw allow ssh
Step 3: Access Control (Sections 4-5)
# 5.2 SSH Server Configuration (/etc/ssh/sshd_config)
sed -i 's/#Protocol 2/Protocol 2/' /etc/ssh/sshd_config
cat >> /etc/ssh/sshd_config << 'EOF'
LogLevel VERBOSE
MaxAuthTries 4
PermitRootLogin no
PermitEmptyPasswords no
PasswordAuthentication no
X11Forwarding no
MaxStartups 10:30:60
LoginGraceTime 60
AllowTcpForwarding no
ClientAliveInterval 300
ClientAliveCountMax 3
EOF
systemctl restart sshd
# 5.3 Password policy (PAM)
# /etc/security/pwquality.conf
minlen = 14
dcredit = -1
ucredit = -1
ocredit = -1
lcredit = -1
# 5.4 User account settings
# /etc/login.defs
PASS_MAX_DAYS 365
PASS_MIN_DAYS 1
PASS_WARN_AGE 7
# Lock inactive accounts
useradd -D -f 30
Step 4: Audit and Logging (Section 4)
# Install and configure auditd
apt install auditd audispd-plugins -y
systemctl enable --now auditd
# /etc/audit/rules.d/cis.rules
cat > /etc/audit/rules.d/cis.rules << 'EOF'
-w /etc/sudoers -p wa -k scope
-w /etc/sudoers.d/ -p wa -k scope
-w /var/log/sudo.log -p wa -k actions
-a always,exit -F arch=b64 -S adjtimex -S settimeofday -k time-change
-a always,exit -F arch=b64 -S sethostname -S setdomainname -k system-locale
-w /etc/group -p wa -k identity
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /var/log/faillog -p wa -k logins
-w /var/log/lastlog -p wa -k logins
-a always,exit -F arch=b64 -S chmod -S fchmod -S fchmodat -k perm_mod
-a always,exit -F arch=b64 -S unlink -S rmdir -S rename -k delete
-w /sbin/insmod -p x -k modules
-w /sbin/modprobe -p x -k modules
-e 2
EOF
augenrules --load
# Configure rsyslog for remote logging
echo "*.* @@syslog-server.corp.com:514" >> /etc/rsyslog.d/50-remote.conf
systemctl restart rsyslog
Step 5: Assess with OpenSCAP
# Install OpenSCAP
apt install openscap-scanner scap-security-guide -y
# Run CIS benchmark assessment
oscap xccdf eval \
--profile xccdf_org.ssgproject.content_profile_cis_level1_server \
--results /tmp/cis_results.xml \
--report /tmp/cis_report.html \
/usr/share/xml/scap/ssg/content/ssg-ubuntu2204-ds.xml
# View HTML report in browser for detailed results
Key Concepts
| Term |
Definition |
| OpenSCAP |
Open-source SCAP (Security Content Automation Protocol) scanner for automated compliance |
| auditd |
Linux audit framework for monitoring system calls and file access |
| PAM |
Pluggable Authentication Modules; configurable authentication framework for Linux |
| sysctl |
Linux kernel parameter configuration for network and system security tuning |
| AIDE |
Advanced Intrusion Detection Environment; file integrity checker for Linux |
Tools & Systems
- OpenSCAP: Automated CIS benchmark assessment for Linux
- Ansible Lockdown: Ansible roles for automated CIS benchmark remediation
- Lynis: Open-source security auditing tool for Linux/Unix systems
- AIDE: File integrity monitoring for Linux endpoints
- auditd: Linux audit framework for system call monitoring
Common Pitfalls
- Applying server benchmarks to workstations: CIS provides separate benchmarks for server and workstation profiles. Server benchmarks disable desktop services.
- Breaking SSH access: Misconfiguring sshd_config (especially PermitRootLogin, PasswordAuthentication) can lock out administrators. Always test SSH configuration changes from a second session.
- Not testing firewall rules: Enabling UFW without allowing SSH first will disconnect remote sessions permanently.
- Kernel parameter changes without testing: Some sysctl settings can break application networking. Test in staging first.
1---2name: hardening-linux-endpoint-with-cis-benchmark3description: Hardens Linux endpoints using CIS Benchmark recommendations for Ubuntu, RHEL, and CentOS to reduce attack surface, enforce security baselines, and meet compliance requirements. Use when deploying new Linux servers, remediating audit findings, or establishing security baselines for Linux infrastructure. Activates for requests involving Linux hardening, CIS benchmarks for Linux, server security baselines, or Linux configuration compliance.4license: Apache-2.05---6# Hardening Linux Endpoint with CIS Benchmark
7
8## When to Use
9
10Use this skill when:
11- Hardening Linux servers (Ubuntu, RHEL, CentOS, Debian) against CIS benchmarks
12- Automating Linux security baselines using Ansible, OpenSCAP, or shell scripts
13- Meeting compliance requirements (PCI DSS, HIPAA, SOC 2) for Linux endpoints
14- Remediating findings from vulnerability scans or security audits
15
16**Do not use** for Windows hardening (use hardening-windows-endpoint-with-cis-benchmark).
17
18## Common Misconfigurations & Verification
19
20- **auditd rules edited but never loaded:** writing `/etc/audit/rules.d/cis.rules` does nothing until `augenrules --load` runs and `auditctl -l` lists them; an earlier `-e 2` (immutable) line blocks later additions until reboot. Confirm the identity/scope/perm_mod watches are live, not just on disk.
21- **sysctl applied at runtime but not persisted:** values set with `sysctl -w` revert on reboot. Verify the `/etc/sysctl.d/99-cis.conf` keys actually take effect — e.g. `sysctl net.ipv4.conf.all.rp_filter` after `sysctl --system` (some are overridden by cloud-init or a higher-numbered file).
22- **/tmp and /dev/shm options silently inactive:** `mount | grep -E '/tmp|/dev/shm'` must show `noexec,nosuid,nodev`; an fstab typo leaves the partition mounted with defaults. A line in fstab is not proof it is applied.
23- **Config drift after baseline:** re-run OpenSCAP on a schedule — a one-time pass does not catch package updates or an admin re-enabling `PasswordAuthentication`. Match the profile to the OS (`ssg-ubuntu2204-ds.xml`, `cis_level1_server`); a mismatched data stream reports false passes.
24- **Verify enforcement, not just config:** after hardening, test from a second SSH session (so a bad `sshd_config` won't lock you out), then touch `/etc/passwd` and confirm an auditd `identity` key event is generated and shipped to the remote rsyslog/SIEM.
25
26## Prerequisites
27
28- Root or sudo access on target Linux endpoints
29- CIS Benchmark PDF for target distribution (from cisecurity.org)
30- OpenSCAP or CIS-CAT for automated assessment
31- Ansible for enterprise-scale remediation (optional)
32
33## Workflow
34
35### Step 1: Filesystem Configuration (Section 1)
36
37```bash
38# 1.1.1 Disable unused filesystems
39cat >> /etc/modprobe.d/CIS.conf << 'EOF'
40install cramfs /bin/true
41install freevxfs /bin/true
42install jffs2 /bin/true
43install hfs /bin/true
44install hfsplus /bin/true
45install squashfs /bin/true
46install udf /bin/true
47EOF
48
49# 1.1.2 Ensure /tmp is a separate partition with nodev,nosuid,noexec
50# /etc/fstab entry:
51# tmpfs /tmp tmpfs defaults,rw,nosuid,nodev,noexec,relatime 0 0
52systemctl unmask tmp.mount
53systemctl enable tmp.mount
54
55# 1.1.8 Ensure nodev option on /dev/shm
56mount -o remount,nodev,nosuid,noexec /dev/shm
57echo "tmpfs /dev/shm tmpfs defaults,nodev,nosuid,noexec 0 0" >> /etc/fstab
58
59# 1.4 Secure boot settings
60chown root:root /boot/grub/grub.cfg
61chmod 600 /boot/grub/grub.cfg
62# Set GRUB password
63grub-mkpasswd-pbkdf2 # Generate hash, add to /etc/grub.d/40_custom
64```
65
66### Step 2: Services and Network (Sections 2-3)
67
68```bash
69# 2.1 Disable unnecessary services
70systemctl disable --now avahi-daemon
71systemctl disable --now cups
72systemctl disable --now rpcbind
73systemctl disable --now xinetd
74
75# 2.2 Ensure NTP is configured
76apt install chrony -y # or systemd-timesyncd
77systemctl enable --now chrony
78
79# 3.1 Network parameters (host only, not router)
80cat >> /etc/sysctl.d/99-cis.conf << 'EOF'
81net.ipv4.ip_forward = 0
82net.ipv4.conf.all.send_redirects = 0
83net.ipv4.conf.default.send_redirects = 0
84net.ipv4.conf.all.accept_source_route = 0
85net.ipv4.conf.default.accept_source_route = 0
86net.ipv4.conf.all.accept_redirects = 0
87net.ipv4.conf.default.accept_redirects = 0
88net.ipv4.conf.all.secure_redirects = 0
89net.ipv4.conf.default.secure_redirects = 0
90net.ipv4.conf.all.log_martians = 1
91net.ipv4.conf.default.log_martians = 1
92net.ipv4.icmp_echo_ignore_broadcasts = 1
93net.ipv4.icmp_ignore_bogus_error_responses = 1
94net.ipv4.conf.all.rp_filter = 1
95net.ipv4.conf.default.rp_filter = 1
96net.ipv4.tcp_syncookies = 1
97net.ipv6.conf.all.accept_ra = 0
98net.ipv6.conf.default.accept_ra = 0
99EOF
100sysctl --system
101
102# 3.4 Configure firewall (UFW or firewalld)
103ufw enable
104ufw default deny incoming
105ufw default allow outgoing
106ufw allow ssh
107```
108
109### Step 3: Access Control (Sections 4-5)
110
111```bash
112# 5.2 SSH Server Configuration (/etc/ssh/sshd_config)
113sed -i 's/#Protocol 2/Protocol 2/' /etc/ssh/sshd_config
114cat >> /etc/ssh/sshd_config << 'EOF'
115LogLevel VERBOSE
116MaxAuthTries 4
117PermitRootLogin no
118PermitEmptyPasswords no
119PasswordAuthentication no
120X11Forwarding no
121MaxStartups 10:30:60
122LoginGraceTime 60
123AllowTcpForwarding no
124ClientAliveInterval 300
125ClientAliveCountMax 3
126EOF
127systemctl restart sshd
128
129# 5.3 Password policy (PAM)
130# /etc/security/pwquality.conf
131minlen = 14
132dcredit = -1
133ucredit = -1
134ocredit = -1
135lcredit = -1
136
137# 5.4 User account settings
138# /etc/login.defs
139PASS_MAX_DAYS 365
140PASS_MIN_DAYS 1
141PASS_WARN_AGE 7
142
143# Lock inactive accounts
144useradd -D -f 30
145```
146
147### Step 4: Audit and Logging (Section 4)
148
149```bash
150# Install and configure auditd
151apt install auditd audispd-plugins -y
152systemctl enable --now auditd
153
154# /etc/audit/rules.d/cis.rules
155cat > /etc/audit/rules.d/cis.rules << 'EOF'
156-w /etc/sudoers -p wa -k scope
157-w /etc/sudoers.d/ -p wa -k scope
158-w /var/log/sudo.log -p wa -k actions
159-a always,exit -F arch=b64 -S adjtimex -S settimeofday -k time-change
160-a always,exit -F arch=b64 -S sethostname -S setdomainname -k system-locale
161-w /etc/group -p wa -k identity
162-w /etc/passwd -p wa -k identity
163-w /etc/shadow -p wa -k identity
164-w /var/log/faillog -p wa -k logins
165-w /var/log/lastlog -p wa -k logins
166-a always,exit -F arch=b64 -S chmod -S fchmod -S fchmodat -k perm_mod
167-a always,exit -F arch=b64 -S unlink -S rmdir -S rename -k delete
168-w /sbin/insmod -p x -k modules
169-w /sbin/modprobe -p x -k modules
170-e 2
171EOF
172augenrules --load
173
174# Configure rsyslog for remote logging
175echo "*.* @@syslog-server.corp.com:514" >> /etc/rsyslog.d/50-remote.conf
176systemctl restart rsyslog
177```
178
179### Step 5: Assess with OpenSCAP
180
181```bash
182# Install OpenSCAP
183apt install openscap-scanner scap-security-guide -y
184
185# Run CIS benchmark assessment
186oscap xccdf eval \
187 --profile xccdf_org.ssgproject.content_profile_cis_level1_server \
188 --results /tmp/cis_results.xml \
189 --report /tmp/cis_report.html \
190 /usr/share/xml/scap/ssg/content/ssg-ubuntu2204-ds.xml
191
192# View HTML report in browser for detailed results
193```
194
195## Key Concepts
196
197| Term | Definition |
198|------|-----------|
199| **OpenSCAP** | Open-source SCAP (Security Content Automation Protocol) scanner for automated compliance |
200| **auditd** | Linux audit framework for monitoring system calls and file access |
201| **PAM** | Pluggable Authentication Modules; configurable authentication framework for Linux |
202| **sysctl** | Linux kernel parameter configuration for network and system security tuning |
203| **AIDE** | Advanced Intrusion Detection Environment; file integrity checker for Linux |
204
205## Tools & Systems
206
207- **OpenSCAP**: Automated CIS benchmark assessment for Linux
208- **Ansible Lockdown**: Ansible roles for automated CIS benchmark remediation
209- **Lynis**: Open-source security auditing tool for Linux/Unix systems
210- **AIDE**: File integrity monitoring for Linux endpoints
211- **auditd**: Linux audit framework for system call monitoring
212
213## Common Pitfalls
214
215- **Applying server benchmarks to workstations**: CIS provides separate benchmarks for server and workstation profiles. Server benchmarks disable desktop services.
216- **Breaking SSH access**: Misconfiguring sshd_config (especially PermitRootLogin, PasswordAuthentication) can lock out administrators. Always test SSH configuration changes from a second session.
217- **Not testing firewall rules**: Enabling UFW without allowing SSH first will disconnect remote sessions permanently.
218- **Kernel parameter changes without testing**: Some sysctl settings can break application networking. Test in staging first.