Every few months someone on a security or compliance team asks the same question: "can we just run the CIS benchmark against our servers and call it done?" The honest answer is no, but understanding why requires actually knowing what a CIS Benchmark is, how it's built, and where it fits into a broader hardening program. I've applied these baselines across mixed fleets of Ubuntu, RHEL, and Windows Server boxes, and the gap between "downloaded the PDF" and "actually hardened the fleet" is where most of the real work lives.
What It Is
A CIS Benchmark is a consensus-developed configuration standard published by the Center for Internet Security, a nonprofit that pulls together input from government, industry, and academic security practitioners. There isn't one benchmark — there are hundreds, one per major operating system, database engine, cloud provider, container runtime, and application platform. There's a benchmark for Ubuntu 22.04 LTS, one for RHEL 9, one for PostgreSQL 15, one for Kubernetes, one for AWS. Each one is a document, typically hundreds of pages, listing individual recommendations: disable this kernel module, set this sysctl value, require this password complexity, restrict permissions on this file.
What makes CIS Benchmarks different from a vendor's own hardening guide is the governance model. They go through community review cycles, and each recommendation includes a rationale, an audit procedure, and a remediation procedure. That's the part people skip reading and shouldn't — the rationale tells you why the control exists, which matters enormously when you're deciding whether to apply it in your environment.
Recommendations are split into two profile levels. Level 1 is meant to be broadly applicable with minimal impact on functionality — things you can apply to nearly any server without much risk of breaking an application. Level 2 is defense-in-depth, intended for environments where security is prioritized over convenience, and it's more likely to affect compatibility or performance. A lot of teams treat Level 1 as the floor and cherry-pick from Level 2 based on their actual risk profile.
How It Works
In practice, applying a CIS Benchmark to a fleet involves three separate activities: scanning, remediation, and drift detection. They get conflated a lot, but they're distinct problems.
Scanning is the assessment phase. CIS publishes a free tool called CIS-CAT Lite (and a paid Pro version) that reads an XCCDF/OVAL-formatted version of the benchmark and checks a live system against it, producing a pass/fail report per control along with a percentage score. Open source alternatives like OpenSCAM and commercial tools like Tenable, Qualys, and Wazuh also ship CIS profiles. A typical scan run looks like this:
$ sudo cis-cat-lite.sh -b benchmarks/CIS_Ubuntu_Linux_22.04_LTS_Benchmark.xml -p "Level 1 - Server"
Assessment Results Summary
---------------------------------------------
Total Rules Assessed : 214
Pass : 168
Fail : 39
Not Applicable : 7
Score : 78.5%
FAILED CONTROLS (sample)
1.1.1.1 Ensure mounting of cramfs filesystems is disabled - FAIL
1.4.1 Ensure permissions on bootloader config are configured - FAIL
5.2.4 Ensure SSH root login is disabled - FAIL
5.3.3 Ensure password complexity requirements are configured - FAIL
Remediation is where you actually fix what the scan found. Some organizations write their own Ansible playbooks or Puppet manifests mapped to control IDs; others buy CIS-CAT Pro or a third-party tool that ships remediation scripts alongside the audit. I generally push teams toward configuration-as-code here rather than one-off shell scripts run by hand, because the third activity — drift detection — depends on it. A server hardened once and never re-checked drifts out of compliance within weeks as packages update, admins make manual changes under pressure, and new services get installed.
A minimal remediation snippet for that SSH root login failure looks like this:
- name: CIS 5.2.4 - Disable SSH root login
lineinfile:
path: /etc/ssh/sshd_config
regexp: '^#?PermitRootLogin'
line: 'PermitRootLogin no'
notify: restart sshd
Run that across the fleet with Ansible, re-scan, and your score moves. Do this for every failed control, in batches, testing on a staging tier first — because some of these changes do break things, and I'll get into that below.
Why It Matters
The obvious reason is that unhardened servers get compromised faster and more often. But the reason CIS specifically matters, as opposed to just "harden your servers however you want," comes down to three things.
First, it's a shared vocabulary. When your auditor, your cyber insurance underwriter, and your new hire on the security team all reference "CIS control 5.2.4," everyone knows exactly what's being discussed without a company-specific glossary. That matters more than it sounds like it should when you're trying to move fast during an audit.
Second, it maps cleanly onto other frameworks people actually get measured against. CIS Controls (the higher-level, org-wide framework, distinct from the OS-specific Benchmarks) map to NIST 800-53, to PCI-DSS, to ISO 27001 Annex A. If you're building toward SOC 2 or PCI compliance, showing CIS Benchmark conformance on your servers is one of the more efficient ways to satisfy configuration management control requirements, because auditors already recognize the framework.
Third, and this is the one people underrate: it removes debate. Without a baseline, hardening decisions become arguments — should we disable this, should we require that, is this too strict. CIS gives you a documented, externally validated default position with a rationale attached. You can still deviate from it, but you deviate from a defensible starting point instead of debating from zero every time.
Real-World Examples
A case that sticks with me: a team running a fleet of internal API servers on RHEL had SELinux set to permissive because a developer had flipped it years earlier to unblock a deployment and nobody ever revisited it. It's one of the more consequential Level 1 controls in the CIS RHEL benchmark. Running a CIS-CAT scan across the fleet surfaced it immediately as a fail, with the exact remediation steps attached. Re-enabling enforcing mode caught two other misconfigurations in the process — a cron job writing to a location it shouldn't have had access to, and a service running with broader file access than its actual function required. Neither would have been obvious without SELinux actually enforcing.
Another example, on the more painful side: applying the CIS Level 2 benchmark for Windows Server to a fleet supporting a legacy application. One of the recommendations restricts NTLM authentication in favor of Kerberos. Correct move from a security standpoint — NTLM relay attacks are a real and common attack path. But the legacy app had a hardcoded dependency on NTLM for a service account connection nobody had documented. Applying that control in production without staging it first took the app down for about forty minutes before the team rolled back and added an documented exception. That's the kind of thing Level 2 controls do — they're right, but they're right in a way that requires you to actually understand your environment before flipping the switch fleet-wide.
On the cloud side, I've seen the AWS CIS Benchmark used effectively as the actual ruleset behind AWS Config rules and Security Hub — controls like "ensure S3 buckets aren't publicly accessible" and "ensure CloudTrail is enabled in all regions" are lifted close to verbatim from the benchmark. When a team at solvethenetwork.com set up their landing zone, they used the CIS AWS Foundations Benchmark as the literal spec for their initial Config rule set rather than inventing their own — which saved a lot of back-and-forth about what "secure by default" should mean for their account structure.
Common Misconceptions
"100% compliance is the goal." It isn't, and chasing it is actually a bad sign. Some CIS controls conflict with legitimate operational requirements — a control that disables USB storage doesn't make sense on a server that needs it for a specific backup workflow, for instance. The right posture is to apply what fits, document exceptions with a reason, and track those exceptions deliberately rather than either ignoring the benchmark or blindly applying every line.
"A CIS score is a security score." It's a configuration compliance score against a specific checklist. A server can hit 95% CIS conformance and still be running a web application riddled with unpatched CVEs, or exposed on a network segment it shouldn't be on. Benchmarks address configuration hygiene, not patch management, application-layer vulnerabilities, or network architecture. Treat it as one input into a security posture, not the whole picture.
"CIS and STIG are the same thing, pick whichever." They overlap heavily but aren't identical. DISA STIGs (Security Technical Implementation Guides) are mandated for US Department of Defense systems and tend to be stricter and more prescriptive with less flexibility. CIS Benchmarks are broader in applicability and explicitly offer the Level 1/Level 2 split to accommodate different risk tolerances. If you're under a DoD contract, you likely need STIG, not CIS. If you're a general enterprise, CIS is usually the better fit and the two frameworks are close enough that satisfying one gets you most of the way to the other.
"Run the scan once, done." This is the one that actually causes incidents. I've seen fleets pass an audit at 90%+ conformance, then drift down to the 60s within six months because nobody wired the scan into a recurring job. Configuration drift is not hypothetical — it's the default outcome of any system that humans and automation both touch over time. A benchmark applied once and never re-verified is a snapshot of a moment in the past, not a current security posture.
"It's a solved problem once IT applies it." Hardening the OS layer doesn't cover application configuration, IAM policy, network segmentation, or logging pipelines feeding your SIEM. CIS Benchmarks exist at multiple layers for a reason — OS, database, container, cloud control plane — and most organizations only ever get around to the OS layer, leaving the rest unaddressed while believing the baseline problem is solved.
The practical takeaway, if you're starting from zero: pick the benchmark matching your OS and platform, run an initial scan to get a baseline score, triage the failures by actual risk rather than trying to fix everything at once, automate the remediation you decide to apply so it's repeatable and reviewable, and schedule recurring scans so drift gets caught before an auditor or an attacker finds it first. It's not glamorous work, but it's the kind of foundational hygiene that makes every other security control you layer on top of it actually mean something.
