Forge Home
Premium module


Compliance Enforcement Module for Linux


258 latest version

Version information

  • 1.9.1 (latest)
  • 1.9.0
  • 1.8.0
  • 1.7.1
  • 1.7.0
  • 1.6.3
  • 1.6.2
  • 1.6.1
  • 1.6.0
  • 1.5.2
  • 1.5.1
  • 1.5.0
  • 1.4.3
  • 1.4.2
  • 1.4.1
  • 1.4.0
  • 1.3.2
  • 1.3.1
  • 1.3.0
  • 1.2.0
  • 1.1.4
  • 1.1.3
  • 1.1.2
  • 1.1.1
  • 1.1.0
  • 1.0.0
released Mar 16th 2022
This version is compatible with:
  • Puppet Enterprise 2023.2.x, 2023.1.x, 2023.0.x, 2021.7.x, 2021.6.x, 2021.5.x, 2021.4.x, 2021.3.x, 2021.2.x, 2021.1.x, 2021.0.x, 2019.8.x
  • Puppet >= 6.23.0 < 8.0.0
  • ,
This module has been deprecated by its author since May 8th 2024.

The author has suggested puppetlabs-sce_linux as its replacement.

  • audit_authselect
  • audit_duplicate_gid
  • audit_duplicate_group_names
  • audit_duplicate_uid
  • audit_duplicate_user_names
  • audit_etcpasswd_groups
  • audit_pw_change_date
  • and 15 more. See all tasks


puppetlabs/cem_linux — version 1.1.2 Mar 16th 2022



Table of Contents


The cem_linux module is one of two Compliance Enforcement Modules (CEM). These are supported Puppet modules developed specifically to bring your Puppet Enterpirse (PE) managed nodes under compliance. CEM currently supports CIS (Center for Internet Security) compliance rules, and other compliance frameworks will be added to CEM in the future.

By default, CEM enforces CIS rules for the level 1 server profile.

This README walks you through installing CEM and customizing the configuration settings to suit your own compliance needs. For a list of available parameters, see the CEM reference.

To manage Windows nodes, navigate to cem_windows.


System requirements

cem_linux supports the following operating systems and CIS benchmarks:

Operating system Framework Level Profile
Red Hat Enterprise Linux 7 CIS benchmarks v3.1.1 1 Server
Red Hat Enterprise Linux 8 CIS benchmarks v1.0.1 1, 2 Server
CentOS Linux 7 CIS benchmarks v3.1.1 1 Server

Install CEM with Code Manager

Puppet Forge Premium Content has specific installation instructions found here.


By default, CEM enforces CIS rules for the level 1 server profile — based on default acceptable values for each CIS recommendation. However, sometimes enforcing these values can leave your nodes in an undesirable state. In these situations, you can customize how CEM enforces the rules and tailor them to your own compliance needs.

Important: CEM's default settings are fully CIS compliant — too much customization can result in your configurations being noncompliant.

Finding and setting configuration options

You can find configuration options in the class *.pp file. For example, in the manifests/benchmarks/cis/controls/ensure_at_is_restricted_to_authorized_users.pp file below, you can can see the optional parameters in the comments:

# @api public
# @param [Boolean] enforced
#   If yes, the control will be enforced
# @param [Hash] config
#   Options for the control
# @option config [Boolean] purge_at_deny
# @option config [Boolean] set_at_allow_perms
# @option config [Array[String[1]]] at_allowlist
# @see cem_linux::utils::packages::linux::at

You can set these configuration options in Hiera using the following format:

cem_linux::benchmark: '<benchmark code>'
  <config options>

For example, configuring the options purge_at_deny, set_at_allow_perms and at_allowlist would look like:

# control-repo/data/common.yaml
cem_linux::benchmark: 'cis'
  profile: 'server'
  level: '1'
      purge_at_deny: true
      set_at_allow_perms: true

You can find all the configuration options in the

Top-level configuration options

The configuration options are configured at the top-level of the module. If configuring with Hiera, these options will be prefixed with cem_linux::

  • benchmark - Enum['cis'] - the compliance framework to use. CEM only supports cis. Default: cis.
  • config - Optional[Hash] - where all non-top-level configuration options live. Default: undef.
  • allow_on_kubernetes_node - Boolean - If cem_linux detects that it is running on a Kubernetes cluster node or host, it will not enforce any rules. It will log a warning stating such. This is to prevent accidentally enforcing incorrect compliance settings that can render Kubernetes non-functional. Default: false.
  • regenerate_grub2_config - Boolean - Some configurations in CEM for Linux modify the Grub2 bootloader configuration. If you would like to regenerate the Grub2 configuration after applying a change, set this parameter to true. If you do not set this to true, you will need to manually regenerate the Grub2 configuration. Default: false.
  • set_grub2_password - Boolean - Set the password for the Grub2 bootloader. If you set this to true, you must also set the grub2_superuser and grub2_superuser_password parameters, or configure the specific bootloader password control via control_configs. Default: false.
  • grub2_superuser - Optional[String[1]] - The superuser for the Grub2 bootloader if you set set_grub2_password to true. Default: Undef
  • grub2_superuser_password - Optional[Sensitive[String]] - The superuser password for the Grub2 bootloader if you set set_grub2_password to true. This value is sensitive, and should be stored in a Sensitive datatype. Default: Undef.

Top-level configuration options Hiera example

The below example configures CEM for Linux to regenerate the Grub2 bootloader config on a node using the CIS benchmark.

cem_linux::benchmark: 'cis'
cem_linux::allow_on_kubernetes_node: false
cem_linux::regenerate_grub2_config: true

General configuration options

These options are available as key-value pairs within the cem_linux::config: hash.

  • only: - Optional[Array[String]] — takes an array of control class names (manifests/benchmarks/<benchmark>/controls/*.pp) — classes specified here are included in the catalog. Takes precedence over ignore:. Default: undef.
  • ignore: - Optional[Array[String]] — takes an array of control class names (manifests/benchmarks/<benchmark>/controls/*.pp). The classes specified here are not included in the catalog. If only: is specified, this option does nothing. Default: undef.
  • control_configs - Optional[Hash] — where all rule-specific configurations live. Default: undef.

CIS configuration options

These options are available as key-value pairs within the cem_linux::config: hash.

  • profile: - Optional[Enum['server', 'workstation']] — the name of the benchmark profile. CEM only supports server. Default: server.
  • level: - Optional[Enum['1', '2']] — the name of the profile level. CEM only supports 1. Default: 1.
  • firewall_type: - Optional[Enum['iptables', 'firewalld', 'unmanaged']] — the preferred firewall provider. If set to unmanaged, CEM will not enforce any firewall-related rules. Default: firewalld.

Red Hat Enterprise Linux 8-specific CIS configuration options

  • use_authselect: - Optional[Boolean] - Whether to use authselect to manage most authentication options. Defaults to false. For more information, see Using authselect
  • authselect_profile - Optional[String] - If using authselect, you must specific an authselect profile with this option. Defaults to undef. For more information, see Using authselect

Control classes

Control classes (manifests/benchmarks/<benchmark>/controls/*.pp) are the interfaces that configure rule settings. Each control class accepts the following two parameters:

  • The $enforced (Boolean) parameter — this toggles whether the included code in the manifest is executed.
  • The $config parameter — this holds the configuration options for a control class as keys in the hash. You set the $config parameter based on values from the control_configs hash. Each top-level key is a control class name (sans path and .pp suffix) and the value of that key is a hash. The keys of the sub-hash map 1 to 1 with the configuration options available in the specific control class.

For example, the control class would look like:

class cem_linux::benchmarks::cis::controls::super_cool_class (
  Boolean $enforced => true,
  Boolean $config => {},
) {
  if $enforced {
    class { 'cem_linux::utils::super_cool_util':
      param_one => dig($config, 'param_one'),
      param_two => dig($config, 'param_two'),

And the Hiera file would look like:

      param_one: 'Dude'
      param_two: 'Sweet'

For a list of control classes and their configuration options, see the reference.

Configuration examples

To see what CEM looks like in production, see the configuration examples below.

Basic configuration example

When you specify a compliance framework, CEM is configured to provide rule enforcement and configuration for that framework. For example, to enforce the CIS Server Level 1 benchmark for a node, you need to classify the node with the CEM class, set the framework parameter to cis, and run Puppet.

In the following example, CEM enforces the CIS level 1 server recommendations "Ensure AIDE is installed" and "Ensure filesystem integrity is regularly checked" on a CentOS 7 node.

  1. Add the following Hiera data to your control repo:
# control-repo/data/nodes/<node name>.yaml
cem_linux::benchmark: 'cis'
  profile: 'server'
  level: '1'
    - 'ensure_aide_is_installed'
    - 'ensure_filesystem_integrity_is_regularly_checked'
  1. Classify the node with the class cem_linux.
  2. Run Puppet.

Some CIS recommendations require you to run a Bolt task. The output of a Puppet run for the debug logs tell you which task to run.

Advanced configuration example

Building on the basic configuration example, the following example customizes the AIDE configuration file in Hiera.

  1. Add the following code to the node's Hiera file:
# control-repo/data/nodes/<node name>.yaml
cem_linux::benchmark: 'cis'
  profile: 'server'
  level: '1'
    - 'ensure_aide_is_installed'
    - 'ensure_filesystem_integrity_is_regularly_checked'
        - 'PERMS = p+u+g+acl+xattrs'
        - 'CONTENT_EX = sha256+ftype+p+u+g+n+acl+xattrs'
        - '/root/\..* PERMS'
        - '/root/   CONTENT_EX'
  1. Classify the node with the class cem_linux.

  2. Run Puppet.

  3. Run the Bolt task specified in the debug log.

The AIDE configuration file now reflects the changes in Hiera.

Enforcing bootloader configurations

Warning: The only bootloader supported by CEM for Linux is grub2.

CEM for Linux enforces various bootloader configurations as required by the selected compliance framework and benchmark. However, since changes to bootloader configurations can be potentially dangerous, CEM for Linux has opted for a light-touch by default.

For CIS, there are several recommendations that modify the bootloader config. If you run CEM for Linux with completely default settings, these changes will be applied, but the bootloader config will not be regenerated. This means that while there are pending changes on the node, nothing about how the bootloader works has actually changed until the configurations are regenerated. The exception to this is the bootloader password, which is not set by default. Below are examples of how you can have CEM for Linux automatically regenerate the bootloader config and how you can set a bootloader password.

Regenerating bootloader configs automatically
# control-repo/data/nodes/<node name>.yaml
cem_linux::regenerate_grub2_config: true
Setting a bootloader password
# control-repo/data/nodes/<node name>.yaml
cem_linux::regenerate_grub2_config: true
cem_linux::set_grub2_password: true
cem_linux::grub2_superuser: 'root'
cem_linux::grub2_superuser_password: 'password'
    convert_to: 'Sensitive'

Notice: The key cem_linux::grub2_superuser_password must be the type Sensitive[String]. Setting a lookup option for that key to convert it to Sensitive is the best way to ensure that the value is a Sensitive[String]. Warning: It IS NOT recommended to store plain-text passwords in Hiera. Using something like hiera-eyaml is a better way to store secrets.

Using authselect

Warning: You SHOULD NOT enable authselect on a node if it is already joined to an Active Directory domain or to Red Hat Identity Management (idM). Enabling authselect on these nodes will break your current authentication configurations. Notice: authselect is only supported on Red Hat Enterprise Linux 8 at this time.

By default, cem_linux uses standard PAM rules to configure the authentication controls specified by CIS. However, if you are enforcing CIS compliance on Red Hat Enterprise Linux 8, CIS prefers that authselect be used. Configuring and using authselect in cem_linux is easy, but requires a specific style of configuration. Below is an example configuration for enabling authselect on a node using the minimal system default profile:

# control-repo/data/nodes/<node name>.yaml
  use_authselect: true
  authselect_profile: 'minimal'

To use authselect, you must first set the config option use_authselect to true. Next, you must specify an authselect profile with the config option authselect_profile. Both of the options must be set directly in the cem_linux::config hash for authselect to work properly.

Custom authselect profiles

Creating and using custom authselect profiles is easy in cem_linux: simply prefix the profile name in authselect_profile with custom/. If the custom profile does not exist on the node, it will automatically be created for you. Below is an example of creating and using a custom profile, my_custom_profile, that is based off of the system profile minimal with some extra features enabled:

# control-repo/data/nodes/<node name>.yaml
  use_authselect: true
  authselect_profile: 'custom/my_custom_profile'
      custom_profile_base: 'minimal'
        - with-faillock
        - with-mkhomedir
Configuring authselect

All authselect configurations are managed via the control class create_custom_authselect_profile, whether you are using a custom profile or not. See the reference for all configuration options.

Authselect and PAM

At this time, using authselect and PAM are mutually exclusive.

Configuring custom logrotate rules

The following example creates custom logrotate rules for the primary Puppet server's puppetserver logs.

# control-repo/data/nodes/<your puppetserver>.yaml
            - '/var/log/puppetlabs/puppetserver/puppetserver.log'
            - '/var/log/puppetlabs/puppetserver/pcp-broker.log'
            - '/var/log/puppetlabs/puppetserver/puppetserver-access.log'
            - '/var/log/puppetlabs/puppetserver/puppetserver-daemon.log'
            - '/var/log/puppetlabs/puppetserver/puppetserver-status.log'
            - '/var/log/puppetlabs/puppetserver/code-manager-access.log'
            - '/var/log/puppetlabs/puppetserver/file-sync-access.log'
            - '/var/log/puppetlabs/puppetserver/masterhttp.log'
          create_owner: 'puppet'
          create_group: 'puppet'

Configuring sudo without a password

The following example configures the admins group to grant sudo access without a password.

cem_linux::benchmark: 'cis'
  profile: 'server'
  level: '1'
      package_ensure: 'installed'
              - 'NOPASSWD:'

Configuring user SSH keys

The following example configures SSH keys.

cem_linux::benchmark: 'cis'
  profile: 'server'
  level: '1'
      permit_root_login: 'yes'
          username: testuser1
          home_dir: /home/testuser1
          ssh_key: ssh-rsa A...ZcTFw== rsa-key-20201022
          username: testuser2
          home_dir: /home/testuser2
          ssh_key: ssh-rsa A...ZcTFw== rsa-key-20201022

Configuring SSH allowed and denied users and groups

The following example configures SSH with allowed users / groups and denied users / groups.

cem_linux::benchmark: 'cis'
        - testuser1
        - the_dude
        - testgroup1
        - goonies
        - testuser2
        - the_emperor
        - testgroup2
        - legion_of_doom

Configuring the firewall type

The following examples configure the firewall.

firewalld is default:

cem_linux::benchmark: 'cis'
  profile: 'server'
  level: '1'
  firewall_type: 'firewalld'

You can also configure iptables:

cem_linux::benchmark: 'cis'
  profile: 'server'
  level: '1'
  firewall_type: 'iptables'

You can also configure unmanaged. When you set firewall_type to unmanaged, CEM does not enforce state on any firewall resource. Use unmanaged if you do not want CEM to configure your firewalls.

cem_linux::benchmark: 'cis'
  profile: 'server'
  level: '1'
  firewall_type: 'unmanaged'

Rules that rely on specific site information

There are some CIS rules that require site specific information. You can use Bolt tasks to configure these.

Bolt tasks in Puppet Enterprise (PE)

Using PE, you can run Bolt tasks and plans to audit or configure specific parts of a node. These are available under Tasks in the PE console — search the drop down menu for cem_linux tasks.

Run Bolt tasks from the command line

You can also run Bolt tasks from the command line.

  1. Install Puppet Development Kit (PDK) and Bolt.
  2. In the root of the CEM directory, run pdk bundle exec rake 'spec_prep'. This downloads the required dependencies as RSpec fixtures, and then symlinks the module directory into the fixtures directory.
  3. Run the tasks on one or more hosts. For example: bolt task run comply_enforcement_module::audit_unowned_files_and_directories -t $nodefqdn --modulepath spec/fixtures/modules. Note that you need to add the --modulepath spec/fixtures/modules option to Bolt commands, otherwise Bolt is not able to find the tasks and plans.

Known issues

Comply Scan Issues

The following recommendations can be reported as failing due to bugs in the CIS-CAT Pro Assessor bundled with Comply. CEM does correctly enforce these settings.

  • Red Hat Enterprise Linux Benchmark v1.0.1:
    • 1.5.1 - Ensure permissions on bootloader are configured
      • On EFI systems, the script ran by CIS-CAT Pro does not locate the correct grub file path. Permissions are set correctly by CEM.
    • 1.5.2 - Ensure bootloader password is set
      • On EFI systems, the script ran by CIS-CAT Pro does not locate the correct grub file path. The bootloader password can be set by CEM.
    • 4.1.16 - Ensure system administrator actions (sudolog) are collected
      • The sudo log path and rule are not successfully matched by the CIS CAT Pro scanner. CEM correctly enables the sudolog.

General Issues

  • nftables firewall is not supported. Use firewalld or iptables instead.
  • CEM cannot create filesystem partitions, which can cause certain scanner checks to fail.
  • CEM cannot set permissions on removable media partitions. To set the required permissions on these partitions, ensure nodev,nosuid,noexec exists in the options portion of /etc/fstab for the partition.
  • XD/NX support is dependent on the host kernel and CEM cannot configure it. Ensure you are using up-to-date kernels.
  • Restricting the root login to a system console requires knowledge of the site. You need to configure this control manually by removing entries in /etc/securetty for consoles that are not in secure locations.
  • CEM does not enforce authselect controls for CIS 1.0.0 5.3.x on RHEL8 or CentOS8. This requires site knowledge and can break network authentication. CIS recomends that you do not enforce this control. CEM includes a Bolt task audit_authselect to audit these controls.
  • You can only configure the ensure_nodev_option_set_on_home_partition class if the /home setting is mounted on it's own partition. Note that Puppet does not create a partition for /home.
  • If you are running on RHEL 8 and CentOS 8:
    • The ensure_nis_server_is_not_enabled class is dependent on ensure__rpc_is_not_enabled. If you enforce ensure_nis_server_is_not_enabled, you must also enforce ensure__rpc_is_not_enabled.
    • The ensure_nfs_is_not_enabled class is dependent on ensure__rpc_is_not_enabled. If you do not enforce ensure_nfs_is_not_enabled, you must also enforce ensure__rpc_is_not_enabled.
  • If you are running on RHEL 7 and CentOS 7:
    • The ensure_rpcbind_is_not_installed_or_the__rpcbind_services_are_masked class is dependant on ensure_nfsutils_is_not_installed_or_the__nfsserver_service_is_masked. If you enforce ensure_rpcbind_is_not_installed_or_the__rpcbind_services_are_masked, you must also enforce ensure_nfsutils_is_not_installed_or_the__nfsserver_service_is_masked.
  • The control disable_wireless_interfaces requires that you install the NetworkManager package and that the service is running.