July 23, 2021

Why Use CIS Benchmarks? How to Enforce CIS Benchmarks

Security & Compliance
How to & Use Cases

CIS benchmarks are important for security and compliance. In this blog, you'll get an overview, plus learn how to enforce CIS benchmarks with Puppet.

Table of Contents:


What Are the CIS Benchmarks?

The CIS benchmarks are globally-recognized benchmarks for implementing and managing cybersecurity. 

CIS (Center for Internet Security) is a non-profit organization that aims to develop a best practice in relation to cyber security. The CIS benchmarks have been adopted by many organizations as the standard against which to measure their systems.

You can download a copy of the CIS standards for free from CIS Security; if you do, you'll see the high number of benchmarks. For example, for CentOS, there are 186 separate tests for the basic server benchmark.

Why Use CIS Benchmarks?

CIS uses a consensus-driven approach to develop its benchmarks.This two-step process starts with cybersecurity and system experts, who define, review and test the recommendations. Once consensus is reached, feedback is accepted from a wider range of cybersecurity professionals from around the world.

This process ensures that the benchmark is truly a best practice that has been well-refined and tested to ensure security and compliance.

Comply With Regulations

CIS benchmarks align with many of the major regulations that are required for various industries.

With so many different regulations to keep up with, it’s no wonder that companies fall behind in compliance. CIS has aligned its benchmarks against many regulatory frameworks, enabling companies to utilize the benchmarks to gain best practices from CIS that help them achieve CIS compliance against the regulations that apply to them.

Globally Recognized

CIS Benchmarks are globally recognized and accepted.

The CIS Benchmarks are accepted by government, business, industry and academia globally. According to Dilligent Insights, “CIS draws members from a range of backgrounds including private companies, government, and research institutions” and “provides a range of tools, resources and programs to enable best-practice IT governance within organizations and government.” With over 100 benchmarks in 14 technology groups, organizations can be sure their security and compliance needs are covered!

CIS Benchmark Tool: Puppet Comply

Puppet Comply can be your CIS benchmark tool. It utilizes the CIS-CAT pro scanner to assess your IT infrastructure against the CIS benchmarks so you can get a clear view of your overall compliance. Puppet recognizes that CIS is the gold standard and when developing our continuous compliance solution, partnering with CIS was the right move for our customers. Pairing CIS benchmarks with Puppet’s powerful automation capabilities goes a long way towards a more compliant and secure infrastructure.

How to Enforce CIS Benchmarks With Puppet

If you were to go away and start writing Puppet code to apply all those rules, your colleagues would not see you for a long time! Fortunately a lot of the work has already been done in the Puppet Forge module fervid/secure_linux_cis. We're going to take a look at how you can quickly apply the server level 1 CIS benchmark.

What Does the secure_linux_cis Module Actually Give Us?

  1. The first thing the Secure Linux CIS Module gives us is the CIS benchmarks as rule sets, so if we want to apply the server level 1 benchmark we can just use that rule set to get all the CIS rule numbers.

  2. The Secure Linux CIS Module maps each CIS rule number to a rule name via a class.

  3. The Secure Linux CIS Module provides a class that implements all those individual rule classes.

How Are We Going to Apply the secure_linux_cis Module?

We could just add the class to a node's classification and we'd get the full CIS benchmark applied, but what happens if you're running an online business? Shutting down our Squid Proxy (rule 2.2.13) on your web servers might be a bit of a disaster.

What if your developers like to access their systems via a desktop interface? If we disable X11 forwarding (rule 5.2.4) in development we could cause them a problem, but we don't want it enabled in production.

And what if the company standard for file sharing is Samba (rule 2.2.12)?

How Are We Going to Apply the secure_linux_cis module Without Breaking Everything?

We're going to need to apply some customizations. It might be tempting to copy the module and start customizing the code directly, but that'll give us a headache when a new version is released. We'll leave the module intact and add an abstraction layer, a profile.

The module already uses Hiera as a parameter lookup so it makes sense for us to do the same. We could put everything into our control-repo Hiera and leverage our current hierarchy, but we're going to do something different (reasons explained later). Instead, we're going to create a profile module (as opposed to a component module). We’ll call our new module cis_profile; it’s a catchy name that tells us exactly what it does. This module is going to be the location for all our Hiera data. You can only do this with version Hiera 5 or later.

The CIS module uses its own Hiera lookup to get the CIS rule set for any given operating system and passes it as a parameter to the class that implements the rules. We could copy that rule set and customize it for each application or environment, but that would give us a few problems.

  1. If we modify that rule set, we can't continue to call it a CIS rule set; it's now our own customized rule set.
  2. It's not a very layered approach. In our original example, we want a set of rules for our web server in production and a few less rules in development. We're not really taking advantage of Hiera.
  3. How do we track what rules we've removed? The security team is going to be asking not what CIS rules are we applying, but what rules we're not applying -- and more importantly, why.

fervid/secure_linux_cis helps us out here because it has exclude rules. This means we can apply the CIS benchmark to everything as defined in the module, then our implementation of the module can provide the exclude rules. We can exclude the HTTP proxy rule on our web servers and exclude the X11 rule in development. Instead of a big list of rules we're applying, we should have a very short list of rules we're not applying.

Let's take our original example of Squid, X11 and Samba. How might that look as a set of exclude rules in hiera?

First we need to configure the Hiera strategy our module is going to use. Unlike looking up an NTP server IP address, we don't want it to stop looking at the first positive result. We want to collect all the rules we want to exclude. We also don't want any duplicates so a unique merge is going to be the strategy for us; we can specify that in cis_profile/data/common.yaml. We also have that company-wide requirement to enable Samba, so we can put that in common.yaml too so everything gets that exclusion.

    merge: unique

# 2.2.12 Ensure Samba is not enabled (Scored)
# Excluded to allow company wide file share system.
  - secure_linux_cis::distribution::centos7::cis_2_2_12

Next we want to add an exclusion for X11 forwarding in development so we'll put that in cis_profile/data/environment/development.yaml.

# 5.2.4 Ensure SSH X11 forwarding is disabled (Scored)
# Enabled in development for debugging.
  - secure_linux_cis::distribution::centos7::cis_5_2_4

Finally, we want to allow HTTP proxy on our web server cis_profile/data/nodes/apache01.example.com.yaml.

# 2.2.13 Ensure HTTP Proxy Server is not enabled (Scored)
# See Security exception number:1234
  - secure_linux_cis::distribution::centos7::cis_2_2_13

We'll need to create a hierarchy that'll use facts on our machines to collect all those exclusions, starting with our common ones, the ones for our environment, and finally the ones for a specific node so our cis_profile/hiera.yaml will look something like this.

version: 5

  datadir: 'data'
  data_hash: 'yaml_data'

  - name: 'Node'
    path: "nodes/%{::trusted.certname}.yaml"

  - name: 'environment'
    path: "environment/%{::environment}.yaml"

  - name: 'common'
    path: 'common.yaml'

Finally, we're going to need a class, cis_profile/manifests/init.pp; it'll get all the exclude rules Hiera found for us and pass them into fervid/secure_linux_cis via $exclude_rules.

class cis_profile (
  Enum['firewall', 'firewalld']           $firewall_package        = 'firewalld',
  Enum['1', '2']                          $enforcement_level       = '1',
  Array[String]                           $exclude_rules           = [],
  class {'::secure_linux_cis':
    time_servers      => ['time1.google.com', 'time1.google.com'],
    profile_type      => 'server',
    allow_users       => ['centos'],
    firewall_package  => $firewall_package,
    enforcement_level => $enforcement_level,
    exclude_rules     => $exclude_rules,

Apply It to a Node

I have a node which passes all the server_level_1 checks so I'll go in and make the following changes:

  • Enable Squid
  • Enable Samba
  • Make /etc/crontab world read/write and make it owned by the centos user.
  • Edit /etc/ssh/sshd_config and set X11Forwarding to yes

Then I'll run Puppet; here's what we get:

[root@apache01 ~]# puppet agent -t
Info: Using configured environment 'production'
Info: Retrieving pluginfacts
Info: Retrieving plugin
Info: Retrieving locales
Info: Loading facts
Info: Caching catalog for apache01.example.com.yaml
Info: Applying configuration version 'peserver-production-b96c97c9a3b'
Notice: /Stage[main]/Secure_linux_cis::Rules::Ensure_permissions_on_etc_crontab_are_configured/File[/etc/crontab]/owner: owner changed 'centos' to 'root' (corrective)
Notice: /Stage[main]/Secure_linux_cis::Rules::Ensure_permissions_on_etc_crontab_are_configured/File[/etc/crontab]/group: group changed 'centos' to 'root' (corrective)
Notice: /Stage[main]/Secure_linux_cis::Rules::Ensure_permissions_on_etc_crontab_are_configured/File[/etc/crontab]/mode: mode changed '0777' to '0600' (corrective)
Notice: Applied catalog in 0.08 seconds

This is my development web server so we've got the exceptions above in place, we can see Samba, Squid and the sshd configuration were not touched, but there is no exception for the crontab rules so the CIS module has corrected its permissions and ownership.

So, That Good Reason for Using a Profile Module...

Because of the way we've implemented the exclude rules, Hiera now only contains our exceptions. It also tells us exactly where those exceptions are, what server they are on, which environment they are in, etc. Our Hiera data has become our CIS audit document and it's not hidden amongst any other data like NTP server IP addresses or public ssh keys.

This is all related to security. A standard change control board may not be appropriate. Pulling this data out of the control-repo allows us to have a very specific set of approvers for changes. We don't even need to use Hiera, we could use a different backend such as a CMDB to provide our exclude rules. In fact, we could hand this entire profile to our security team to maintain.

Getting Started

As I said at the start, there are 186 server_level_1 tests for a CentOS 7 machine. Some of those tests have dependencies; for example, the contab test requires puppetlabs/cron. You may be using a different cron module or even have written your own. You're also likely to find some things are already managed in your own baseline and that's going to give a duplicate resource declaration error. This can add up to a screen full of errors that can be overwhelming but a simple strategy to get started can help you out. Copy the entire server_level_1 test list into your exclude list. It sounds a bit excessive, but there is some logic in there.

You're now applying the CIS standard and you now have a list of all the standards you're not enforcing. It's not a bad place to be on day 1 of CIS enforcement.

Now you have your exclude list that you can work through, removing the tests you want to enforce.

Careful, There Is a Little Gotcha

If you find yourself scratching your head after modifying the exclude list, running

puppet agent -t

and not seeing any changes, don't worry. Some of the tests eat up a not insignificant amount of CPU during the enforcement, so there is a scheduler that by default only applies the module once every hour. For testing you may want to add the following to your Hiera lookup with some more suitable values:

  period: hourly
  repeat: 2

These parameters are passed to the Resource Type: schedule.

Learn more

Not Using Puppet Yet?

Get started with your free trial of Puppet Enterprise today.



This blog was originally published in two parts on March 9, 2021 and July 23, 2021. It has since been consolidated and updated for relevance.