linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Introduction
  • Lessons
  • How it works
  • Simulator
  • Knowledge base
  • Interview prep
Index
Categories
All entries
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
home/linux/kb/Security/cis-benchmark-hardening

kb/security ── Security ── advanced

CIS Benchmark and system hardening (lynis, OpenSCAP)

CIS Benchmark is the Linux hardening standard. Lynis is a fast local audit with a score, OpenSCAP is the formal one with XCCDF profiles and a SCAP report. ansible-lockdown remediates. Keep audit and remediate separate.

view as markdownaka: cis, cis-benchmark, lynis, openscap, ansible-lockdown, hardening

What a CIS Benchmark is

The Center for Internet Security (CIS) is a non-profit organization that publishes Benchmarks, hardening guidelines for each platform: RHEL 9, Ubuntu 22.04, Kubernetes, AWS, Docker, and so on.

A Benchmark is an 800 to 1000 page PDF with numbered recommendations:

1.1.1.1 Ensure mounting of cramfs filesystems is disabled (Automated)
Profile: L1 Server, L1 Workstation
Description: ...
Rationale: ...
Audit: modprobe -n -v cramfs | grep "^install /bin/false"
Remediation: echo "install cramfs /bin/false" >> /etc/modprobe.d/cramfs.conf

Each recommendation says what to check, why, how to audit it, and how to remediate. They split into:

  • L1 (Level 1) is the baseline, with no loss of functionality. It targets most production servers.
  • L2 (Level 2) is paranoid and can break legacy. It targets high-security environments.
  • Server vs Workstation profiles have different priorities (for example, you do not need X11 on a server).
  • Automated vs Manual says whether a scanner can check it automatically.

You download it after registering on cisecurity.org. It is free, and the license covers reading and use, not rebranding.

Why it matters

  • Compliance: PCI-DSS, HIPAA, and SOC 2 all require some baseline. CIS is the most understandable and the most widely accepted.
  • Reduce attack surface: strip SUID bits from binaries that do not need them, disable unneeded services, restrict kernel modules.
  • Defense in depth: it sits between AppArmor/SELinux at the application level and the firewall on the network.

Alternative standards

StandardWhoWhere it applies
CIS BenchmarkCIS (industry)universal, the basis of compliance
STIGDISA (US DoD)US government sector
DISA SRGDISAcontainers, cloud
NIST SP 800-53NISThigh-level controls, not a recipe
PCI-DSSCard industrywherever cards are processed

They often interlock: CIS maps to a PCI control. An auditor wants to see the Benchmark plus the scan result.

lynis, quick audit

A Bash script from CISOfy that runs locally, rates hardening against about a hundred heuristics, and produces a hardening index (0 to 100):

bash
sudo lynis audit system
# Hardening index : 67
# Tests performed : 263
# Plugins enabled : 0

It checks the PAM config, sudo settings, [[ssh-hardening|sshd]], the firewall, mount options, kernel parameters, world-writable files, and outdated software.

The output gives Suggestions and Warnings linked to docs. It is more for the developer-admin (see quickly what is wrong) than for a compliance report.

bash
# Only a specific section
sudo lynis audit system --tests-from-group "kernel,filesystems"
# Cron for regular auditing
0 2 * * * /usr/sbin/lynis audit system --cronjob > /var/log/lynis.log

Downsides: the score is subjective, it is not tied to a specific standard, and it is bash-only (no remediation).

OpenSCAP, formal compliance

The SCAP (Security Content Automation Protocol) standard from NIST is an XML format for describing checks, configs, and vulns. OpenSCAP is the open-source implementation.

It uses:

  • XCCDF (eXtensible Configuration Checklist Description Format) for the profile description (the recommendations)
  • OVAL (Open Vulnerability Assessment Language) for how to check
  • CPE (Common Platform Enumeration) for which platforms apply

Ready-made profiles come from scap-security-guide (SSG), with RHEL/Ubuntu/Debian and CIS / STIG / PCI / HIPAA mappings.

bash
# install
dnf install scap-security-guide openscap-scanner
# list of profiles
oscap info /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml
# audit against CIS L1 Server
oscap xccdf eval \
  --profile xccdf_org.ssgproject.content_profile_cis_server_l1 \
  --report /tmp/cis-report.html \
  --results /tmp/cis-results.xml \
  /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml

The artifact is an HTML report with pass/fail for each rule, plus XML with machine-readable results for a compliance system.

Auto-remediate (with caution)

OpenSCAP can generate a remediation script:

bash
oscap xccdf generate fix \
  --profile xccdf_org.ssgproject.content_profile_cis_server_l1 \
  --output remediate.sh \
  /tmp/cis-results.xml

Never run it blindly in production. Read the script with your own eyes:

  • It may regenerate SSH keys and break your current access
  • It may tighten sudo and stop automation accounts from working
  • It may enable SELinux, and applications that are not ready will fall over

The approach: stage it (dev to staging to prod), exclude inappropriate rules, document the exceptions.

ansible-lockdown, Ansible playbooks

Ready-made Ansible roles for CIS/STIG across different distros:

ansible-lockdown/RHEL9-CIS
ansible-lockdown/UBUNTU22-CIS
ansible-lockdown/RHEL9-STIG

Each rule is a separate task with a tag (rule_1.1.1.1). You can enable or disable them through pre-tasks:

yaml
vars:
  rhel9cis_rule_1_1_1_1: true             # cramfs disable
  rhel9cis_rule_1_1_1_2: false            # squashfs, keep it
  rhel9cis_firewall: nftables             # firewall choice

This is a production-ready way to apply CIS: versioned, idempotent, testable. Combine it with GitOps.

What you must check (short list)

If you do not have time for the full CIS, the minimum is:

  1. SSH: keys only, no root login (see ssh-hardening)
  2. firewall: default-deny, allowlist (see firewalld-vs-nftables)
  3. sudo: not NOPASSWD by default, audited through [[auditd|auditd]]
  4. PAM: pam_faillock (which replaced the deprecated pam_tally2), pam_pwquality (see pam)
  5. Mount options: nodev/nosuid/noexec on /tmp and /dev/shm
  6. Sysctl: kernel.kptr_restrict=1, kernel.dmesg_restrict=1, net.ipv4.conf.all.rp_filter=1
  7. Kernel modules: disable unused ones (cramfs, freevxfs, jffs2, udf)
  8. Auditd rules: execve, identity changes, file changes in /etc
  9. Updates: unattended-upgrades at least for security
  10. Logging: centralized syslog, retention of 90 or more days

Container / Kubernetes hardening

CIS publishes separate Benchmarks for:

  • Docker: daemon config, image build, runtime
  • Kubernetes: control plane, node, RBAC, network
  • EKS / GKE / AKS: cloud-specific

Tools:

  • docker-bench-security, a bash script for CIS Docker
  • kube-bench (Aqua), a CIS Kubernetes audit. It runs as a Job in the cluster and produces a report
  • kube-hunter, a penetration-style scanner for k8s
bash
kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml
kubectl logs -l job-name=kube-bench

Drift and continuous compliance

A one-time hardening does not work. Within a month someone will disable a rule, add a SUID binary, or weaken sudoers. The fix is continuous compliance:

  • Cron lynis --cronjob or oscap daily, alert when the score drops below a threshold
  • A compliance platform (Wazuh, Tenable, Rapid7) centralizes it
  • GitOps infrastructure, changes only through a PR

When things go wrong

  • oscap fails with a timeout: a slow disk, or the OVAL content includes a full-fs scan. You can exclude sections with --remediate.
  • Lynis reports a Hardening Index of 30: this is subjective. Do not panic, read through the specific Suggestion entries.
  • SSH does not work after applying a CIS role: it is typically disabled by ip-list. Use an out-of-band console (IPMI/serial) and roll back through ansible.
  • Auto-remediate broke cron: a common case where nodev,noexec on /tmp breaks scripts that write there. Exclude with ansible skip_tags.
  • A compliance scan does not see a rule as fixed: the change happened in runtime, but the /etc/... config was not updated. The scan reads the file, not runtime state.
  • CIS requires Ensure /tmp is on separate partition: on a cloud instance with a single disk this is painful. The alternative is a bind-mount in the systemd tmp.mount.
  • STIG contradicts the application docs: a common case with proprietary software. Document the exception and put in a compensating control.

What not to do

  • Do not run remediation blindly in production: always read the script first
  • Do not chase 100% CIS: some rules do not apply, and a documented exception beats forced compliance
  • Do not harden just once: it degrades over months without monitoring
  • Do not confuse audit and remediate: they are two different operations, and you can audit without modifying

§ команды

bash
sudo lynis audit system

Full node audit in one command: the hardening index and the list of Suggestions

bash
sudo lynis audit system --cronjob > /var/log/lynis.log

Non-interactive mode for cron: regular monitoring

bash
oscap info /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml

List the profiles available in the SCAP content for the distro

bash
oscap xccdf eval --profile cis_server_l1 --report report.html /usr/share/xml/scap/ssg/content/ssg-rhel9-ds.xml

Audit against the CIS L1 Server profile with an HTML report for the compliance auditor

bash
ansible-playbook -i inventory rhel9cis.yml --tags level1-server --check

Dry-run remediate through ansible-lockdown: shows what will change

bash
kubectl apply -f https://raw.githubusercontent.com/aquasecurity/kube-bench/main/job.yaml && kubectl logs -l job-name=kube-bench

kube-bench audit of a Kubernetes cluster against the CIS K8s benchmark

bash
find / -perm -4000 -type f 2>/dev/null

All SUID binaries in the system: a quick audit of excess privileges

§ см. также

  • ssh-hardeningSSH hardening: locking down the serverSSH hardening: keys only (PasswordAuthentication no), disable root login, AllowUsers/AllowGroups, MaxAuthTries, a fail2ban jail on sshd. Optionally a custom port plus Match blocks for guests.
  • auditdauditd: syscall and file auditauditd writes kernel events to /var/log/audit/audit.log: file watches (-w), syscall rules (-a), execs. Use ausearch to search, aureport for reports. This is the basis of compliance (PCI-DSS, HIPAA, FZ-152).
  • selinux-policySELinux policy: types, domains, audit2allowSELinux: every process has a domain, every object has a type. The policy defines which domains may do what to which types. audit2allow generates rules from AVC denials, semanage tunes, and .pp files are policy modules.
  • firewalld-vs-nftablesfirewalld vs nftables: what to choosefirewalld is a daemon wrapper with zones, services, and rich rules; the backend since RHEL 8 is nftables. Plain nft gives more control, sets, and atomic reload. firewalld fits desktop and multi-zone, nft fits a server fleet.
  • pamPAM: Pluggable Authentication ModulesPAM is the authentication framework in Linux. Programs (sudo, login, sshd) do not check passwords themselves. They call PAM, which decides whether to let you in through a stack of modules in `/etc/pam.d/<service>`.
Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies