Forge Home
Premium module


Compliance Enforcement Module for Linux


169 latest version

Version information

  • 1.2.0 (latest)
  • 1.1.4
  • 1.1.3
  • 1.1.2
  • 1.1.1
  • 1.1.0
  • 1.0.0
released May 24th 2022
This version is compatible with:
  • Puppet Enterprise 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
  • ,
  • audit_authselect
  • audit_check_ipv6
  • audit_duplicate_gid
  • audit_duplicate_group_names
  • audit_duplicate_uid
  • audit_duplicate_user_names
  • audit_etcpasswd_groups
  • and 20 more. See all tasks


puppetlabs/cem_linux — version 1.2.0 May 24th 2022



Table of contents

Introducing the Compliance Enforcement Modules

The cem_linux module is one of two Compliance Enforcement Modules (CEM). These supported Puppet modules were developed specifically to bring your Puppet Enterprise (PE) managed nodes into compliance. CEM currently supports Center for Internet Security (CIS) compliance rules.

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

This readme file provides instructions for installing CEM and customizing the configuration settings to meet your organization’s compliance requirements. For a list of available parameters, see the CEM reference.

After you have installed and configured CEM, PE will run on any classified nodes without user intervention to scan for compliance.

To manage Microsoft Windows nodes, navigate to cem_windows.


Before you install CEM, review the System requirements to ensure that CEM can be run on the operating systems in your environment. Then, contact a Puppet sales representative to purchase CEM.

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, 2 Server
Red Hat Enterprise Linux 8 CIS Benchmarks v2.0.0 1, 2 Server
CentOS Linux 7 CIS Benchmarks v3.1.2 1, 2 Server

Install CEM with Code Manager

You can install CEM by using Code Manager, a code management tool. For installation instructions, see Puppet Forge Premium Content.


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 default values can leave your nodes in an undesirable state. In these situations, you can customize how CEM enforces compliance to meet your organization's requirements.

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

Find and set configuration options

Configuration options include top-level options, general options, and CIS options.

For many users, the CEM default settings are sufficient because they enforce rules for the Level 1 (and, in some cases, the Level 2) server profile. However, you can change the settings. For a description of the settings, see the option files in the following folder:


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 by using the following format:

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

For example, configuring the options purge_at_deny and set_at_allow_perms 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

These configuration options are set at the top level of the module. In Hiera, these options are prefixed with cem_linux:

  • benchmark - Enum['cis'] - the compliance framework to use. CEM supports only cis. Default: cis.
  • config - Optional[Hash] - the location for all non-top-level configuration options. Default: undef.
  • allow_on_kubernetes_node - Boolean - If cem_linux detects that it is running on a Kubernetes cluster node or host, CEM does not enforce controls and logs a warning to inform the user. In this way, CEM helps to prevent the accidental enforcement of 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. To regenerate the Grub2 configuration after applying a change, set this parameter to true. If you do not set this to true, you must 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 by using the control_configs option. 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 in terms of security, and should be stored in a Sensitive data type. Default: Undef.

Hiera example

The following 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

The general configuration 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

The CIS configuration options are available as key-value pairs within the cem_linux::config: hash.

  • profile: - Optional[Enum['server', 'workstation']] — the name of the benchmark profile. The only value supported by CEM is server. Default: server.
  • level: - Optional[Enum['1', '2']] — the name of the profile level. The only value supported by CEM is 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.
  • enable_systemd_journal - Optional[Boolean] - Whether to enable systemd-journal. The default value is false. If this option is enabled, several configuration parameters are required.
    cem_linux::utils::services::systemd::journal::url: 'ip address or DNS resolvable hostname to receiving host'
    cem_linux::utils::services::systemd::journal::serverkeyfile: 'ServerKey file location'
    cem_linux::utils::services::systemd::journal::servercertificatefile: 'Server Certificate file location'
    cem_linux::utils::services::systemd::journal::trustedcertificatefile: 'Trusted Certificate file location'

Red Hat Enterprise Linux 8-specific CIS configuration options

If you installed CEM on a Red Hat Enterprise Linux 8 operating system, the authselect option is available, but the option should be avoided in almost all cases. The authselect option disrupts authentication and requires extensive configuration.

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 parameter determines whether the included code in the manifest is executed.
  • The $config parameter — You can set this parameter to maintain 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 (without a path and the .pp suffix) and the value of that key is a hash. The keys of the sub-hash are identical to the configuration options that are 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 following configuration examples.

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 repository, 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. To determine which task to run, review the output of the Puppet debug logs.

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 that is specified in the debug log.

The AIDE configuration file now reflects the changes in Hiera.

Enforce bootloader configurations

In rare cases, it might be useful to enable automatic regeneration of the bootloader configuration, and you might want to set a bootloader password.

Caution: 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, because changes to bootloader configurations can be potentially dangerous, a minimalistic approach to configuration changes is used by CEM for Linux.

For CIS, there are several recommendations that modify the bootloader config. If you run CEM for Linux with the full range of default settings, these changes will be applied, but the bootloader config will not be regenerated. While changes are pending on the node, bootloader operations remain the same until the configurations are regenerated. The exception to this is the bootloader password, which is not set by default. The following examples show how you can configure CEM for Linux to automatically regenerate the bootloader config and how you can set a bootloader password.

Regenerate bootloader configs automatically

To regenerate bootloader configurations automatically, locate the following file, where <node name> specifies the name of the affected node.

Edit the file to specify the following setting:

# control-repo/data/nodes/<node name>.yaml
cem_linux::regenerate_grub2_config: true
Set a bootloader password

You can set a bootloader password as shown in the following example:

# 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'

Restriction: The cem_linux::grub2_superuser_password key must be of 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].

Caution: Do not store plain-text passwords in Hiera. Using something like hiera-eyaml is a better way to store secrets.

Guidelines for enabling the authselect option

The authselect option is disabled by default because enablement of authselect can disrupt authentication methods, and use of the option requires extensive configuration.

Caution: If a node is joined to an Active Directory domain or to Red Hat Identity Management (idM), do not enable the authselect option. Enabling authselect on these nodes will break your authentication configurations.


  • The authselect option is supported only on Red Hat Enterprise Linux 8.
  • You cannot enable the authselect option if you are using pluggable authentication modules (PAM) for application management.

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 guidelines call for authselect to be used. The following example configuration shows how to enable authselect on a node by using the minimal system default profile:

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

To enable the authselect option:

  1. Set the config option use_authselect to true.
  2. 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 the authselect option to work properly.

Custom authselect profiles

If you are enforcing CIS compliance on a Red Hat Enterprise Linux 8 system and you want to enable additional features for your authselect profile, you can create a custom profile.

To create and use a custom authselect profile in cem_linux, prefix the profile name in authselect_profile with custom/. If the custom profile does not exist on the node, the profile will be created automatically. The following example shows how to create and use a custom profile, my_custom_profile, which is based on the system profile minimal with additional 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
Configure authselect

All authselect configurations are managed via the control class ensure_custom_authselect_profile_is_used, regardless of whether you use a custom profile. See the reference for all configuration options.

Configure custom logrotate rules

To help ensure that logs are pruned on a regular basis to conserve system space, you can specify 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'

Configure sudo without a password

You can give users and user groups the ability to run some or all commands as root 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:'

Configure user SSH keys

To use the Secure Shell (SSH) protocol for communication between computers, you must configure SSH keys. You can also configure SSH keys for individual users. In the following example, keys are configured for testuser1 and testuser2:

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

Configure SSH permissions for users and groups

You can configure SSH at a granular level to specify users and groups that are granted or denied permissions. The following example configures SSH to grant permissions to some users and groups and deny permissions to other users and groups:

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

Configure the firewall type

The following examples configure the firewall.

firewalld is the default setting:

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

You can also specify a value of iptables:

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

You can also specify a value of unmanaged. When you set the firewall_type parameter to unmanaged, CEM does not enforce a 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 site-specific information

Some CIS rules require information that is specific to a customer site. You can use Bolt tasks to configure these rules.

Bolt tasks in Puppet Enterprise (PE)

Using PE, you can run Bolt tasks and plans to audit or configure specific parts of a node. To run Bolt tasks, open the PE console and select the Tasks menu. Then, select cem_linux.

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 the pdk bundle exec rake 'spec_prep' command. This command downloads the required dependencies as RSpec fixtures, and then creates a symbolic link from the module directory to 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. You must add the --modulepath spec/fixtures/modules option to Bolt commands. Otherwise, Bolt is not able to find the tasks and plans.

Known issues

The current release includes known issues and restrictions. In most cases, workarounds are provided.

Comply scan issues

During a Comply scan, you might see errors about CIS recommended guidelines that are not enforced. These error messages are triggered by bugs in the CIS-CAT Pro Assessor that is bundled with Comply. CEM does correctly enforce these settings.

  • Red Hat Enterprise Linux Benchmark v2.0.0:
    • 1.4.2 - Ensure permissions on bootloader are configured
      • On EFI systems, the script that was run by the CIS-CAT Pro Assessor did not locate the correct grub file path. Permissions are set correctly by CEM.
    • 1.4.1 - Ensure bootloader password is set
      • On EFI systems, the script that was run by the CIS-CAT Pro Assessor did not locate the correct grub file path. The bootloader password can be set by CEM.
    • Ensure system is disabled when audit logs are full
      • This is set to halt by CEM. The CIS-CAT Pro Assessor shows this incorrectly as a scan failure.
    • 5.2.18 Ensure SSH MaxSessions is set to 10 or less
      • This is set to 10 by default. The CIS-CAT Pro Assessor shows this incorrectly as a scan failure. The scanner is incorrectly looking for <=4 instead of <=10.

General issues and limitations

  • Firewalls that are based on the nftables framework are not supported. Use the firewalld or iptables setting instead.
  • CEM cannot create file system partitions. This limitation can cause certain scanner checks to fail.
  • CEM cannot set permissions on removable media partitions. To set the required permissions on these partitions, ensure that 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 customer site. You must 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 2.0.0 5.4.x on Red Hat Enterprise Linux 8. Enforcement requires site knowledge and can break network authentication. CIS recommends that you do not enforce this control. CEM includes a Bolt task, audit_authselect, to audit these controls.
  • You can configure the ensure_nodev_option_set_on_home_partition class only if the /home setting is mounted on its own partition. Puppet does not create a partition for /home.
  • If your system is running on Red Hat Enterprise Linux 8:
    • The ensure_nis_server_is_not_installed class is dependent on ensure_rpcbind_is_not_installed_or_the__rpcbind_services_are_masked. If you enforce ensure_nis_server_is_not_installed, you must also enforce ensure_rpcbind_is_not_installed_or_the__rpcbind_services_are_masked.
    • The ensure_nfs_utils_is_not_installed_or_the__nfs_server_service_is_masked class is dependent on ensure_rpcbind_is_not_installed_or_the__rpcbind_services_are_masked. If you do not enforce ensure_nfs_utils_is_not_installed_or_the__nfs_server_service_is_masked, you must also not enforce ensure_nfs_utils_is_not_installed_or_the__nfs_server_service_is_masked.
  • The ensure_users_must_provide_password_for_escalation class is disabled by default. It is possible removing NOPASSWD: from sudoers files could invalidate those file's syntax and break system authentication. To enable this control set top level config enable_nopasswd_sudo_prune to true.
  • If your system is running on Red Hat Enterprise Linux 7 or CentOS 7:
    • The ensure_rpcbind_is_not_installed_or_the__rpcbind_services_are_masked class is dependent 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 disable_wireless_interfaces control requires that you install the NetworkManager package and that the service is running.