Guide to the Secure Configuration of SUSE Linux Enterprise 12

with profile DISA STIG for SUSE Linux Enterprise 12
This profile contains configuration checks that align to the DISA STIG for SUSE Linux Enterprise 12 V2R3.
This guide presents a catalog of security-relevant configuration settings for SUSE Linux Enterprise 12. It is a rendering of content structured in the eXtensible Configuration Checklist Description Format (XCCDF) in order to support security automation. The SCAP content is is available in the scap-security-guide package which is developed at https://www.open-scap.org/security-policies/scap-security-guide.

Providing system administrators with such guidance informs them how to securely configure systems under their control in a variety of network roles. Policy makers and baseline creators can use this catalog of settings, with its associated references to higher-level security control catalogs, in order to assist them in security baseline creation. This guide is a catalog, not a checklist, and satisfaction of every item is not likely to be possible or sensible in many operational scenarios. However, the XCCDF format enables granular selection and adjustment of settings, and their association with OVAL and OCIL content provides an automated checking capability. Transformations of this document, and its associated automated checking content, are capable of providing baselines that meet a diverse set of policy objectives. Some example XCCDF Profiles, which are selections of items that form checklists and can be used as baselines, are available with this guide. They can be processed, in an automated fashion, with tools that support the Security Content Automation Protocol (SCAP). The DISA STIG, which provides required settings for US Department of Defense systems, is one example of a baseline created from this guidance.
Do not attempt to implement any of the settings in this guide without first testing them in a non-operational environment. The creators of this guidance assume no responsibility whatsoever for its use by other parties, and makes no guarantees, expressed or implied, about its quality, reliability, or any other characteristic.
Profile TitleDISA STIG for SUSE Linux Enterprise 12
Profile IDxccdf_org.ssgproject.content_profile_stig

Revision History

Current version: 0.1.56

  • draft (as of 2021-06-04)

Platforms

  • cpe:/o:suse:linux_enterprise_server:12
  • cpe:/o:suse:linux_enterprise_desktop:12

Table of Contents

  1. System Settings
    1. Installing and Maintaining Software
    2. Account and Access Control
    3. System Accounting with auditd
    4. Network Configuration and Firewalls
    5. File Permissions and Masks
    6. GRUB2 bootloader configuration
    7. Configure Syslog
  2. Services
    1. FTP Server
    2. System Security Services Daemon
    3. SSH Server
    4. Obsolete Services
    5. Base Services
    6. NFS and RPC
    7. Network Time Protocol
    8. Mail Server Software

Checklist

contains 205 rules

System Settingsgroup

Contains rules that check correct system settings.

contains 176 rules

Installing and Maintaining Softwaregroup

The following sections contain information on security-relevant choices during the initial operating system installation process and the setup of software updates.

contains 23 rules

System and Software Integritygroup

System and software integrity can be gained by installing antivirus, increasing system encryption strength with FIPS, verifying installed software, enabling SELinux, installing an Intrusion Prevention System, etc. However, installing or enabling integrity checking tools cannot prevent intrusions, but they can detect that an intrusion may have occurred. Requirements for integrity checking may be highly dependent on the environment in which the system will be used. Snapshot-based approaches such as AIDE may induce considerable overhead in the presence of frequent software updates.

contains 8 rules

Software Integrity Checkinggroup

Both the AIDE (Advanced Intrusion Detection Environment) software and the RPM package management system provide mechanisms for verifying the integrity of installed software. AIDE uses snapshots of file metadata (such as hashes) and compares these to current system files in order to detect changes.

The RPM package management system can conduct integrity checks by comparing information in its metadata database with files installed on the system.

contains 5 rules

Verify Integrity with AIDEgroup

AIDE conducts integrity checks by comparing information about files with previously-gathered information. Ideally, the AIDE database is created immediately after initial system configuration, and then again after any software update. AIDE is highly configurable, with further configuration information located in /usr/share/doc/aide-VERSION.

contains 5 rules

Install AIDErule

The aide package can be installed with the following command:

$ sudo zypper install aide

Rationale:

The AIDE package must be installed if it is to be available for integrity checking.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

zypper install -y "aide"

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Ensure aide is installed
  package:
    name: aide
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83067-9
    - CJIS-5.10.1.3
    - DISA-STIG-SLES-12-010500
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-11.5
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_aide_installed
Remediation script:
include install_aide

class install_aide {
  package { 'aide':
    ensure => 'installed',
  }
}
Remediation script:

[[packages]]
name = "aide"
version = "*"

Configure AIDE to Verify Extended Attributesrule

By default, the xattrs option is added to the FIPSR ruleset in AIDE. If using a custom ruleset or the xattrs option is missing, add xattrs to the appropriate ruleset. For example, add xattrs to the following line in /etc/aide.conf:

FIPSR = p+i+n+u+g+s+m+c+acl+selinux+xattrs+sha256
AIDE rules can be configured in multiple ways; this is merely one example that is already configured by default. The remediation provided with this rule adds xattrs to all rule sets available in /etc/aide.conf

Rationale:

Extended attributes in file systems are used to contain arbitrary data and file metadata with security implications.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

zypper install -y "aide"

aide_conf="/etc/aide.conf"

groups=$(LC_ALL=C grep "^[A-Z][A-Za-z_]*" $aide_conf | grep -v "^ALLXTRAHASHES" | cut -f1 -d '=' | tr -d ' ' | sort -u)

for group in $groups
do
	config=$(grep "^$group\s*=" $aide_conf | cut -f2 -d '=' | tr -d ' ')

	if ! [[ $config = *xattrs* ]]
	then
		if [[ -z $config ]]
		then
			config="xattrs"
		else
			config=$config"+xattrs"
		fi
	fi
	sed -i "s/^$group\s*=.*/$group = $config/g" $aide_conf
done

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Gather list of packages
  package_facts:
    manager: auto
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83151-1
    - DISA-STIG-SLES-12-010530
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SI-7
    - NIST-800-53-SI-7(1)
    - aide_verify_ext_attributes
    - low_complexity
    - low_disruption
    - low_severity
    - no_reboot_needed
    - restrict_strategy

- name: get rules groups
  shell: |
    set -o pipefail
    LC_ALL=C grep "^[A-Z][A-Za-z_]*" /etc/aide.conf | grep -v "^ALLXTRAHASHES" | cut -f1 -d '=' | tr -d ' ' | sort -u || true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '''aide'' in ansible_facts.packages'
  register: find_rules_groups_results
  tags:
    - CCE-83151-1
    - DISA-STIG-SLES-12-010530
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SI-7
    - NIST-800-53-SI-7(1)
    - aide_verify_ext_attributes
    - low_complexity
    - low_disruption
    - low_severity
    - no_reboot_needed
    - restrict_strategy

- name: ensure the xattrs rule is present when aide is installed.
  replace:
    path: /etc/aide.conf
    regexp: (^\s*{{ item }}\s*=\s*)(?!.*xattrs)([^\s]*)
    replace: \g<1>\g<2>+xattrs
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '''aide'' in ansible_facts.packages'
  with_items: '{{ find_rules_groups_results.stdout_lines | map(''trim'') | list }}'
  tags:
    - CCE-83151-1
    - DISA-STIG-SLES-12-010530
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SI-7
    - NIST-800-53-SI-7(1)
    - aide_verify_ext_attributes
    - low_complexity
    - low_disruption
    - low_severity
    - no_reboot_needed
    - restrict_strategy

Configure Notification of Post-AIDE Scan Detailsrule

AIDE should notify appropriate personnel of the details of a scan after the scan has been run. If AIDE has already been configured for periodic execution in /etc/crontab, append the following line to the existing AIDE line:

 | /bin/mail -s "$(hostname) - AIDE Integrity Check" root@localhost
Otherwise, add the following line to /etc/crontab:
05 4 * * * root /usr/sbin/aide --check | /bin/mail -s "$(hostname) - AIDE Integrity Check" root@localhost
AIDE can be executed periodically through other means; this is merely one example.

Rationale:

Unauthorized changes to the baseline configuration could make the system vulnerable to various attacks or allow unauthorized access to the operating system. Changes to operating system configurations can have unintended side effects, some of which may be relevant to security.

Detecting such changes and providing an automated response can help avoid unintended, negative consequences that could ultimately affect the security state of the operating system. The operating system's Information Management Officer (IMO)/Information System Security Officer (ISSO) and System Administrators (SAs) must be notified via email and/or monitoring system trap when there is an unauthorized modification of a configuration item.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

zypper install -y "aide"

CRONTAB=/etc/crontab
CRONDIRS='/etc/cron.d /etc/cron.daily /etc/cron.weekly /etc/cron.monthly'

# NOTE: on some platforms, /etc/crontab may not exist
if [ -f /etc/crontab ]; then
	CRONTAB_EXIST=/etc/crontab
fi

if [ -f /var/spool/cron/root ]; then
	VARSPOOL=/var/spool/cron/root
fi

if ! grep -qR '^.*\/usr\/sbin\/aide\s*\-\-check.*|.*\/bin\/mail\s*-s\s*".*"\s*root@.*$' $CRONTAB_EXIST $VARSPOOL $CRONDIRS; then

	echo '0 5 * * * root /usr/bin/aide  --check | /bin/mail -s "$(hostname) - AIDE Integrity Check" root@localhost' >> $CRONTAB

fi

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi

Configure AIDE to Verify Access Control Lists (ACLs)rule

By default, the acl option is added to the FIPSR ruleset in AIDE. If using a custom ruleset or the acl option is missing, add acl to the appropriate ruleset. For example, add acl to the following line in /etc/aide.conf:

FIPSR = p+i+n+u+g+s+m+c+acl+selinux+xattrs+sha256
AIDE rules can be configured in multiple ways; this is merely one example that is already configured by default. The remediation provided with this rule adds acl to all rule sets available in /etc/aide.conf

Rationale:

ACLs can provide permissions beyond those permitted through the file mode and must be verified by the file integrity tools.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

zypper install -y "aide"

aide_conf="/etc/aide.conf"

groups=$(LC_ALL=C grep "^[A-Z][A-Za-z_]*" $aide_conf | grep -v "^ALLXTRAHASHES" | cut -f1 -d '=' | tr -d ' ' | sort -u)

for group in $groups
do
	config=$(grep "^$group\s*=" $aide_conf | cut -f2 -d '=' | tr -d ' ')

	if ! [[ $config = *acl* ]]
	then
		if [[ -z $config ]]
		then
			config="acl"
		else
			config=$config"+acl"
		fi
	fi
	sed -i "s/^$group\s*=.*/$group = $config/g" $aide_conf
done

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Gather list of packages
  package_facts:
    manager: auto
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83150-3
    - DISA-STIG-SLES-12-010520
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SI-7
    - NIST-800-53-SI-7(1)
    - aide_verify_acls
    - low_complexity
    - low_disruption
    - low_severity
    - no_reboot_needed
    - restrict_strategy

- name: get rules groups
  shell: |
    set -o pipefail
    LC_ALL=C grep "^[A-Z][A-Za-z_]*" /etc/aide.conf | grep -v "^ALLXTRAHASHES" | cut -f1 -d '=' | tr -d ' ' | sort -u || true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '''aide'' in ansible_facts.packages'
  register: find_rules_groups_results
  tags:
    - CCE-83150-3
    - DISA-STIG-SLES-12-010520
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SI-7
    - NIST-800-53-SI-7(1)
    - aide_verify_acls
    - low_complexity
    - low_disruption
    - low_severity
    - no_reboot_needed
    - restrict_strategy

- name: ensure the acl rule is present when aide is installed.
  replace:
    path: /etc/aide.conf
    regexp: (^\s*{{ item }}\s*=\s*)(?!.*acl)([^\s]*)
    replace: \g<1>\g<2>+acl
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '''aide'' in ansible_facts.packages'
  with_items: '{{ find_rules_groups_results.stdout_lines | map(''trim'') | list }}'
  tags:
    - CCE-83150-3
    - DISA-STIG-SLES-12-010520
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SI-7
    - NIST-800-53-SI-7(1)
    - aide_verify_acls
    - low_complexity
    - low_disruption
    - low_severity
    - no_reboot_needed
    - restrict_strategy

Configure AIDE to Verify the Audit Toolsrule

The SUSE operating system file integrity tool must be configured to protect the integrity of the audit tools.

Rationale:

Protecting the integrity of the tools used for auditing purposes is a critical step toward ensuring the integrity of audit information. Audit information includes all information (e.g., audit records, audit settings, and audit reports) needed to successfully audit information system activity. Audit tools include but are not limited to vendor-provided and open-source audit tools needed to successfully view and manipulate audit information system activity and records. Audit tools include custom queries and report generators. It is not uncommon for attackers to replace the audit tools or inject code into the existing tools to provide the capability to hide or erase system activity from the audit logs. To address this risk, audit tools must be cryptographically signed to provide the capability to identify when the audit tools have been modified, manipulated, or replaced. An example is a checksum hash of the file or files.

Remediation script:
- name: Install aide package
  zypper:
    name: aide
    state: latest
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83204-8
    - DISA-STIG-SLES-12-010540
    - NIST-800-53-AU-9(3)
    - NIST-800-53-AU-9(3).1
    - aide_check_audit_tools
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Set audit_tools fact
  set_fact:
    audit_tools:
      - /usr/sbin/audispd
      - /usr/sbin/auditctl
      - /usr/sbin/auditd
      - /usr/sbin/augenrules
      - /usr/sbin/aureport
      - /usr/sbin/ausearch
      - /usr/sbin/autrace
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83204-8
    - DISA-STIG-SLES-12-010540
    - NIST-800-53-AU-9(3)
    - NIST-800-53-AU-9(3).1
    - aide_check_audit_tools
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure existing AIDE configuration for audit tools are correct
  lineinfile:
    path: /etc/aide.conf
    regexp: ^{{ item }}\s
    line: '{{ item }} p+i+n+u+g+s+b+acl+selinux+xattrs+sha512'
  with_items: '{{ audit_tools }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83204-8
    - DISA-STIG-SLES-12-010540
    - NIST-800-53-AU-9(3)
    - NIST-800-53-AU-9(3).1
    - aide_check_audit_tools
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Configure AIDE to properly protect audit tools
  lineinfile:
    path: /etc/aide.conf
    line: '{{ item }} p+i+n+u+g+s+b+acl+selinux+xattrs+sha512'
  with_items: '{{ audit_tools }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83204-8
    - DISA-STIG-SLES-12-010540
    - NIST-800-53-AU-9(3)
    - NIST-800-53-AU-9(3).1
    - aide_check_audit_tools
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Endpoint Protection Softwaregroup

Endpoint protection security software that is not provided or supported by Red Hat can be installed to provide complementary or duplicative security capabilities to those provided by the base platform. Add-on software may not be appropriate for some specialized systems.

contains 1 rule

McAfee Endpoint Security Softwaregroup

In DoD environments, McAfee Host-based Security System (HBSS) and VirusScan Enterprise for Linux (VSEL) is required to be installed on all systems.

contains 1 rule

McAfee Host-Based Intrusion Detection Software (HBSS)group

McAfee Host-based Security System (HBSS) is a suite of software applications used to monitor, detect, and defend computer networks and systems.

contains 1 rule

Install the Host Intrusion Prevention System (HIPS) Modulerule

Install the McAfee Host Intrusion Prevention System (HIPS) Module if it is absolutely necessary. If SELinux is enabled, do not install or enable this module.

warning  Installing and enabling this module conflicts with SELinux. Per DoD/DISA guidance, SELinux takes precedence over this module.
warning  Due to McAfee HIPS being 3rd party software, automated remediation is not available for this configuration check.
Rationale:

Without a host-based intrusion detection tool, there is no system-level defense when an intruder gains access to a system or network. Additionally, a host-based intrusion prevention tool can provide methods to immediately lock out detected intrusion attempts.

Remediation script:

[[packages]]
name = "MFEhiplsm"
version = "*"

Operating System Vendor Support and Certificationgroup

The assurance of a vendor to provide operating system support and maintenance for their product is an important criterion to ensure product stability and security over the life of the product. A certified product that follows the necessary standards and government certification requirements guarantees that known software vulnerabilities will be remediated, and proper guidance for protecting and securing the operating system will be given.

contains 2 rules

The Installed Operating System Is FIPS 140-2 Certifiedrule

To enable processing of sensitive information the operating system must provide certified cryptographic modules compliant with FIPS 140-2 standard. SUSE Enterprise Linux is supported by SUSE Software Solutions Germany GmbH. As the SUSE Enterprise Linux vendor, SUSE Software Solutions Germany GmbH is responsible for maintaining government certifications and standards.

warning  There is no remediation besides switching to a different operating system.
warning  System Crypto Modules must be provided by a vendor that undergoes FIPS-140 certifications. FIPS-140 is applicable to all Federal agencies that use cryptographic-based security systems to protect sensitive information in computer and telecommunication systems (including voice systems) as defined in Section 5131 of the Information Technology Management Reform Act of 1996, Public Law 104-106. This standard shall be used in designing and implementing cryptographic modules that Federal departments and agencies operate or are operated for them under contract. See https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.140-2.pdf To meet this, the system has to have cryptographic software provided by a vendor that has undergone this certification. This means providing documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process.
Rationale:

The Federal Information Processing Standard (FIPS) Publication 140-2, (FIPS PUB 140-2) is a computer security standard. The standard specifies security requirements for cryptographic modules used to protect sensitive unclassified information. Refer to the full FIPS 140-2 standard at http://csrc.nist.gov/publications/fips/fips140-2/fips1402.pdf for further details on the requirements. FIPS 140-2 validation is required by U.S. law when information systems use cryptography to protect sensitive government information. In order to achieve FIPS 140-2 certification, cryptographic modules are subject to extensive testing by independent laboratories, accredited by National Institute of Standards and Technology (NIST).

The Installed Operating System Is Vendor Supportedrule

The installed operating system must be maintained by a vendor. SUSE Linux Enterprise is supported by SUSE. As the SUSE Linux Enterprise vendor, SUSE is responsible for providing security patches.

warning  There is no remediation besides switching to a different operating system.
Rationale:

An operating system is considered "supported" if the vendor continues to provide security patches for the product. With an unsupported release, it will not be possible to resolve any security issue discovered in the system software.

Updating Softwaregroup

The zypper command line tool is used to install and update software packages. The system also provides a graphical software update tool in the System menu, in the Administration submenu, called Software Update.

SUSE Linux Enterprise 12 systems contain an installed software catalog called the RPM database, which records metadata of installed packages. Consistently using zypper or the graphical Software Update for all software installation allows for insight into the current inventory of installed software on the system.

contains 3 rules

Ensure zypper Removes Previous Package Versionsrule

zypper should be configured to remove previous software components after new versions have been installed. To configure zypper to remove the previous software components after updating, set the solver.upgradeRemoveDroppedPackages to 1 in /etc/zypp/zypp.conf.

Rationale:

Previous versions of software components that are not removed from the information system after updates have been installed may be exploited by some adversaries.

Remediation script:
# Remediation is applicable only in certain platforms
if rpm --quiet -q zypper; then

# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
  # Otherwise, regular sed command will do.
  sed_command=('sed' '-i')
  if test -L "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="${cce}"
  else
    cce="CCE"
  fi

  # Strip any search characters in the key arg so that the key can be replaced without
  # adding any search characters to the config file.
  stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$value"

  # If the key exists, change it. Otherwise, add it to the config_file.
  # We search for the key string followed by a word boundary (matched by \>),
  # so if we search for 'setting', 'setting2' won't match.
  if LC_ALL=C grep -q -m 1 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}
replace_or_append '/etc/zypp/zypp.conf' '^solver.upgradeRemoveDroppedPackages' 'true' 'CCE-83186-7' '%s=%s'

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CCE-83186-7
    - DISA-STIG-SLES-12-010570
    - NIST-800-171-3.4.8
    - NIST-800-53-CM-11(a)
    - NIST-800-53-CM-11(b)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SI-2(6)
    - clean_components_post_updating
    - low_complexity
    - low_disruption
    - low_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure Zypper Removes Previous Package Versions
  ini_file:
    dest: /etc/zypp/zypp.conf
    section: main
    option: solver.upgradeRemoveDroppedPackages
    value: true
    create: false
  when: '"zypper" in ansible_facts.packages'
  tags:
    - CCE-83186-7
    - DISA-STIG-SLES-12-010570
    - NIST-800-171-3.4.8
    - NIST-800-53-CM-11(a)
    - NIST-800-53-CM-11(b)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SI-2(6)
    - clean_components_post_updating
    - low_complexity
    - low_disruption
    - low_severity
    - no_reboot_needed
    - restrict_strategy

Ensure Software Patches Installedrule

If the system is configured for online updates, invoking the following command will list available security updates:

$ sudo zypper refresh && sudo zypper list-patches -g security


NOTE: U.S. Defense systems are required to be patched within 30 days or sooner as local policy dictates.

Rationale:

Installing software updates is a fundamental mitigation against the exploitation of publicly-known vulnerabilities. If the most recent security patches and updates are not installed, unauthorized users may take advantage of weaknesses in the unpatched software. The lack of prompt attention to patching could result in a system compromise.

Remediation script:
- name: Security patches are up to date
  package:
    name: '*'
    state: latest
  tags:
    - CCE-83002-6
    - CJIS-5.10.4.1
    - DISA-STIG-SLES-12-010010
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SI-2(5)
    - NIST-800-53-SI-2(c)
    - PCI-DSS-Req-6.2
    - high_disruption
    - high_severity
    - low_complexity
    - patch_strategy
    - reboot_required
    - security_patches_up_to_date
    - skip_ansible_lint

Ensure gpgcheck Enabled In Main zypper Configurationrule

The gpgcheck option controls whether RPM packages' signatures are always checked prior to installation. To configure zypper to check package signatures before installing them, ensure the following line appears in /etc/zypp/zypp.conf in the [main] section:

gpgcheck=1

Rationale:

Changes to any software components can have significant effects on the overall security of the operating system. This requirement ensures the software has not been tampered with and that it has been provided by a trusted vendor.
Accordingly, patches, service packs, device drivers, or operating system components must be signed with a certificate recognized and approved by the organization.
Verifying the authenticity of the software prior to installation validates the integrity of the patch or upgrade received from a vendor. This ensures the software has not been tampered with and that it has been provided by a trusted vendor. Self-signed certificates are disallowed by this requirement. Certificates used to verify the software must be from an approved Certificate Authority (CA).

Remediation script:
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CCE-83068-7
    - CJIS-5.10.4.1
    - DISA-STIG-SLES-12-010550
    - NIST-800-171-3.4.8
    - NIST-800-53-CM-11(a)
    - NIST-800-53-CM-11(b)
    - NIST-800-53-CM-5(3)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SA-12
    - NIST-800-53-SA-12(10)
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SI-7
    - PCI-DSS-Req-6.2
    - ensure_gpgcheck_globally_activated
    - high_severity
    - low_complexity
    - medium_disruption
    - no_reboot_needed
    - unknown_strategy

- name: Ensure GPG check is globally activated (zypper)
  ini_file:
    dest: /etc/zypp/zypp.conf
    section: main
    option: gpgcheck
    value: 1
    no_extra_spaces: true
    create: false
  when: '"zypper" in ansible_facts.packages'
  tags:
    - CCE-83068-7
    - CJIS-5.10.4.1
    - DISA-STIG-SLES-12-010550
    - NIST-800-171-3.4.8
    - NIST-800-53-CM-11(a)
    - NIST-800-53-CM-11(b)
    - NIST-800-53-CM-5(3)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SA-12
    - NIST-800-53-SA-12(10)
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SI-7
    - PCI-DSS-Req-6.2
    - ensure_gpgcheck_globally_activated
    - high_severity
    - low_complexity
    - medium_disruption
    - no_reboot_needed
    - unknown_strategy

Sudogroup

Sudo, which stands for "su 'do'", provides the ability to delegate authority to certain users, groups of users, or system administrators. When configured for system users and/or groups, Sudo can allow a user or group to execute privileged commands that normally only root is allowed to execute.

For more information on Sudo and addition Sudo configuration options, see https://www.sudo.ws.

contains 2 rules

Ensure Users Re-Authenticate for Privilege Escalation - sudo !authenticaterule

The sudo !authenticate option, when specified, allows a user to execute commands using sudo without having to authenticate. This should be disabled by making sure that the !authenticate option does not exist in /etc/sudoers configuration file or any sudo configuration snippets in /etc/sudoers.d/.

Rationale:

Without re-authentication, users may access resources or perform tasks for which they do not have authorization.

When operating systems provide the capability to escalate a functional capability, it is critical that the user re-authenticate.

Remediation script:

for f in $( ls /etc/sudoers /etc/sudoers.d/* 2> /dev/null ) ; do
  matching_list=$(grep -P '^(?!#).*[\s]+\!authenticate.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "!authenticate" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"

    /usr/sbin/visudo -cf $f &> /dev/null || echo "Fail to validate $f with visudo"
  fi
done
Remediation script:
- name: Find /etc/sudoers.d/ files
  find:
    paths:
      - /etc/sudoers.d/
  register: sudoers
  tags:
    - CCE-83013-3
    - DISA-STIG-SLES-12-010110
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-11
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - sudo_remove_no_authenticate

- name: Remove lines containing !authenticate from sudoers files
  replace:
    regexp: (^(?!#).*[\s]+\!authenticate.*$)
    replace: '# \g<1>'
    path: '{{ item.path }}'
    validate: /usr/sbin/visudo -cf %s
  with_items:
    - path: /etc/sudoers
    - '{{ sudoers.files }}'
  tags:
    - CCE-83013-3
    - DISA-STIG-SLES-12-010110
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-11
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - sudo_remove_no_authenticate

Ensure Users Re-Authenticate for Privilege Escalation - sudo NOPASSWDrule

The sudo NOPASSWD tag, when specified, allows a user to execute commands using sudo without having to authenticate. This should be disabled by making sure that the NOPASSWD tag does not exist in /etc/sudoers configuration file or any sudo configuration snippets in /etc/sudoers.d/.

Rationale:

Without re-authentication, users may access resources or perform tasks for which they do not have authorization.

When operating systems provide the capability to escalate a functional capability, it is critical that the user re-authenticate.

Remediation script:

for f in $( ls /etc/sudoers /etc/sudoers.d/* 2> /dev/null ) ; do
  matching_list=$(grep -P '^(?!#).*[\s]+NOPASSWD[\s]*\:.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "NOPASSWD" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"

    /usr/sbin/visudo -cf $f &> /dev/null || echo "Fail to validate $f with visudo"
  fi
done
Remediation script:
- name: Find /etc/sudoers.d/ files
  find:
    paths:
      - /etc/sudoers.d/
  register: sudoers
  tags:
    - CCE-83012-5
    - DISA-STIG-SLES-12-010110
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-11
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - sudo_remove_nopasswd

- name: Remove lines containing NOPASSWD from sudoers files
  replace:
    regexp: (^(?!#).*[\s]+NOPASSWD[\s]*\:.*$)
    replace: '# \g<1>'
    path: '{{ item.path }}'
    validate: /usr/sbin/visudo -cf %s
  with_items:
    - path: /etc/sudoers
    - '{{ sudoers.files }}'
  tags:
    - CCE-83012-5
    - DISA-STIG-SLES-12-010110
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-11
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - sudo_remove_nopasswd

GNOME Desktop Environmentgroup

GNOME is a graphical desktop environment bundled with many Linux distributions that allow users to easily interact with the operating system graphically rather than textually. The GNOME Graphical Display Manager (GDM) provides login, logout, and user switching contexts as well as display server management.

GNOME is developed by the GNOME Project and is considered the default Red Hat Graphical environment.

For more information on GNOME and the GNOME Project, see https://www.gnome.org.

contains 6 rules

Configure GNOME Screen Lockinggroup

In the default GNOME3 desktop, the screen can be locked by selecting the user name in the far right corner of the main panel and selecting Lock.

The following sections detail commands to enforce idle activation of the screensaver, screen locking, a blank-screen screensaver, and an idle activation time.

Because users should be trained to lock the screen when they step away from the computer, the automatic locking feature is only meant as a backup.

The root account can be screen-locked; however, the root account should never be used to log into an X Windows environment and should only be used to for direct login via console in emergency circumstances.

For more information about enforcing preferences in the GNOME3 environment using the DConf configuration system, see http://wiki.gnome.org/dconf and the man page dconf(1).

contains 3 rules

Implement Blank Screensaverrule

On SUSE users should set the screensaver to use publicly viewable images or blank screen by doing the following: Find the Settings menu and then navigate to the Background selection section - Click "Applications" on the bottom left. - Hover over "System Tools" with the mouse. - Click the "Settings" icon under System Tools. - Click "Background" and then "Lock Screen". - Select image and set the Lock Screen image to the user's choice. - Click "Select". - Exit Settings Dialog. To set the screensaver mode in the GNOME3 desktop to a blank screen, add or set picture-uri to string '' in /etc/dconf/db/local.d/00-security-settings. For example:

[org/gnome/desktop/screensaver]
picture-uri=''
Once the settings have been added, add a lock to /etc/dconf/db/local.d/locks/00-security-settings-lock to prevent user modification. For example:
/org/gnome/desktop/screensaver/picture-uri
After the settings have been set, run dconf update.

Rationale:

Setting the screensaver mode to blank-only conceals the contents of the display from passersby.

Remediation script:
# Remediation is applicable only in certain platforms
if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then

# Check for setting in any of the DConf db directories
# If files contain ibus or distro, ignore them.
# The assignment assumes that individual filenames don't contain :
readarray -t SETTINGSFILES < <(grep -r "\\[org/gnome/desktop/screensaver\\]" "/etc/dconf/db/" | grep -v 'distro\|ibus' | cut -d":" -f1)
DCONFFILE="/etc/dconf/db/local.d/00-security-settings"
DBDIR="/etc/dconf/db/local.d"

mkdir -p "${DBDIR}"

if [ "${#SETTINGSFILES[@]}" -eq 0 ]
then
    [ ! -z ${DCONFFILE} ] || echo "" >> ${DCONFFILE}
    printf '%s\n' "[org/gnome/desktop/screensaver]" >> ${DCONFFILE}
    printf '%s=%s\n' "picture-uri" "string ''" >> ${DCONFFILE}
else
    escaped_value="$(sed -e 's/\\/\\\\/g' <<< "string ''")"
    if grep -q "^\\s*picture-uri\\s*=" "${SETTINGSFILES[@]}"
    then
        sed -i "s/\\s*picture-uri\\s*=\\s*.*/picture-uri=${escaped_value}/g" "${SETTINGSFILES[@]}"
    else
        sed -i "\\|\\[org/gnome/desktop/screensaver\\]|a\\picture-uri=${escaped_value}" "${SETTINGSFILES[@]}"
    fi
fi

dconf update
# Check for setting in any of the DConf db directories
LOCKFILES=$(grep -r "^/org/gnome/desktop/screensaver/picture-uri$" "/etc/dconf/db/" | grep -v 'distro\|ibus' | cut -d":" -f1)
LOCKSFOLDER="/etc/dconf/db/local.d/locks"

mkdir -p "${LOCKSFOLDER}"

if [[ -z "${LOCKFILES}" ]]
then
    echo "/org/gnome/desktop/screensaver/picture-uri" >> "/etc/dconf/db/local.d/locks/00-security-settings-lock"
fi

dconf update

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CCE-83221-2
    - CJIS-5.5.5
    - DISA-STIG-SLES-12-010100
    - NIST-800-171-3.1.10
    - NIST-800-53-AC-11(1)
    - NIST-800-53-AC-11(1).1
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.8
    - dconf_gnome_screensaver_mode_blank
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

- name: Implement Blank Screensaver
  ini_file:
    dest: /etc/dconf/db/local.d/00-security-settings
    section: org/gnome/desktop/screensaver
    option: picture-uri
    value: string ''
    create: true
    no_extra_spaces: true
  when:
    - '"gdm" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83221-2
    - CJIS-5.5.5
    - DISA-STIG-SLES-12-010100
    - NIST-800-171-3.1.10
    - NIST-800-53-AC-11(1)
    - NIST-800-53-AC-11(1).1
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.8
    - dconf_gnome_screensaver_mode_blank
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

- name: Prevent user modification of GNOME picture-uri
  lineinfile:
    path: /etc/dconf/db/local.d/locks/00-security-settings-lock
    regexp: ^/org/gnome/desktop/screensaver/picture-uri
    line: /org/gnome/desktop/screensaver/picture-uri
    create: true
  when:
    - '"gdm" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83221-2
    - CJIS-5.5.5
    - DISA-STIG-SLES-12-010100
    - NIST-800-171-3.1.10
    - NIST-800-53-AC-11(1)
    - NIST-800-53-AC-11(1).1
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.8
    - dconf_gnome_screensaver_mode_blank
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

- name: Dconf Update
  command: dconf update
  when:
    - '"gdm" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83221-2
    - CJIS-5.5.5
    - DISA-STIG-SLES-12-010100
    - NIST-800-171-3.1.10
    - NIST-800-53-AC-11(1)
    - NIST-800-53-AC-11(1).1
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.8
    - dconf_gnome_screensaver_mode_blank
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

Set GNOME3 Screensaver Inactivity Timeoutrule

The idle time-out value for inactivity in the GNOME3 desktop is configured via the idle-delay setting must be set under an appropriate configuration file(s) in the /etc/dconf/db/local.d directory and locked in /etc/dconf/db/local.d/locks directory to prevent user modification.

For example, to configure the system for a 15 minute delay, add the following to /etc/dconf/db/local.d/00-security-settings:

[org/gnome/desktop/session]
idle-delay=uint32 900
Once the setting has been added, add a lock to /etc/dconf/db/local.d/locks/00-security-settings-lock to prevent user modification. For example:
/org/gnome/desktop/session/idle-delay
After the settings have been set, run dconf update.

Rationale:

A session time-out lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity of the information system but does not logout because of the temporary nature of the absence. Rather than relying on the user to manually lock their operating system session prior to vacating the vicinity, GNOME3 can be configured to identify when a user's session has idled and take action to initiate a session lock.

Remediation script:
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CCE-83010-9
    - CJIS-5.5.5
    - DISA-STIG-SLES-12-010080
    - NIST-800-171-3.1.10
    - NIST-800-53-AC-11(a)
    - NIST-800-53-AC-11.1 (ii)
    - PCI-DSS-Req-8.1.8
    - dconf_gnome_screensaver_idle_delay
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy
- name: XCCDF Value inactivity_timeout_value # promote to variable
  set_fact:
    inactivity_timeout_value: !!str 900
  tags:
    - always

- name: Set GNOME3 Screensaver Inactivity Timeout
  ini_file:
    dest: /etc/dconf/db/local.d/00-security-settings
    section: org/gnome/desktop/session
    option: idle-delay
    value: uint32 {{ inactivity_timeout_value }}
    create: true
    no_extra_spaces: true
  when:
    - '"gdm" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83010-9
    - CJIS-5.5.5
    - DISA-STIG-SLES-12-010080
    - NIST-800-171-3.1.10
    - NIST-800-53-AC-11(a)
    - NIST-800-53-AC-11.1 (ii)
    - PCI-DSS-Req-8.1.8
    - dconf_gnome_screensaver_idle_delay
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

- name: Prevent user modification of GNOME idle-delay
  lineinfile:
    path: /etc/dconf/db/local.d/locks/00-security-settings-lock
    regexp: ^/org/gnome/desktop/session/idle-delay
    line: /org/gnome/desktop/session/idle-delay
    create: true
  when:
    - '"gdm" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83010-9
    - CJIS-5.5.5
    - DISA-STIG-SLES-12-010080
    - NIST-800-171-3.1.10
    - NIST-800-53-AC-11(a)
    - NIST-800-53-AC-11.1 (ii)
    - PCI-DSS-Req-8.1.8
    - dconf_gnome_screensaver_idle_delay
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

- name: Dconf Update
  command: dconf update
  when:
    - '"gdm" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83010-9
    - CJIS-5.5.5
    - DISA-STIG-SLES-12-010080
    - NIST-800-171-3.1.10
    - NIST-800-53-AC-11(a)
    - NIST-800-53-AC-11.1 (ii)
    - PCI-DSS-Req-8.1.8
    - dconf_gnome_screensaver_idle_delay
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

Enable GNOME3 Screensaver Lock After Idle Periodrule

To activate locking of the screensaver in the GNOME3 desktop when it is activated, run the following command to configure the SUSE operating system to allow the user to lock the GUI:

gsettings set org.gnome.desktop.lockdown disable-lock-screen false
Validate that disable-lock-screen has been set to false with the command:
gsettings get org.gnome.desktop.lockdown disable-lock-screen

Rationale:

A session lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity of the information system but does not want to logout because of the temporary nature of the absense.

Remediation script:
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CCE-83222-0
    - CJIS-5.5.5
    - DISA-STIG-SLES-12-010060
    - NIST-800-171-3.1.10
    - NIST-800-53-AC-11
    - NIST-800-53-AC-11(1)
    - NIST-800-53-AC-11(1).1
    - NIST-800-53-AC-11(a)
    - NIST-800-53-AC-11(b)
    - NIST-800-53-AC-11.1(iii)
    - PCI-DSS-Req-8.1.8
    - dconf_gnome_screensaver_lock_enabled
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

- name: Dconf Update
  command: dconf update
  when:
    - '"gdm" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ansible_distribution == 'SLES'
  tags:
    - CCE-83222-0
    - CJIS-5.5.5
    - DISA-STIG-SLES-12-010060
    - NIST-800-171-3.1.10
    - NIST-800-53-AC-11
    - NIST-800-53-AC-11(1)
    - NIST-800-53-AC-11(1).1
    - NIST-800-53-AC-11(a)
    - NIST-800-53-AC-11(b)
    - NIST-800-53-AC-11.1(iii)
    - PCI-DSS-Req-8.1.8
    - dconf_gnome_screensaver_lock_enabled
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

- name: Enable GNOME3 Screensaver Lock After Idle Period
  ini_file:
    dest: /etc/dconf/db/local.d/00-security-settings
    section: org/gnome/desktop/screensaver
    option: lock-enabled
    value: 'true'
    create: true
    no_extra_spaces: true
  when:
    - '"gdm" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83222-0
    - CJIS-5.5.5
    - DISA-STIG-SLES-12-010060
    - NIST-800-171-3.1.10
    - NIST-800-53-AC-11
    - NIST-800-53-AC-11(1)
    - NIST-800-53-AC-11(1).1
    - NIST-800-53-AC-11(a)
    - NIST-800-53-AC-11(b)
    - NIST-800-53-AC-11.1(iii)
    - PCI-DSS-Req-8.1.8
    - dconf_gnome_screensaver_lock_enabled
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

- name: Prevent user modification of GNOME lock-enabled
  lineinfile:
    path: /etc/dconf/db/local.d/locks/00-security-settings-lock
    regexp: ^/org/gnome/desktop/screensaver/lock-enabled
    line: /org/gnome/desktop/screensaver/lock-enabled
    create: true
  when:
    - '"gdm" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83222-0
    - CJIS-5.5.5
    - DISA-STIG-SLES-12-010060
    - NIST-800-171-3.1.10
    - NIST-800-53-AC-11
    - NIST-800-53-AC-11(1)
    - NIST-800-53-AC-11(1).1
    - NIST-800-53-AC-11(a)
    - NIST-800-53-AC-11(b)
    - NIST-800-53-AC-11.1(iii)
    - PCI-DSS-Req-8.1.8
    - dconf_gnome_screensaver_lock_enabled
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

- name: Check GNOME3 screenserver disable-lock-screen false
  command: gsettings get org.gnome.desktop.lockdown disable-lock-screen
  register: cmd_out
  when:
    - '"gdm" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ansible_distribution == 'SLES'
  tags:
    - CCE-83222-0
    - CJIS-5.5.5
    - DISA-STIG-SLES-12-010060
    - NIST-800-171-3.1.10
    - NIST-800-53-AC-11
    - NIST-800-53-AC-11(1)
    - NIST-800-53-AC-11(1).1
    - NIST-800-53-AC-11(a)
    - NIST-800-53-AC-11(b)
    - NIST-800-53-AC-11.1(iii)
    - PCI-DSS-Req-8.1.8
    - dconf_gnome_screensaver_lock_enabled
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

- name: Update GNOME3 screenserver disable-lock-screen false
  command: gsettings set org.gnome.desktop.lockdown disable-lock-screen false
  when:
    - '"gdm" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ansible_distribution == 'SLES'
  tags:
    - CCE-83222-0
    - CJIS-5.5.5
    - DISA-STIG-SLES-12-010060
    - NIST-800-171-3.1.10
    - NIST-800-53-AC-11
    - NIST-800-53-AC-11(1)
    - NIST-800-53-AC-11(1).1
    - NIST-800-53-AC-11(a)
    - NIST-800-53-AC-11(b)
    - NIST-800-53-AC-11.1(iii)
    - PCI-DSS-Req-8.1.8
    - dconf_gnome_screensaver_lock_enabled
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

- name: Dconf Update
  command: dconf update
  when:
    - '"gdm" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83222-0
    - CJIS-5.5.5
    - DISA-STIG-SLES-12-010060
    - NIST-800-171-3.1.10
    - NIST-800-53-AC-11
    - NIST-800-53-AC-11(1)
    - NIST-800-53-AC-11(1).1
    - NIST-800-53-AC-11(a)
    - NIST-800-53-AC-11(b)
    - NIST-800-53-AC-11.1(iii)
    - PCI-DSS-Req-8.1.8
    - dconf_gnome_screensaver_lock_enabled
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy
contains 1 rule

Make sure that the dconf databases are up-to-date with regards to respective keyfilesrule

By default, DConf uses a binary database as a data backend. The system-level database is compiled from keyfiles in the /etc/dconf/db/ directory by the

dconf update
command.

Rationale:

Unlike text-based keyfiles, the binary database is impossible to check by OVAL. Therefore, in order to evaluate dconf configuration, both have to be true at the same time - configuration files have to be compliant, and the database needs to be more recent than those keyfiles, which gives confidence that it reflects them.

identifiers:  CCE-83182-6

references:  164.308(a)(1)(ii)(B), 164.308(a)(5)(ii)(A), SRG-OS-000480-GPOS-00227

Remediation script:
# Remediation is applicable only in certain platforms
if rpm --quiet -q gdm && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then

dconf update

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CCE-83182-6
    - dconf_db_up_to_date
    - high_severity
    - low_complexity
    - medium_disruption
    - no_reboot_needed
    - unknown_strategy

- name: Run dconf update
  shell: |-
    set -o pipefail
    dconf update
  when:
    - '"gdm" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83182-6
    - dconf_db_up_to_date
    - high_severity
    - low_complexity
    - medium_disruption
    - no_reboot_needed
    - unknown_strategy

Disk Partitioninggroup

To ensure separation and protection of data, there are top-level system directories which should be placed on their own physical partition or logical volume. The installer's default partitioning scheme creates separate logical volumes for /, /boot, and swap.

  • If starting with any of the default layouts, check the box to \"Review and modify partitioning.\" This allows for the easy creation of additional logical volumes inside the volume group already created, though it may require making /'s logical volume smaller to create space. In general, using logical volumes is preferable to using partitions because they can be more easily adjusted later.
  • If creating a custom layout, create the partitions mentioned in the previous paragraph (which the installer will require anyway), as well as separate ones described in the following sections.
If a system has already been installed, and the default partitioning scheme was used, it is possible but nontrivial to modify it to create separate logical volumes for the directories listed above. The Logical Volume Manager (LVM) makes this possible. See the LVM HOWTO at http://tldp.org/HOWTO/LVM-HOWTO/ for more detailed information on LVM.

contains 4 rules

Ensure /home Located On Separate Partitionrule

If user home directories will be stored locally, create a separate partition for /home at installation time (or migrate it later using LVM). If /home will be mounted from another system such as an NFS server, then creating a separate partition is not necessary at installation time, and the mountpoint can instead be configured later.

Rationale:

Ensuring that /home is mounted on its own partition enables the setting of more restrictive mount options, and also helps ensure that users cannot trivially fill partitions used for log or audit data storage.

Ensure /var/log/audit Located On Separate Partitionrule

Audit logs are stored in the /var/log/audit directory. Ensure that it has its own partition or logical volume at installation time, or migrate it later using LVM. Make absolutely certain that it is large enough to store all audit logs that will be created by the auditing daemon.

Rationale:

Placing /var/log/audit in its own partition enables better separation between audit files and other files, and helps ensure that auditing cannot be halted due to the partition running out of space.

Encrypt Partitionsrule

SUSE Linux Enterprise 12 natively supports partition encryption through the Linux Unified Key Setup-on-disk-format (LUKS) technology. The easiest way to encrypt a partition is during installation time.

For manual installations, select the Encrypt checkbox during partition creation to encrypt the partition. When this option is selected the system will prompt for a passphrase to use in decrypting the partition. The passphrase will subsequently need to be entered manually every time the system boots.

Detailed information on encrypting partitions using LUKS or LUKS ciphers can be found on the SUSE Linux Enterprise 12 Documentation web site:
https://www.suse.com/documentation/sled-12/book_security/data/sec_security_cryptofs_y2.html

Rationale:

The risk of a system's physical compromise, particularly mobile systems such as laptops, places its data at risk of compromise. Encrypting this data mitigates the risk of its loss if the system is lost.

Ensure /var Located On Separate Partitionrule

The /var directory is used by daemons and other system services to store frequently-changing data. Ensure that /var has its own partition or logical volume at installation time, or migrate it using LVM.

Rationale:

Ensuring that /var is mounted on its own partition enables the setting of more restrictive mount options. This helps protect system services such as daemons or other programs which use it. It is not uncommon for the /var directory to contain world-writable directories installed by other software packages.

Account and Access Controlgroup

In traditional Unix security, if an attacker gains shell access to a certain login account, they can perform any action or access any file to which that account has access. Therefore, making it more difficult for unauthorized people to gain shell access to accounts, particularly to privileged accounts, is a necessary part of securing a system. This section introduces mechanisms for restricting access to accounts under SUSE Linux Enterprise 12.

contains 50 rules

Protect Accounts by Restricting Password-Based Logingroup

Conventionally, Unix shell accounts are accessed by providing a username and password to a login program, which tests these values for correctness using the /etc/passwd and /etc/shadow files. Password-based login is vulnerable to guessing of weak passwords, and to sniffing and man-in-the-middle attacks against passwords entered over a network or at an insecure console. Therefore, mechanisms for accessing accounts by entering usernames and passwords should be restricted to those which are operationally necessary.

contains 12 rules

Verify Proper Storage and Existence of Password Hashesgroup

By default, password hashes for local accounts are stored in the second field (colon-separated) in /etc/shadow. This file should be readable only by processes running with root credentials, preventing users from casually accessing others' password hashes and attempting to crack them. However, it remains possible to misconfigure the system and store password hashes in world-readable files such as /etc/passwd, or to even store passwords themselves in plaintext on the system. Using system-provided tools for password change/creation should allow administrators to avoid such misconfiguration.

contains 2 rules

Prevent Login to Accounts With Empty Passwordrule

If an account is configured for password authentication but does not have an assigned password, it may be possible to log into the account without authentication. Remove any instances of the nullok in password authentication configurations in /etc/pam.d/ to prevent logins with empty passwords.

Rationale:

If an account has an empty password, anyone could log in and run commands with the privileges of that account. Accounts with empty passwords should never be used in operational environments.

Remediation script:
- name: Find files in /etc/pam.d/ with password auth
  find:
    paths: /etc/pam.d
    contains: .*pam_unix\.so.*nullok.*
    recurse: true
  register: find_pam_conf_files_result
  tags:
    - CCE-83039-8
    - CJIS-5.5.2
    - DISA-STIG-SLES-12-010231
    - NIST-800-171-3.1.1
    - NIST-800-171-3.1.5
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(a)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.3
    - configure_strategy
    - high_severity
    - low_complexity
    - medium_disruption
    - no_empty_passwords
    - no_reboot_needed

- name: Prevent Log In to Accounts with Empty Password
  replace:
    dest: '{{ item.path }}'
    regexp: nullok
  with_items: '{{ find_pam_conf_files_result.files }}'
  tags:
    - CCE-83039-8
    - CJIS-5.5.2
    - DISA-STIG-SLES-12-010231
    - NIST-800-171-3.1.1
    - NIST-800-171-3.1.5
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(a)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.3
    - configure_strategy
    - high_severity
    - low_complexity
    - medium_disruption
    - no_empty_passwords
    - no_reboot_needed

Verify All Account Password Hashes are Shadowed with SHA512rule

Verify the SUSE operating system requires the shadow password suite configuration be set to encrypt interactive user passwords using a strong cryptographic hash. Check that the interactive user account passwords are using a strong password hash with the following command:

# sudo cut -d: -f2 /etc/shadow
$6$kcOnRq/5$NUEYPuyL.wghQwWssXRcLRFiiru7f5JPV6GaJhNC2aK5F3PZpE/BCCtwrxRc/AInKMNX3CdMw11m9STiql12f/
Password hashes ! or * indicate inactive accounts not available for logon and are not evaluated. If any interactive user password hash does not begin with $6, this is a finding.

Rationale:

The system must use a strong hashing algorithm to store the password. The system must use a sufficient number of hashing rounds to ensure the required level of entropy.

Set Password Expiration Parametersgroup

The file /etc/login.defs controls several password-related settings. Programs such as passwd, su, and login consult /etc/login.defs to determine behavior with regard to password aging, expiration warnings, and length. See the man page login.defs(5) for more information.

Users should be forced to change their passwords, in order to decrease the utility of compromised passwords. However, the need to change passwords often should be balanced against the risk that users will reuse or write down passwords if forced to change them too often. Forcing password changes every 90-360 days, depending on the environment, is recommended. Set the appropriate value as PASS_MAX_DAYS and apply it to existing accounts with the -M flag.

The PASS_MIN_DAYS (-m) setting prevents password changes for 7 days after the first change, to discourage password cycling. If you use this setting, train users to contact an administrator for an emergency password change in case a new password becomes compromised. The PASS_WARN_AGE (-W) setting gives users 7 days of warnings at login time that their passwords are about to expire.

For example, for each existing human user USER, expiration parameters could be adjusted to a 180 day maximum password age, 7 day minimum password age, and 7 day warning period with the following command:

$ sudo chage -M 180 -m 7 -W 7 USER

contains 4 rules

Set Existing Passwords Maximum Agerule

Configure non-compliant accounts to enforce a 60-day maximum password lifetime restriction by running the following command:

$ sudo chage -M 60 USER

Rationale:

Any password, no matter how complex, can eventually be cracked. Therefore, passwords need to be changed periodically. If the operating system does not limit the lifetime of passwords and force users to change their passwords, there is the risk that the operating system passwords could be compromised.

Set Existing Passwords Minimum Agerule

Configure non-compliant accounts to enforce a 24 hours/1 day minimum password lifetime by running the following command:

$ sudo chage -m 1 USER

Rationale:

Enforcing a minimum password lifetime helps to prevent repeated password changes to defeat the password reuse or history enforcement requirement. If users are allowed to immediately and continually change their password, the password could be repeatedly changed in a short period of time to defeat the organization's policy regarding password reuse.

Restrict Root Loginsgroup

Direct root logins should be allowed only for emergency use. In normal situations, the administrator should access the system via a unique unprivileged account, and then use su or sudo to execute privileged commands. Discouraging administrators from accessing the root account directly ensures an audit trail in organizations with multiple administrators. Locking down the channels through which root can connect directly also reduces opportunities for password-guessing against the root account. The login program uses the file /etc/securetty to determine which interfaces should allow root logins. The virtual devices /dev/console and /dev/tty* represent the system consoles (accessible via the Ctrl-Alt-F1 through Ctrl-Alt-F6 keyboard sequences on a default installation). The default securetty file also contains /dev/vc/*. These are likely to be deprecated in most environments, but may be retained for compatibility. Root should also be prohibited from connecting via network protocols. Other sections of this document include guidance describing how to prevent root from logging in via SSH.

contains 1 rule

Verify Only Root Has UID 0rule

If any account other than root has a UID of 0, this misconfiguration should be investigated and the accounts other than root should be removed or have their UID changed.
If the account is associated with system commands or applications the UID should be changed to one greater than "0" but less than "1000." Otherwise assign a UID greater than "1000" that has not already been assigned.

Rationale:

An account has root authority if it has a UID of 0. Multiple accounts with a UID of 0 afford more opportunity for potential intruders to guess a password for a privileged account. Proper configuration of sudo is recommended to afford multiple system administrators access to root privileges in an accountable manner.

Remediation script:
awk -F: '$3 == 0 && $1 != "root" { print $1 }' /etc/passwd | xargs --max-lines=1 passwd -l
Remediation script:
- name: get all /etc/passwd file entries
  getent:
    database: passwd
    split: ':'
  tags:
    - CCE-83020-8
    - DISA-STIG-SLES-12-010650
    - NIST-800-171-3.1.1
    - NIST-800-171-3.1.5
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1(iv)
    - accounts_no_uid_except_zero
    - high_severity
    - low_complexity
    - low_disruption
    - no_reboot_needed
    - restrict_strategy

- name: lock the password of the user accounts other than root with uid 0
  command: passwd -l {{ item.key }}
  loop: '{{ getent_passwd | dict2items | rejectattr(''key'', ''search'', ''root'')
    | list }}'
  when: item.value.1  == '0'
  tags:
    - CCE-83020-8
    - DISA-STIG-SLES-12-010650
    - NIST-800-171-3.1.1
    - NIST-800-171-3.1.5
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1(iv)
    - accounts_no_uid_except_zero
    - high_severity
    - low_complexity
    - low_disruption
    - no_reboot_needed
    - restrict_strategy
contains 4 rules

Policy Requires Immediate Change of Temporary Passwordsrule

Temporary passwords for SUSE operating system logons must require an immediate change to a permanent password. Verify that a policy exists that ensures when a user is created, it is creating using a method that forces a user to change their password upon their next login.

Rationale:

Without providing this capability, an account may be created without a password. Nonrepudiation cannot be guaranteed once an account is created if a user is not forced to change the temporary password upon initial logon. Temporary passwords are typically used to allow access when new accounts are created or passwords are changed. It is common practice for administrators to create temporary passwords for user accounts that allow the users to log on, yet force them to change the password once they have successfully authenticated.

identifiers:  CCE-83205-5

references:  CCI-002041, IA-5(1)(f), SRG-OS-000380-GPOS-00165, SLES-12-010660

Secure Session Configuration Files for Login Accountsgroup

When a user logs into a Unix account, the system configures the user's session by reading a number of files. Many of these files are located in the user's home directory, and may have weak permissions as a result of user error or misconfiguration. If an attacker can modify or even read certain types of account configuration information, they can often gain full access to the affected user's account. Therefore, it is important to test and correct configuration file permissions for interactive accounts, particularly those of privileged users such as root or system administrators.

contains 12 rules

Ensure that Users Have Sensible Umask Valuesgroup

The umask setting controls the default permissions for the creation of new files. With a default umask setting of 077, files and directories created by users will not be readable by any other user on the system. Users who wish to make specific files group- or world-readable can accomplish this by using the chmod command. Additionally, users can make all their files readable to their group by default by setting a umask of 027 in their shell configuration files. If default per-user groups exist (that is, if every user has a default group whose name is the same as that user's username and whose only member is the user), then it may even be safe for users to select a umask of 007, making it very easy to intentionally share files with groups of which the user is a member.

contains 1 rule

User Initialization Files Must Not Run World-Writable Programsrule

Set the mode on files being executed by the user initialization files with the following command:

$ sudo chmod 0755 FILE

Rationale:

If user start-up files execute world-writable programs, especially in unprotected directories, they could be maliciously modified to destroy user files or otherwise compromise the system at the user level. If the system is compromised at the user level, it is easier to elevate privileges to eventually compromise the system at the root and network level.

identifiers:  CCE-83099-2

references:  CCI-000366, SRG-OS-000480-GPOS-00227, SLES-12-010780, SV-217177r646731_rule

Ensure the Logon Failure Delay is Set Correctly in login.defsrule

To ensure the logon failure delay controlled by /etc/login.defs is set properly, add or correct the FAIL_DELAY setting in /etc/login.defs to read as follows:

FAIL_DELAY 4

Rationale:

Increasing the time between a failed authentication attempt and re-prompting to enter credentials helps to slow a single-threaded brute force attack.

Remediation script:
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CCE-83028-1
    - DISA-STIG-SLES-12-010140
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - accounts_logon_fail_delay
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy
- name: XCCDF Value var_accounts_fail_delay # promote to variable
  set_fact:
    var_accounts_fail_delay: !!str 4
  tags:
    - always

- name: Set accounts logon fail delay
  lineinfile:
    dest: /etc/login.defs
    regexp: ^FAIL_DELAY
    line: FAIL_DELAY {{ var_accounts_fail_delay }}
    create: true
  when: '"shadow" in ansible_facts.packages'
  tags:
    - CCE-83028-1
    - DISA-STIG-SLES-12-010140
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - accounts_logon_fail_delay
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

All Interactive User Home Directories Must Have mode 0750 Or Less Permissiverule

Change the mode of interactive users home directories to 0750. To change the mode of interactive users home directory, use the following command:

$ sudo chmod 0750 /home/USER

Rationale:

Excessive permissions on local interactive user home directories may allow unauthorized access to user files by other users.

identifiers:  CCE-83076-0

references:  CCI-000366, SRG-OS-000480-GPOS-00227, SLES-12-010740, SV-217173r603887_rule

Set Interactive Session Timeoutrule

Setting the TMOUT option in /etc/profile ensures that all user sessions will terminate based on inactivity. The TMOUT setting in /etc/profile.d/autologout.sh should read as follows:

TMOUT=900
readonly TMOUT export TMOUT

Rationale:

Terminating an idle session within a short time period reduces the window of opportunity for unauthorized personnel to take control of a management session enabled on the console or console port that has been left unattended.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then


var_accounts_tmout="900"



if [ -f /etc/profile.d/autologout.sh ]; then
    if grep --silent '^\s*TMOUT' /etc/profile.d/autologout.sh ; then
        sed -i -E "s/^(\s*)TMOUT\s*=\s*(\w|\$)*(.*)$/\1TMOUT=$var_accounts_tmout\3/g" /etc/profile.d/autologout.sh
    fi
else
    echo -e "\n# Set TMOUT to $var_accounts_tmout per security requirements" >> /etc/profile.d/autologout.sh
    echo "TMOUT=$var_accounts_tmout" >> /etc/profile.d/autologout.sh
fi
if ! grep --silent '^\s*readonly TMOUT' /etc/profile.d/autologout.sh ; then
    echo "readonly TMOUT" >> /etc/profile.d/autologout.sh
fi

if ! grep --silent '^\s*export TMOUT' /etc/profile.d/autologout.sh ; then
    echo "export TMOUT" >> /etc/profile.d/autologout.sh
fi
chmod +x /etc/profile.d/autologout.sh

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: XCCDF Value var_accounts_tmout # promote to variable
  set_fact:
    var_accounts_tmout: !!str 900
  tags:
    - always

- name: Set Interactive Session Timeout
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/profile.d/autologout.sh
        create: false
        regexp: ^\s*TMOUT=
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/profile.d/autologout.sh
      lineinfile:
        path: /etc/profile.d/autologout.sh
        create: false
        regexp: ^\s*TMOUT=
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/profile.d/autologout.sh
      lineinfile:
        path: /etc/profile.d/autologout.sh
        create: true
        regexp: ^\s*TMOUT=
        line: TMOUT={{ var_accounts_tmout }}
        state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83011-7
    - DISA-STIG-SLES-12-010090
    - NIST-800-171-3.1.11
    - NIST-800-53-AC-11(a)
    - accounts_tmout
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Set Interactive Session Timeout
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/profile.d/autologout.sh
        create: false
        regexp: ^\s*readonly\s+
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/profile.d/autologout.sh
      lineinfile:
        path: /etc/profile.d/autologout.sh
        create: false
        regexp: ^\s*readonly\s+
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/profile.d/autologout.sh
      lineinfile:
        path: /etc/profile.d/autologout.sh
        create: true
        regexp: ^\s*readonly\s+
        line: readonly TMOUT
        state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83011-7
    - DISA-STIG-SLES-12-010090
    - NIST-800-171-3.1.11
    - NIST-800-53-AC-11(a)
    - accounts_tmout
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Set Interactive Session Timeout
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/profile.d/autologout.sh
        create: false
        regexp: ^\s*export\s+
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/profile.d/autologout.sh
      lineinfile:
        path: /etc/profile.d/autologout.sh
        create: false
        regexp: ^\s*export\s+
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/profile.d/autologout.sh
      lineinfile:
        path: /etc/profile.d/autologout.sh
        create: true
        regexp: ^\s*export\s+
        line: export TMOUT
        state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83011-7
    - DISA-STIG-SLES-12-010090
    - NIST-800-171-3.1.11
    - NIST-800-53-AC-11(a)
    - accounts_tmout
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Set the permission for /etc/profile.d/autologout.sh
  file:
    path: /etc/profile.d/autologout.sh
    mode: '0755'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83011-7
    - DISA-STIG-SLES-12-010090
    - NIST-800-171-3.1.11
    - NIST-800-53-AC-11(a)
    - accounts_tmout
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

All Interactive Users Home Directories Must Existrule

Create home directories to all interactive users that currently do not have a home directory assigned. Use the following commands to create the user home directory assigned in /etc/passwd:

$ sudo mkdir /home/USER

Rationale:

If a local interactive user has a home directory defined that does not exist, the user may be given access to the / directory as the current working directory upon logon. This could create a Denial of Service because the user would not be able to access their logon configuration files, and it may give them visibility to system files they normally would not be able to access.

identifiers:  CCE-83074-5

references:  CCI-000366, SRG-OS-000480-GPOS-00227, SLES-12-010730, SV-217172r603885_rule

Ensure All User Initialization Files Have Mode 0740 Or Less Permissiverule

Set the mode of the user initialization files to 0740 with the following command:

$ sudo chmod 0740 /home/USER/.INIT_FILE

Rationale:

Local initialization files are used to configure the user's shell environment upon logon. Malicious modification of these files could compromise accounts upon logon.

identifiers:  CCE-83097-6

references:  CCI-000366, SRG-OS-000480-GPOS-00227, SLES-12-010760, SV-217175r603262_rule

All Interactive User Home Directories Must Be Group-Owned By The Primary Userrule

Change the group owner of interactive users home directory to the group found in /etc/passwd. To change the group owner of interactive users home directory, use the following command:

$ sudo chgrp USER_GROUP /home/USER

Rationale:

If the Group Identifier (GID) of a local interactive users home directory is not the same as the primary GID of the user, this would allow unauthorized access to the users files, and users that share the same group may not be able to access files that they legitimately should.

identifiers:  CCE-83096-8

references:  CCI-000366, SRG-OS-000480-GPOS-00227, SLES-12-010750, SV-217174r603889_rule

Ensure that Users Path Contains Only Local Directoriesrule

Ensure that all interactive user initialization files executable search path statements do not contain statements that will reference a working directory other than the users home directory.

Rationale:

The executable search path (typically the PATH environment variable) contains a list of directories for the shell to search to find executables. If this path includes the current working directory (other than the users home directory), executables in these directories may be executed instead of system commands. This variable is formatted as a colon-separated list of directories. If there is an empty entry, such as a leading or trailing colon or two consecutive colons, this is interpreted as the current working directory. If deviations from the default system search path for the local interactive user are required, they must be documented with the Information System Security Officer (ISSO).

identifiers:  CCE-83098-4

references:  CCI-000366, SRG-OS-000480-GPOS-00227, SLES-12-010770, SV-217176r603262_rule

All Interactive Users Must Have A Home Directory Definedrule

Assign home directories to all interactive users that currently do not have a home directory assigned.

Rationale:

If local interactive users are not assigned a valid home directory, there is no place for the storage and control of files they should own.

identifiers:  CCE-83075-2

references:  CCI-000366, SRG-OS-000480-GPOS-00227, SLES-12-010710, SV-217170r646728_rule

Protect Physical Console Accessgroup

It is impossible to fully protect a system from an attacker with physical access, so securing the space in which the system is located should be considered a necessary step. However, there are some steps which, if taken, make it more difficult for an attacker to quickly or undetectably modify a system from its console.

contains 6 rules

Configure Screen Lockinggroup

When a user must temporarily leave an account logged-in, screen locking should be employed to prevent passersby from abusing the account. User education and training is particularly important for screen locking to be effective, and policies can be implemented to reinforce this.

Automatic screen locking is only meant as a safeguard for those cases where a user forgot to lock the screen.

contains 5 rules

Configure Console Screen Lockinggroup

A console screen locking mechanism is a temporary action taken when a user stops work and moves away from the immediate physical vicinity of the information system but does not logout because of the temporary nature of the absence. Rather than relying on the user to manually lock their operation system session prior to vacating the vicinity, operating systems need to be able to identify when a user's session has idled and take action to initiate the session lock.

contains 1 rule

Check that vlock is installed to allow session lockingrule

The SUSE operating system must have vlock installed to allow for session locking. The kbd package can be installed with the following command:

$ sudo zypper install kbd

Rationale:

A session lock is a temporary action taken when a user stops work and moves away from the immediate physical vicinity of the information system but does not want to log out because of the temporary nature of the absence. The session lock is implemented at the point where session activity can be determined. Regardless of where the session lock is determined and implemented, once invoked, the session lock must remain in place until the user reauthenticates. No other activity aside from reauthentication must unlock the system.

Remediation script:

zypper install -y "kbd"
Remediation script:
- name: Ensure kbd is installed
  package:
    name: kbd
    state: present
  tags:
    - CCE-83009-1
    - DISA-STIG-SLES-12-010070
    - NIST-800-53-AC-11(1)
    - NIST-800-53-AC-11(a)
    - NIST-800-53-AC-11(b)
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - vlock_installed
Remediation script:
include install_kbd

class install_kbd {
  package { 'kbd':
    ensure => 'installed',
  }
}
Remediation script:

[[packages]]
name = "kbd"
version = "*"
contains 4 rules

Configure Smart Card Certificate Status Checkingrule

Configure the operating system to do certificate status checking for PKI authentication. Modify all of the cert_policy lines in /etc/pam_pkcs11/pam_pkcs11.conf to include ocsp_on like so:

cert_policy = ca, ocsp_on, signature;

Rationale:

Using an authentication device, such as a CAC or token that is separate from the information system, ensures that even if the information system is compromised, that compromise will not affect credentials stored on the authentication device.

Multifactor solutions that require devices separate from information systems gaining access include, for example, hardware tokens providing time-based or challenge-response authenticators and smart cards such as the U.S. Government Personal Identity Verification card and the DoD Common Access Card.

Remediation script:
- name: package facts
  package_facts: null
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83178-4
    - DISA-STIG-SLES-12-030510
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - smartcard_configure_cert_checking

- name: Replace 'none' from cert_policy
  replace:
    path: /etc/pam_pkcs11/pam_pkcs11.conf
    regexp: (^\s*cert_policy\s*=\s*)none\s*;(\s*$)
    replace: \g<1>ocsp_on,ca,signature;\g<2>
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '''pam_pkcs11'' in ansible_facts.packages'
  tags:
    - CCE-83178-4
    - DISA-STIG-SLES-12-030510
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - smartcard_configure_cert_checking

- name: Add 'ocsp_on' parameter for cert_policy in /etc/pam_pkcs11/pam_pkcs11.conf
  replace:
    path: /etc/pam_pkcs11/pam_pkcs11.conf
    regexp: (^\s*cert_policy\s*=\s*)(?!.*ocsp_on)(.*)
    replace: \g<1>ocsp_on,\g<2>
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '''pam_pkcs11'' in ansible_facts.packages'
  tags:
    - CCE-83178-4
    - DISA-STIG-SLES-12-030510
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - smartcard_configure_cert_checking

Install Smart Card Packages For Multifactor Authenticationrule

Configure the operating system to implement multifactor authentication by installing the required package with the following command: The pam_pkcs11 package can be installed with the following command:

$ sudo zypper install pam_pkcs11
The mozilla-nss package can be installed with the following command:
$ sudo zypper install mozilla-nss
The mozilla-nss-tools package can be installed with the following command:
$ sudo zypper install mozilla-nss-tools
The pcsc-ccid package can be installed with the following command:
$ sudo zypper install pcsc-ccid
The pcsc-lite package can be installed with the following command:
$ sudo zypper install pcsc-lite
The pcsc-tools package can be installed with the following command:
$ sudo zypper install pcsc-tools
The opensc package can be installed with the following command:
$ sudo zypper install opensc
The coolkey package can be installed with the following command:
$ sudo zypper install coolkey

Rationale:

Using an authentication device, such as a CAC or token that is separate from the information system, ensures that even if the information system is compromised, that compromise will not affect credentials stored on the authentication device.

Multifactor solutions that require devices separate from information systems gaining access include, for example, hardware tokens providing time-based or challenge-response authenticators and smart cards such as the U.S. Government Personal Identity Verification card and the DoD Common Access Card.

Remediation script:
- name: Set smartcard packages fact
  set_fact:
    smartcard_packages:
      - pam_pkcs11
      - mozilla-nss
      - mozilla-nss-tools
      - pcsc-ccid
      - pcsc-lite
      - pcsc-tools
      - opensc
      - coolkey
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83177-6
    - DISA-STIG-SLES-12-030500
    - NIST-800-53-CM-6(a)
    - enable_strategy
    - install_smartcard_packages
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Ensure {{ smartcard_packages }} are installed
  package:
    name: '{{ smartcard_packages }}'
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83177-6
    - DISA-STIG-SLES-12-030500
    - NIST-800-53-CM-6(a)
    - enable_strategy
    - install_smartcard_packages
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

Configure Smart Card Certificate Authority Validationrule

Configure the operating system to do certificate status checking for PKI authentication. Modify all of the cert_policy lines in /etc/pam_pkcs11/pam_pkcs11.conf to include ca like so:

cert_policy = ca, ocsp_on, signature;

Rationale:

Using an authentication device, such as a CAC or token that is separate from the information system, ensures that even if the information system is compromised, that compromise will not affect credentials stored on the authentication device.

Multifactor solutions that require devices separate from information systems gaining access include, for example, hardware tokens providing time-based or challenge-response authenticators and smart cards such as the U.S. Government Personal Identity Verification card and the DoD Common Access Card.

Remediation script:
- name: package facts
  package_facts: null
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83198-2
    - DISA-STIG-SLES-12-030530
    - NIST-800-53-IA-5 (2)
    - NIST-800-53-IA-5 (2).1
    - NIST-800-53-IA-5(2)(a)
    - NIST-800-53-IA-5(2)(d)
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - smartcard_configure_ca

- name: Replace 'none' from cert_policy
  replace:
    path: /etc/pam_pkcs11/pam_pkcs11.conf
    regexp: (^\s*cert_policy\s*=\s*)none\s*;(\s*$)
    replace: \g<1>ocsp_on,ca,signature;\g<2>
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '''pam_pkcs11'' in ansible_facts.packages'
  tags:
    - CCE-83198-2
    - DISA-STIG-SLES-12-030530
    - NIST-800-53-IA-5 (2)
    - NIST-800-53-IA-5 (2).1
    - NIST-800-53-IA-5(2)(a)
    - NIST-800-53-IA-5(2)(d)
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - smartcard_configure_ca

- name: Add 'ca' parameter for cert_policy in /etc/pam_pkcs11/pam_pkcs11.conf
  replace:
    path: /etc/pam_pkcs11/pam_pkcs11.conf
    regexp: (^\s*cert_policy\s*=\s*)(?!.*ca)(.*)
    replace: \g<1>ca,\g<2>
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '''pam_pkcs11'' in ansible_facts.packages'
  tags:
    - CCE-83198-2
    - DISA-STIG-SLES-12-030530
    - NIST-800-53-IA-5 (2)
    - NIST-800-53-IA-5 (2).1
    - NIST-800-53-IA-5(2)(a)
    - NIST-800-53-IA-5(2)(d)
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - smartcard_configure_ca

Enable Smart Card Logins in PAMrule

This requirement only applies to components where this is specific to the function of the device or has the concept of an organizational user (e.g., VPN, proxy capability). This does not apply to authentication for the purpose of configuring the device itself (management). Check that the pam_pkcs11.so option is configured in the etc/pam.d/common-auth file with the following command:

# grep pam_pkcs11.so /etc/pam.d/common-auth

auth sufficient pam_pkcs11.so
For general information about enabling smart card authentication, consult the documentation at:

Rationale:

Smart card login provides two-factor authentication stronger than that provided by a username and password combination. Smart cards leverage PKI (public key infrastructure) in order to provide and verify credentials. Using an authentication device, such as a CAC or token that is separate from the information system, ensures that even if the information system is compromised, that compromise will not affect credentials stored on the authentication device. Multifactor solutions that require devices separate from information systems gaining access include, for example, hardware tokens providing time-based or challenge-response authenticators and smart cards such as the U.S. Government Personal Identity Verification card and the DoD Common Access Card.

Remediation script:
- name: Gather list of packages
  package_facts:
    manager: auto
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83208-9
    - DISA-STIG-SLES-12-030520
    - NIST-800-53-IA-2(1)
    - NIST-800-53-IA-2(1).1
    - NIST-800-53-IA-2(11)
    - NIST-800-53-IA-2(12)
    - NIST-800-53-IA-2(2)
    - NIST-800-53-IA-2(2).1
    - NIST-800-53-IA-2(3)
    - NIST-800-53-IA-2(3).1
    - NIST-800-53-IA-2(4)
    - NIST-800-53-IA-2(4).1
    - NIST-800-53-IA-5(2)
    - NIST-800-53-IA-5(2)(c)
    - NIST-800-53-IA-5(2).1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - smartcard_pam_enabled

- name: Check to see if 'pam_pkcs11' module is configured in '/etc/pam.d/common-auth'
  shell: grep -E '^\s*auth\s+\S+\s+pam_pkcs11\.so' /etc/pam.d/common-auth || true
  register: check_pam_pkcs11_module_result
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"pam_pkcs11" in ansible_facts.packages'
  tags:
    - CCE-83208-9
    - DISA-STIG-SLES-12-030520
    - NIST-800-53-IA-2(1)
    - NIST-800-53-IA-2(1).1
    - NIST-800-53-IA-2(11)
    - NIST-800-53-IA-2(12)
    - NIST-800-53-IA-2(2)
    - NIST-800-53-IA-2(2).1
    - NIST-800-53-IA-2(3)
    - NIST-800-53-IA-2(3).1
    - NIST-800-53-IA-2(4)
    - NIST-800-53-IA-2(4).1
    - NIST-800-53-IA-5(2)
    - NIST-800-53-IA-5(2)(c)
    - NIST-800-53-IA-5(2).1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - smartcard_pam_enabled

- name: Configure 'pam_pkcs11' module in '/etc/pam.d/common-auth'
  lineinfile:
    path: /etc/pam.d/common-auth
    line: auth sufficient pam_pkcs11.so
    insertafter: ^\s*#
    state: present
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"pam_pkcs11" in ansible_facts.packages'
    - '"pam_pkcs11.so" not in check_pam_pkcs11_module_result.stdout'
  tags:
    - CCE-83208-9
    - DISA-STIG-SLES-12-030520
    - NIST-800-53-IA-2(1)
    - NIST-800-53-IA-2(1).1
    - NIST-800-53-IA-2(11)
    - NIST-800-53-IA-2(12)
    - NIST-800-53-IA-2(2)
    - NIST-800-53-IA-2(2).1
    - NIST-800-53-IA-2(3)
    - NIST-800-53-IA-2(3).1
    - NIST-800-53-IA-2(4)
    - NIST-800-53-IA-2(4).1
    - NIST-800-53-IA-5(2)
    - NIST-800-53-IA-5(2)(c)
    - NIST-800-53-IA-5(2).1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - smartcard_pam_enabled

- name: Ensure 'pam_pkcs11' module has 'sufficient' control flag
  lineinfile:
    path: /etc/pam.d/common-auth
    regexp: ^(\s*auth\s+)\S+(\s+pam_pkcs11\.so.*)
    line: \g<1>sufficient\g<2>
    backrefs: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"pam_pkcs11" in ansible_facts.packages'
  tags:
    - CCE-83208-9
    - DISA-STIG-SLES-12-030520
    - NIST-800-53-IA-2(1)
    - NIST-800-53-IA-2(1).1
    - NIST-800-53-IA-2(11)
    - NIST-800-53-IA-2(12)
    - NIST-800-53-IA-2(2)
    - NIST-800-53-IA-2(2).1
    - NIST-800-53-IA-2(3)
    - NIST-800-53-IA-2(3).1
    - NIST-800-53-IA-2(4)
    - NIST-800-53-IA-2(4).1
    - NIST-800-53-IA-5(2)
    - NIST-800-53-IA-5(2)(c)
    - NIST-800-53-IA-5(2).1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - smartcard_pam_enabled

Disable Ctrl-Alt-Del Reboot Activationrule

By default, SystemD will reboot the system if the Ctrl-Alt-Del key sequence is pressed.

To configure the system to ignore the Ctrl-Alt-Del key sequence from the command line instead of rebooting the system, do either of the following:

ln -sf /dev/null /etc/systemd/system/ctrl-alt-del.target
or
systemctl mask ctrl-alt-del.target


Do not simply delete the /usr/lib/systemd/system/ctrl-alt-del.service file, as this file may be restored during future system updates.

Rationale:

A locally logged-in user who presses Ctrl-Alt-Del, when at the console, can reboot the system. If accidentally pressed, as could happen in the case of mixed OS environment, this can create the risk of short-term loss of availability of systems due to unintentional reboot.

Remediation script:
- name: Disable Ctrl-Alt-Del Reboot Activation
  systemd:
    name: ctrl-alt-del.target
    masked: true
    state: stopped
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83018-2
    - DISA-STIG-SLES-12-010610
    - NIST-800-171-3.4.5
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - disable_ctrlaltdel_reboot
    - disable_strategy
    - high_severity
    - low_complexity
    - low_disruption
    - no_reboot_needed

Warning Banners for System Accessesgroup

Each system should expose as little information about itself as possible.

System banners, which are typically displayed just before a login prompt, give out information about the service or the host's operating system. This might include the distribution name and the system kernel version, and the particular version of a network service. This information can assist intruders in gaining access to the system as it can reveal whether the system is running vulnerable software. Most network services can be configured to limit what information is displayed.

Many organizations implement security policies that require a system banner provide notice of the system's ownership, provide warning to unauthorized users, and remind authorized users of their consent to monitoring.

contains 5 rules
contains 4 rules

Modify the System GUI Login Bannerrule

To configure the GUI system login banner edit /etc/gdm/banner. Replace the default text with a message compliant with the local site policy or a legal disclaimer. The DoD required text is either:

You are accessing a U.S. Government (USG) Information System (IS) that is provided for USG-authorized use only. By using this IS (which includes any device attached to this IS), you consent to the following conditions:
-The USG routinely intercepts and monitors communications on this IS for purposes including, but not limited to, penetration testing, COMSEC monitoring, network operations and defense, personnel misconduct (PM), law enforcement (LE), and counterintelligence (CI) investigations.
-At any time, the USG may inspect and seize data stored on this IS.
-Communications using, or data stored on, this IS are not private, are subject to routine monitoring, interception, and search, and may be disclosed or used for any USG-authorized purpose.
-This IS includes security measures (e.g., authentication and access controls) to protect USG interests -- not for your personal benefit or privacy.
-Notwithstanding the above, using this IS does not constitute consent to PM, LE or CI investigative searching or monitoring of the content of privileged communications, or work product, related to personal representation or services by attorneys, psychotherapists, or clergy, and their assistants. Such communications and work product are private and confidential. See User Agreement for details.


OR:

I've read & consent to terms in IS user agreem't.

Rationale:

Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance.

System use notifications are required only for access via login interfaces with human users and are not required when such human interfaces do not exist.

identifiers:  CCE-83183-4

references:  CCI-000050, AC-8(b), SLES-12-030020, SV-217260r603262_rule

Remediation script:
# Remediation is applicable only in certain platforms
if rpm --quiet -q gdm; then


login_banner_text="(N/A)"

# There was a regular-expression matching various banners, needs to be expanded
expanded=$(echo "$login_banner_text" | sed 's/(\\\\\x27)\*/\\\x27/g;s/(\\\x27)\*//g;s/\^(\(.*\)|.*$/\1/g;s/\[\\s\\n\][+*]/ /g;s/\\//g;s/[^-]- /\n\n-/g;s/(n)\**//g')
formatted=$(echo "$expanded" | fold -sw 80)

cat <<EOF >/etc/gdm/banner
$formatted

EOF

chmod 0644 /etc/gdm/banner

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CCE-83183-4
    - DISA-STIG-SLES-12-030020
    - NIST-800-53-AC-8(b)
    - banner_etc_gdm_banner
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy
- name: XCCDF Value login_banner_text # promote to variable
  set_fact:
    login_banner_text: !!str (N/A)
  tags:
    - always

- name: Modify the System GUI Login Banner
  lineinfile:
    dest: /etc/gdm/banner
    line: '{{ login_banner_text | regex_replace("^\^(.*)\$$", "\1") | regex_replace("^\((.*)\|.*\)$",
      "\1") | regex_replace("\[\\s\\n\]\+"," ") | regex_replace("\(\?:\[\\n\]\+\|\(\?:\\\\n\)\+\)",
      "\n") | regex_replace("\\", "") | wordwrap() }}'
    create: true
  when: '"gdm" in ansible_facts.packages'
  tags:
    - CCE-83183-4
    - DISA-STIG-SLES-12-030020
    - NIST-800-53-AC-8(b)
    - banner_etc_gdm_banner
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

Enable GNOME3 Login Warning Bannerrule

In the default graphical environment, displaying a login warning banner in the GNOME Display Manager's login screen can be enabled on the login screen by setting banner-message-enable to true.

To enable, add or edit banner-message-enable to /etc/dconf/db/gdm.d/00-security-settings. For example:

[org/gnome/login-screen]
banner-message-enable=true
Once the setting has been added, add a lock to /etc/dconf/db/gdm.d/locks/00-security-settings-lock to prevent user modification. For example:
/org/gnome/login-screen/banner-message-enable
After the settings have been set, run dconf update. The banner text must also be set.

Rationale:

Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance.

For U.S. Government systems, system use notifications are required only for access via login interfaces with human users and are not required when such human interfaces do not exist.

Remediation script:
# Remediation is applicable only in certain platforms
if rpm --quiet -q gdm; then

# Check for setting in any of the DConf db directories
# If files contain ibus or distro, ignore them.
# The assignment assumes that individual filenames don't contain :
readarray -t SETTINGSFILES < <(grep -r "\\[org/gnome/login-screen\\]" "/etc/dconf/db/" | grep -v 'distro\|ibus' | cut -d":" -f1)
DCONFFILE="/etc/dconf/db/gdm.d/00-security-settings"
DBDIR="/etc/dconf/db/gdm.d"

mkdir -p "${DBDIR}"

if [ "${#SETTINGSFILES[@]}" -eq 0 ]
then
    [ ! -z ${DCONFFILE} ] || echo "" >> ${DCONFFILE}
    printf '%s\n' "[org/gnome/login-screen]" >> ${DCONFFILE}
    printf '%s=%s\n' "banner-message-enable" "true" >> ${DCONFFILE}
else
    escaped_value="$(sed -e 's/\\/\\\\/g' <<< "true")"
    if grep -q "^\\s*banner-message-enable\\s*=" "${SETTINGSFILES[@]}"
    then
        sed -i "s/\\s*banner-message-enable\\s*=\\s*.*/banner-message-enable=${escaped_value}/g" "${SETTINGSFILES[@]}"
    else
        sed -i "\\|\\[org/gnome/login-screen\\]|a\\banner-message-enable=${escaped_value}" "${SETTINGSFILES[@]}"
    fi
fi

dconf update
# Check for setting in any of the DConf db directories
LOCKFILES=$(grep -r "^/org/gnome/login-screen/banner-message-enable$" "/etc/dconf/db/" | grep -v 'distro\|ibus' | cut -d":" -f1)
LOCKSFOLDER="/etc/dconf/db/gdm.d/locks"

mkdir -p "${LOCKSFOLDER}"

if [[ -z "${LOCKFILES}" ]]
then
    echo "/org/gnome/login-screen/banner-message-enable" >> "/etc/dconf/db/gdm.d/locks/00-security-settings-lock"
fi

dconf update

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CCE-83005-9
    - DISA-STIG-SLES-12-010040
    - NIST-800-171-3.1.9
    - NIST-800-53-AC-8(a)
    - NIST-800-53-AC-8(b)
    - NIST-800-53-AC-8(c)
    - dconf_gnome_banner_enabled
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

- name: Enable GNOME3 Login Warning Banner
  ini_file:
    dest: /etc/dconf/db/gdm.d/00-security-settings
    section: org/gnome/login-screen
    option: banner-message-enable
    value: 'true'
    create: true
    no_extra_spaces: true
  when: '"gdm" in ansible_facts.packages'
  tags:
    - CCE-83005-9
    - DISA-STIG-SLES-12-010040
    - NIST-800-171-3.1.9
    - NIST-800-53-AC-8(a)
    - NIST-800-53-AC-8(b)
    - NIST-800-53-AC-8(c)
    - dconf_gnome_banner_enabled
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

- name: Prevent user modification of GNOME banner-message-enabled
  lineinfile:
    path: /etc/dconf/db/gdm.d/locks/00-security-settings-lock
    regexp: ^/org/gnome/login-screen/banner-message-enable
    line: /org/gnome/login-screen/banner-message-enable
    create: true
  when: '"gdm" in ansible_facts.packages'
  tags:
    - CCE-83005-9
    - DISA-STIG-SLES-12-010040
    - NIST-800-171-3.1.9
    - NIST-800-53-AC-8(a)
    - NIST-800-53-AC-8(b)
    - NIST-800-53-AC-8(c)
    - dconf_gnome_banner_enabled
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

- name: Dconf Update
  command: dconf update
  when: '"gdm" in ansible_facts.packages'
  tags:
    - CCE-83005-9
    - DISA-STIG-SLES-12-010040
    - NIST-800-171-3.1.9
    - NIST-800-53-AC-8(a)
    - NIST-800-53-AC-8(b)
    - NIST-800-53-AC-8(c)
    - dconf_gnome_banner_enabled
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

Modify the System Login Bannerrule

To configure the system login banner edit /etc/issue. Replace the default text with a message compliant with the local site policy or a legal disclaimer. The DoD required text is either:

You are accessing a U.S. Government (USG) Information System (IS) that is provided for USG-authorized use only. By using this IS (which includes any device attached to this IS), you consent to the following conditions:
-The USG routinely intercepts and monitors communications on this IS for purposes including, but not limited to, penetration testing, COMSEC monitoring, network operations and defense, personnel misconduct (PM), law enforcement (LE), and counterintelligence (CI) investigations.
-At any time, the USG may inspect and seize data stored on this IS.
-Communications using, or data stored on, this IS are not private, are subject to routine monitoring, interception, and search, and may be disclosed or used for any USG-authorized purpose.
-This IS includes security measures (e.g., authentication and access controls) to protect USG interests -- not for your personal benefit or privacy.
-Notwithstanding the above, using this IS does not constitute consent to PM, LE or CI investigative searching or monitoring of the content of privileged communications, or work product, related to personal representation or services by attorneys, psychotherapists, or clergy, and their assistants. Such communications and work product are private and confidential. See User Agreement for details.


OR:

I've read & consent to terms in IS user agreem't.

Rationale:

Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance.

System use notifications are required only for access via login interfaces with human users and are not required when such human interfaces do not exist.

Remediation script:
- name: XCCDF Value login_banner_text # promote to variable
  set_fact:
    login_banner_text: !!str (N/A)
  tags:
    - always

- name: Modify the System Login Banner - remove incorrect banner
  file:
    state: absent
    path: /etc/issue
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83054-7
    - DISA-STIG-SLES-12-010030
    - NIST-800-171-3.1.9
    - NIST-800-53-AC-8(a)
    - NIST-800-53-AC-8.1(ii)
    - banner_etc_issue
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

- name: Modify the System Login Banner - add correct banner
  lineinfile:
    dest: /etc/issue
    line: '{{ login_banner_text | regex_replace("^\^(.*)\$$", "\1") | regex_replace("^\((.*)\|.*\)$",
      "\1") | regex_replace("\[\\s\\n\]\+"," ") | regex_replace("\(\?:\[\\n\]\+\|\(\?:\\\\n\)\+\)",
      "\n") | regex_replace("\\", "") | wordwrap() }}'
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83054-7
    - DISA-STIG-SLES-12-010030
    - NIST-800-171-3.1.9
    - NIST-800-53-AC-8(a)
    - NIST-800-53-AC-8.1(ii)
    - banner_etc_issue
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

Protect Accounts by Configuring PAMgroup

PAM, or Pluggable Authentication Modules, is a system which implements modular authentication for Linux programs. PAM provides a flexible and configurable architecture for authentication, and it should be configured to minimize exposure to unnecessary risk. This section contains guidance on how to accomplish that.

PAM is implemented as a set of shared objects which are loaded and invoked whenever an application wishes to authenticate a user. Typically, the application must be running as root in order to take advantage of PAM, because PAM's modules often need to be able to access sensitive stores of account information, such as /etc/shadow. Traditional privileged network listeners (e.g. sshd) or SUID programs (e.g. sudo) already meet this requirement. An SUID root application, userhelper, is provided so that programs which are not SUID or privileged themselves can still take advantage of PAM.

PAM looks in the directory /etc/pam.d for application-specific configuration information. For instance, if the program login attempts to authenticate a user, then PAM's libraries follow the instructions in the file /etc/pam.d/login to determine what actions should be taken.

One very important file in /etc/pam.d is /etc/pam.d/system-auth. This file, which is included by many other PAM configuration files, defines 'default' system authentication measures. Modifying this file is a good way to make far-reaching authentication changes, for instance when implementing a centralized authentication service.

warning  Be careful when making changes to PAM's configuration files. The syntax for these files is complex, and modifications can have unexpected consequences. The default configurations shipped with applications should be sufficient for most users.
warning  Running authconfig or system-config-authentication will re-write the PAM configuration files, destroying any manually made changes and replacing them with a series of system defaults. One reference to the configuration file syntax can be found at http://www.linux-pam.org/Linux-PAM-html/sag-configuration-file.html.
contains 15 rules

Set Lockouts for Failed Password Attemptsgroup

The pam_faillock PAM module provides the capability to lock out user accounts after a number of failed login attempts. Its documentation is available in /usr/share/doc/pam-VERSION/txts/README.pam_faillock.

warning  Locking out user accounts presents the risk of a denial-of-service attack. The lockout policy must weigh whether the risk of such a denial-of-service attack outweighs the benefits of thwarting password guessing attacks.
contains 3 rules

Enforce Delay After Failed Logon Attemptsrule

To configure the system to introduce a delay after failed logon attempts, add or correct the pam_faildelay settings in /etc/pam.d/common-auth to make sure its delay parameter is at least 4000000 or greater. For example:

auth required pam_faildelay.so delay=4000000

Rationale:

Limiting the number of logon attempts over a certain time interval reduces the chances that an unauthorized user may gain access to an account.

Remediation script:
- name: XCCDF Value var_password_pam_delay # promote to variable
  set_fact:
    var_password_pam_delay: !!str 4000000
  tags:
    - always

- name: Set control_flag fact
  set_fact:
    control_flag: required
  tags:
    - CCE-83176-8
    - DISA-STIG-SLES-12-010370
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1(iv)
    - accounts_passwords_pam_faildelay_delay
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check to see if 'pam_faildelay.so' module is configured in '/etc/pam.d/common-auth'
  shell: |
    set -o pipefail
    grep -E '^\s*auth\s+\S+\s+pam_faildelay.so' /etc/pam.d/common-auth || true
  register: check_pam_module_result
  tags:
    - CCE-83176-8
    - DISA-STIG-SLES-12-010370
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1(iv)
    - accounts_passwords_pam_faildelay_delay
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Configure 'pam_faildelay.so' module in '/etc/pam.d/common-auth'
  lineinfile:
    path: /etc/pam.d/common-auth
    line: auth required pam_faildelay.so
    state: present
  when: '"pam_faildelay.so" not in check_pam_module_result.stdout'
  tags:
    - CCE-83176-8
    - DISA-STIG-SLES-12-010370
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1(iv)
    - accounts_passwords_pam_faildelay_delay
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure 'pam_faildelay.so' module has conforming control flag
  lineinfile:
    path: /etc/pam.d/common-auth
    regexp: ^(\s*auth\s+)\S+(\s+pam_faildelay.so\s+.*)
    line: \g<1>required\g<2>
    backrefs: true
  when: control_flag|length
  tags:
    - CCE-83176-8
    - DISA-STIG-SLES-12-010370
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1(iv)
    - accounts_passwords_pam_faildelay_delay
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure "pam_faildelay.so" module has argument "delay={{ var_password_pam_delay
    }}"
  lineinfile:
    path: /etc/pam.d/common-auth
    regexp: ^(\s*auth\s+required\s+pam_faildelay.so(?:\s+\S+)*\s+delay=)(?:\S+)((\s+\S+)*\s*\\*\s*)$
    line: \g<1>{{ var_password_pam_delay }}\g<2>
    backrefs: true
  tags:
    - CCE-83176-8
    - DISA-STIG-SLES-12-010370
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1(iv)
    - accounts_passwords_pam_faildelay_delay
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check the presence of "delay" argument in "pam_faildelay.so" module
  shell: |
    set -o pipefail
    grep -E '^\s*auth\s+required\s+pam_faildelay.so.*\s+delay(=|\s|\s*$)' /etc/pam.d/common-auth || true
  register: check_pam_module_argument_result
  tags:
    - CCE-83176-8
    - DISA-STIG-SLES-12-010370
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1(iv)
    - accounts_passwords_pam_faildelay_delay
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Add "delay" argument to "pam_faildelay.so" module
  lineinfile:
    path: /etc/pam.d/common-auth
    regexp: ^(\s*auth\s+required\s+pam_faildelay.so)((\s+\S+)*\s*(\\)*$)
    line: \g<1> delay={{ var_password_pam_delay }}\g<2>
    backrefs: true
  when: '"delay" not in check_pam_module_argument_result.stdout'
  tags:
    - CCE-83176-8
    - DISA-STIG-SLES-12-010370
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1(iv)
    - accounts_passwords_pam_faildelay_delay
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Limit Password Reuserule

Do not allow users to reuse recent passwords. This can be accomplished by using the remember option for the pam_pwhistory PAM modules.

In the file /etc/pam.d/common-password, make sure the parameters remember and use_authtok are present, and that the value for the remember parameter is 5 or greater. For example:

password requisite pam_pwhistory.so ...existing_options... remember=5 use_authtok
The DoD STIG requirement is 5 passwords.

Rationale:

Preventing re-use of previous passwords helps ensure that a compromised password is not re-used by a user.

Remediation script:
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CCE-83173-5
    - DISA-STIG-SLES-12-010310
    - NIST-800-53-IA-5 (1).1(v)
    - NIST-800-53-IA-5(1)(e)
    - accounts_password_pam_pwhistory_remember
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
- name: XCCDF Value var_password_pam_remember # promote to variable
  set_fact:
    var_password_pam_remember: !!str 5
  tags:
    - always

- name: Set control_flag fact
  set_fact:
    control_flag: requisite
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-83173-5
    - DISA-STIG-SLES-12-010310
    - NIST-800-53-IA-5 (1).1(v)
    - NIST-800-53-IA-5(1)(e)
    - accounts_password_pam_pwhistory_remember
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check to see if 'pam_pwhistory.so' module is configured in '/etc/pam.d/common-password'
  shell: |
    set -o pipefail
    grep -E '^\s*password\s+\S+\s+pam_pwhistory.so' /etc/pam.d/common-password || true
  register: check_pam_module_result
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-83173-5
    - DISA-STIG-SLES-12-010310
    - NIST-800-53-IA-5 (1).1(v)
    - NIST-800-53-IA-5(1)(e)
    - accounts_password_pam_pwhistory_remember
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Configure 'pam_pwhistory.so' module in '/etc/pam.d/common-password'
  lineinfile:
    path: /etc/pam.d/common-password
    line: password requisite pam_pwhistory.so
    state: present
  when:
    - '"pam" in ansible_facts.packages'
    - '"pam_pwhistory.so" not in check_pam_module_result.stdout'
  tags:
    - CCE-83173-5
    - DISA-STIG-SLES-12-010310
    - NIST-800-53-IA-5 (1).1(v)
    - NIST-800-53-IA-5(1)(e)
    - accounts_password_pam_pwhistory_remember
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure 'pam_pwhistory.so' module has conforming control flag
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+)\S+(\s+pam_pwhistory.so\s+.*)
    line: \g<1>requisite\g<2>
    backrefs: true
  when:
    - '"pam" in ansible_facts.packages'
    - control_flag|length
  tags:
    - CCE-83173-5
    - DISA-STIG-SLES-12-010310
    - NIST-800-53-IA-5 (1).1(v)
    - NIST-800-53-IA-5(1)(e)
    - accounts_password_pam_pwhistory_remember
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure "pam_pwhistory.so" module has argument "remember={{ var_password_pam_remember
    }}"
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so(?:\s+\S+)*\s+remember=)(?:\S+)((\s+\S+)*\s*\\*\s*)$
    line: \g<1>{{ var_password_pam_remember }}\g<2>
    backrefs: true
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-83173-5
    - DISA-STIG-SLES-12-010310
    - NIST-800-53-IA-5 (1).1(v)
    - NIST-800-53-IA-5(1)(e)
    - accounts_password_pam_pwhistory_remember
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check the presence of "remember" argument in "pam_pwhistory.so" module
  shell: |
    set -o pipefail
    grep -E '^\s*password\s+requisite\s+pam_pwhistory.so.*\s+remember(=|\s|\s*$)' /etc/pam.d/common-password || true
  register: check_pam_module_argument_result
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-83173-5
    - DISA-STIG-SLES-12-010310
    - NIST-800-53-IA-5 (1).1(v)
    - NIST-800-53-IA-5(1)(e)
    - accounts_password_pam_pwhistory_remember
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Add "remember" argument to "pam_pwhistory.so" module
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so)((\s+\S+)*\s*(\\)*$)
    line: \g<1> remember={{ var_password_pam_remember }}\g<2>
    backrefs: true
  when:
    - '"pam" in ansible_facts.packages'
    - '"remember" not in check_pam_module_argument_result.stdout'
  tags:
    - CCE-83173-5
    - DISA-STIG-SLES-12-010310
    - NIST-800-53-IA-5 (1).1(v)
    - NIST-800-53-IA-5(1)(e)
    - accounts_password_pam_pwhistory_remember
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Set argument_value fact
  set_fact:
    argument_value: ''
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-83173-5
    - DISA-STIG-SLES-12-010310
    - NIST-800-53-IA-5 (1).1(v)
    - NIST-800-53-IA-5(1)(e)
    - accounts_password_pam_pwhistory_remember
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure "pam_pwhistory.so" module has argument "use_authtok"
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so(?:\s+\S+)*\s+use_authtok=)(?!)\S*((\s+\S+)*\s*\\*\s*)$
    line: \g<1>\g<2>
    backrefs: true
  when:
    - '"pam" in ansible_facts.packages'
    - argument_value|length
  tags:
    - CCE-83173-5
    - DISA-STIG-SLES-12-010310
    - NIST-800-53-IA-5 (1).1(v)
    - NIST-800-53-IA-5(1)(e)
    - accounts_password_pam_pwhistory_remember
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check the presence of "use_authtok" argument in "pam_pwhistory.so" module
  shell: |
    set -o pipefail
    grep -E '^\s*password\s+requisite\s+pam_pwhistory.so.*\s+use_authtok(=|\s|\s*$)' /etc/pam.d/common-password || true
  register: check_pam_module_argument_result
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-83173-5
    - DISA-STIG-SLES-12-010310
    - NIST-800-53-IA-5 (1).1(v)
    - NIST-800-53-IA-5(1)(e)
    - accounts_password_pam_pwhistory_remember
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Add "use_authtok" argument to "pam_pwhistory.so" module
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so)((\s+\S+)*\s*(\\)*$)
    line: \g<1> use_authtok\g<2>
    backrefs: true
  when:
    - '"pam" in ansible_facts.packages'
    - '"use_authtok" not in check_pam_module_argument_result.stdout'
  tags:
    - CCE-83173-5
    - DISA-STIG-SLES-12-010310
    - NIST-800-53-IA-5 (1).1(v)
    - NIST-800-53-IA-5(1)(e)
    - accounts_password_pam_pwhistory_remember
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Set Deny For Failed Password Attemptsrule

The SUSE operating system must lock an account after three consecutive invalid access attempts.

Rationale:

By limiting the number of failed logon attempts, the risk of unauthorized system access via user password guessing, otherwise known as brute-force attacks, is reduced. Limits are imposed by locking the account. To configure the operating system to lock an account after three unsuccessful consecutive access attempts using pam_tally2.so, modify the content of both /etc/pam.d/common-auth and /etc/pam.d/common-account as follows:

  • add or modify the pam_tally2.so module line in /etc/pam.d/common-auth to ensure both onerr=fail and deny=3 are present. For example:
    auth required pam_tally2.so onerr=fail silent audit deny=3
  • add or modify the following line in /etc/pam.d/common-account:
    account required pam_tally2.so

Remediation script:
function ensure_pam_module_options {
	if [ $# -lt 7 ] || [ $# -gt 8 ] ; then
                echo "$0 requires seven or eight arguments" >&2
                exit 1
        fi
	local _pamFile="$1" _type="$2" _control="$3" _module="$4" _option="$5" _valueRegex="$6" _defaultValue="$7"
	local _remove_argument=""
	if [ $# -eq 8 ] ; then
        	_remove_argument="$8"
		# convert it to lowercase
		_remove_argument=${_remove_argument,,}
	fi

	# make sure that we have a line like this in ${_pamFile} (additional options are left as-is):
	# ${_type} ${_control} ${_module} ${_option}=${_valueRegex}

	if ! [ -e "$_pamFile" ] ; then
		echo "$_pamFile doesn't exist" >&2
		exit 1
	fi

	# if remove argument only
	if [ "${_remove_argument}" = "yes" -o "${_remove_argument}" = "true" ] ; then
		sed --follow-symlinks -i -E -e "s/^(\\s*${_type}\\s+\\S+\\s+${_module}(\\s.+)?)\\s${_option}(=\\S+)?/\\1/" "${_pamFile}"
		exit 0
	fi

	# non-empty values need to be preceded by an equals sign
	[ -n "${_valueRegex}" ] && _valueRegex="=${_valueRegex}"
	# add an equals sign to non-empty values
	[ -n "${_defaultValue}" ] && _defaultValue="=${_defaultValue}"

	# fix 'type' if it's wrong
	if grep -q -P "^\\s*(?"'!'"${_type}\\s)[[:alnum:]]+\\s+[[:alnum:]]+\\s+${_module}" < "${_pamFile}" ; then
		sed --follow-symlinks -i -E -e "s/^(\\s*)[[:alnum:]]+(\\s+[[:alnum:]]+\\s+${_module})/\\1${_type}\\2/" "${_pamFile}"
	fi

	# fix 'control' if it's wrong
	if grep -q -P "^\\s*${_type}\\s+(?"'!'"${_control})[[:alnum:]]+\\s+${_module}" < "${_pamFile}" ; then
		sed --follow-symlinks -i -E -e "s/^(\\s*${_type}\\s+)[[:alnum:]]+(\\s+${_module})/\\1${_control}\\2/" "${_pamFile}"
	fi

	# fix the value for 'option' if one exists but does not match '_valueRegex'
    if grep -q -P "^\\s*${_type}\\s+${_control}\\s+${_module}(\\s.+)?\\s+${_option}(?"'!'"${_valueRegex}(\\s|\$))" < "${_pamFile}" ; then
		sed --follow-symlinks -i -E -e "s/^(\\s*${_type}\\s+${_control}\\s+${_module}(\\s.+)?\\s)${_option}=[^[:space:]]+/\\1${_option}${_defaultValue}/" "${_pamFile}"

    # add 'option=default' if option is not set
	elif grep -q -E "^\\s*${_type}\\s+${_control}\\s+${_module}" < "${_pamFile}" &&
         grep    -E "^\\s*${_type}\\s+${_control}\\s+${_module}" < "${_pamFile}" | grep -q -E -v "\\s${_option}(=|\\s|\$)" ; then

		sed --follow-symlinks -i -E -e "s/^(\\s*${_type}\\s+${_control}\\s+${_module}[^\\n]*)/\\1 ${_option}${_defaultValue}/" "${_pamFile}"
	# add a new entry if none exists
	elif ! grep -q -P "^\\s*${_type}\\s+${_control}\\s+${_module}(\\s.+)?\\s+${_option}${_valueRegex}(\\s|\$)" < "${_pamFile}" ; then
		echo "${_type} ${_control} ${_module} ${_option}${_defaultValue}" >> "${_pamFile}"
	fi
}
ensure_pam_module_options '/etc/pam.d/common-auth' 'auth' 'required' 'pam_tally2.so' 'deny' '[123]' '3'
ensure_pam_module_options '/etc/pam.d/common-auth' 'auth' 'required' 'pam_tally2.so' 'onerr' '(fail)' 'fail'
function ensure_pam_module_options {
	if [ $# -lt 7 ] || [ $# -gt 8 ] ; then
                echo "$0 requires seven or eight arguments" >&2
                exit 1
        fi
	local _pamFile="$1" _type="$2" _control="$3" _module="$4" _option="$5" _valueRegex="$6" _defaultValue="$7"
	local _remove_argument=""
	if [ $# -eq 8 ] ; then
        	_remove_argument="$8"
		# convert it to lowercase
		_remove_argument=${_remove_argument,,}
	fi

	# make sure that we have a line like this in ${_pamFile} (additional options are left as-is):
	# ${_type} ${_control} ${_module} ${_option}=${_valueRegex}

	if ! [ -e "$_pamFile" ] ; then
		echo "$_pamFile doesn't exist" >&2
		exit 1
	fi

	# if remove argument only
	if [ "${_remove_argument}" = "yes" -o "${_remove_argument}" = "true" ] ; then
		sed --follow-symlinks -i -E -e "s/^(\\s*${_type}\\s+\\S+\\s+${_module}(\\s.+)?)\\s${_option}(=\\S+)?/\\1/" "${_pamFile}"
		exit 0
	fi

	# non-empty values need to be preceded by an equals sign
	[ -n "${_valueRegex}" ] && _valueRegex="=${_valueRegex}"
	# add an equals sign to non-empty values
	[ -n "${_defaultValue}" ] && _defaultValue="=${_defaultValue}"

	# fix 'type' if it's wrong
	if grep -q -P "^\\s*(?"'!'"${_type}\\s)[[:alnum:]]+\\s+[[:alnum:]]+\\s+${_module}" < "${_pamFile}" ; then
		sed --follow-symlinks -i -E -e "s/^(\\s*)[[:alnum:]]+(\\s+[[:alnum:]]+\\s+${_module})/\\1${_type}\\2/" "${_pamFile}"
	fi

	# fix 'control' if it's wrong
	if grep -q -P "^\\s*${_type}\\s+(?"'!'"${_control})[[:alnum:]]+\\s+${_module}" < "${_pamFile}" ; then
		sed --follow-symlinks -i -E -e "s/^(\\s*${_type}\\s+)[[:alnum:]]+(\\s+${_module})/\\1${_control}\\2/" "${_pamFile}"
	fi

	# fix the value for 'option' if one exists but does not match '_valueRegex'
    if grep -q -P "^\\s*${_type}\\s+${_control}\\s+${_module}(\\s.+)?\\s+${_option}(?"'!'"${_valueRegex}(\\s|\$))" < "${_pamFile}" ; then
		sed --follow-symlinks -i -E -e "s/^(\\s*${_type}\\s+${_control}\\s+${_module}(\\s.+)?\\s)${_option}=[^[:space:]]+/\\1${_option}${_defaultValue}/" "${_pamFile}"

    # add 'option=default' if option is not set
	elif grep -q -E "^\\s*${_type}\\s+${_control}\\s+${_module}" < "${_pamFile}" &&
         grep    -E "^\\s*${_type}\\s+${_control}\\s+${_module}" < "${_pamFile}" | grep -q -E -v "\\s${_option}(=|\\s|\$)" ; then

		sed --follow-symlinks -i -E -e "s/^(\\s*${_type}\\s+${_control}\\s+${_module}[^\\n]*)/\\1 ${_option}${_defaultValue}/" "${_pamFile}"
	# add a new entry if none exists
	elif ! grep -q -P "^\\s*${_type}\\s+${_control}\\s+${_module}(\\s.+)?\\s+${_option}${_valueRegex}(\\s|\$)" < "${_pamFile}" ; then
		echo "${_type} ${_control} ${_module} ${_option}${_defaultValue}" >> "${_pamFile}"
	fi
}
ensure_pam_module_options '/etc/pam.d/common-account' 'account' 'required' 'pam_tally2.so' '' '' ''
Remediation script:
- name: Check to see if pam_tally2.so is configured in /etc/pam.d/common-auth
  shell: grep -e '^\s*auth\s\+required\s\+pam_tally2\.so' /etc/pam.d/common-auth ||
    true
  register: check_pam_tally2_result
  tags:
    - CCE-83055-4
    - DISA-STIG-SLES-12-010130
    - NIST-800-53-AC-7(a)
    - accounts_passwords_pam_tally2
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Configure pam_tally2.so module in /etc/pam.d/common-auth
  lineinfile:
    path: /etc/pam.d/common-auth
    line: auth required pam_tally2.so
    state: present
  when: '"pam_tally2" not in check_pam_tally2_result.stdout'
  tags:
    - CCE-83055-4
    - DISA-STIG-SLES-12-010130
    - NIST-800-53-AC-7(a)
    - accounts_passwords_pam_tally2
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Check to see if 'onerr' parameter is present
  shell: grep -e '^\s*auth\s\+required\s\+pam_tally2\.so.*\sonerr=.*' /etc/pam.d/common-auth
    || true
  register: check_onerr_result
  tags:
    - CCE-83055-4
    - DISA-STIG-SLES-12-010130
    - NIST-800-53-AC-7(a)
    - accounts_passwords_pam_tally2
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Make sure pam_tally2.so has 'onerr' parameter set 'fail'
  replace:
    path: /etc/pam.d/common-auth
    regexp: ^(\s*auth\s+required\s+pam_tally2\.so\s+[^\n]*)(onerr=[A-Za-z]+)([^A-Za-z]?.*)
    replace: \1onerr=fail\3
  register: onerr_update_result
  when: '"onerr=" in check_onerr_result.stdout'
  tags:
    - CCE-83055-4
    - DISA-STIG-SLES-12-010130
    - NIST-800-53-AC-7(a)
    - accounts_passwords_pam_tally2
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Add 'onerr' parameter for pam_tally2.so module in /etc/pam.d/common-auth
  lineinfile:
    path: /etc/pam.d/common-auth
    regexp: ^(\s*auth\s+required\s+pam_tally2\.so)((\s+\S+)*\s*(\\)*$)
    line: \1 onerr=fail\2
    backrefs: true
    state: present
  when: '"onerr=" not in check_onerr_result.stdout'
  tags:
    - CCE-83055-4
    - DISA-STIG-SLES-12-010130
    - NIST-800-53-AC-7(a)
    - accounts_passwords_pam_tally2
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Check to see if 'deny' parameter is present
  shell: grep -e '^\s*auth\s\+required\s\+pam_tally2\.so.*\sdeny=.*' /etc/pam.d/common-auth
    || true
  register: check_deny_result
  tags:
    - CCE-83055-4
    - DISA-STIG-SLES-12-010130
    - NIST-800-53-AC-7(a)
    - accounts_passwords_pam_tally2
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Make sure pam_tally2.so has 'deny' parameter set to less than 4
  replace:
    path: /etc/pam.d/common-auth
    regexp: ^(\s*auth\s+required\s+pam_tally2\.so\s+[^\n]*)deny=([4-9]|[1-9][0-9]+)(\s*.*)
    replace: \1deny=3\3
  when: '"deny=" in check_deny_result.stdout'
  tags:
    - CCE-83055-4
    - DISA-STIG-SLES-12-010130
    - NIST-800-53-AC-7(a)
    - accounts_passwords_pam_tally2
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Add 'deny' parameter for pam_tally2.so module in /etc/pam.d/common-auth
  lineinfile:
    path: /etc/pam.d/common-auth
    regexp: ^(\s*auth\s+required\s+pam_tally2\.so)((\s+\S+)*\s*(\\)*$)
    line: \1 deny=3\2
    backrefs: true
    state: present
  when: '"deny=" not in check_deny_result.stdout'
  tags:
    - CCE-83055-4
    - DISA-STIG-SLES-12-010130
    - NIST-800-53-AC-7(a)
    - accounts_passwords_pam_tally2
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Check to see if pam_tally2.so is configured in /etc/pam.d/common-account
  shell: grep -e '^\s*account\s\+required\s\+pam_tally2\.so' /etc/pam.d/common-account
    || true
  register: check_account_pam_tally2_result
  tags:
    - CCE-83055-4
    - DISA-STIG-SLES-12-010130
    - NIST-800-53-AC-7(a)
    - accounts_passwords_pam_tally2
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Configure pam_tally2.so module in /etc/pam.d/common-account
  lineinfile:
    path: /etc/pam.d/common-account
    line: account required pam_tally2.so
    state: present
  when: '"pam_tally2" not in check_account_pam_tally2_result.stdout'
  tags:
    - CCE-83055-4
    - DISA-STIG-SLES-12-010130
    - NIST-800-53-AC-7(a)
    - accounts_passwords_pam_tally2
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

Set Password Hashing Algorithmgroup

The system's default algorithm for storing password hashes in /etc/shadow is SHA-512. This can be configured in several locations.

contains 3 rules

Set Password Hashing Algorithm in /etc/login.defsrule

In /etc/login.defs, add or correct the following line to ensure the system will use SHA-512 as the hashing algorithm:

ENCRYPT_METHOD SHA512

Rationale:

Passwords need to be protected at all times, and encryption is the standard method for protecting passwords. If passwords are not encrypted, they can be plainly read (i.e., clear text) and easily compromised. Passwords that are encrypted with a weak algorithm are no more protected than if they are kept in plain text.

Using a stronger hashing algorithm makes password cracking attacks more difficult.

Remediation script:
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CCE-83029-9
    - CJIS-5.6.2.2
    - DISA-STIG-SLES-12-010210
    - NIST-800-171-3.13.11
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - set_password_hashing_algorithm_logindefs
- name: XCCDF Value var_password_hashing_algorithm # promote to variable
  set_fact:
    var_password_hashing_algorithm: !!str SHA512
  tags:
    - always

- name: Set Password Hashing Algorithm in /etc/login.defs
  lineinfile:
    dest: /etc/login.defs
    regexp: ^#?ENCRYPT_METHOD
    line: ENCRYPT_METHOD {{ var_password_hashing_algorithm }}
    state: present
    create: true
  when: '"shadow" in ansible_facts.packages'
  tags:
    - CCE-83029-9
    - CJIS-5.6.2.2
    - DISA-STIG-SLES-12-010210
    - NIST-800-171-3.13.11
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - set_password_hashing_algorithm_logindefs

Set PAM's Password Hashing Algorithmrule

The PAM system service can be configured to only store encrypted representations of passwords. In /etc/pam.d/common-password, the password section of the file controls which PAM modules execute during a password change. Set the pam_unix.so module in the password section to include the argument sha512, as shown below:

password    required    pam_unix.so sha512 other arguments...

This will help ensure when local users change their passwords, hashes for the new passwords will be generated using the SHA-512 algorithm. This is the default.

Rationale:

Passwords need to be protected at all times, and encryption is the standard method for protecting passwords. If passwords are not encrypted, they can be plainly read (i.e., clear text) and easily compromised. Passwords that are encrypted with a weak algorithm are no more protected than if they are kepy in plain text.

This setting ensures user and group account administration utilities are configured to store only encrypted representations of passwords. Additionally, the crypt_style configuration option ensures the use of a strong hashing algorithm that makes password cracking attacks more difficult.

Remediation script:
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CCE-83184-2
    - CJIS-5.6.2.2
    - DISA-STIG-SLES-12-010230
    - NIST-800-171-3.13.11
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - set_password_hashing_algorithm_systemauth

- name: Set control_flag fact
  set_fact:
    control_flag: required
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-83184-2
    - CJIS-5.6.2.2
    - DISA-STIG-SLES-12-010230
    - NIST-800-171-3.13.11
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - set_password_hashing_algorithm_systemauth

- name: Check to see if 'pam_unix.so' module is configured in '/etc/pam.d/common-password'
  shell: |
    set -o pipefail
    grep -E '^\s*password\s+\S+\s+pam_unix.so' /etc/pam.d/common-password || true
  register: check_pam_module_result
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-83184-2
    - CJIS-5.6.2.2
    - DISA-STIG-SLES-12-010230
    - NIST-800-171-3.13.11
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - set_password_hashing_algorithm_systemauth

- name: Configure 'pam_unix.so' module in '/etc/pam.d/common-password'
  lineinfile:
    path: /etc/pam.d/common-password
    line: password required pam_unix.so
    state: present
  when:
    - '"pam" in ansible_facts.packages'
    - '"pam_unix.so" not in check_pam_module_result.stdout'
  tags:
    - CCE-83184-2
    - CJIS-5.6.2.2
    - DISA-STIG-SLES-12-010230
    - NIST-800-171-3.13.11
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - set_password_hashing_algorithm_systemauth

- name: Ensure 'pam_unix.so' module has conforming control flag
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+)\S+(\s+pam_unix.so\s+.*)
    line: \g<1>required\g<2>
    backrefs: true
  when:
    - '"pam" in ansible_facts.packages'
    - control_flag|length
  tags:
    - CCE-83184-2
    - CJIS-5.6.2.2
    - DISA-STIG-SLES-12-010230
    - NIST-800-171-3.13.11
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - set_password_hashing_algorithm_systemauth

- name: Set argument_value fact
  set_fact:
    argument_value: ''
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-83184-2
    - CJIS-5.6.2.2
    - DISA-STIG-SLES-12-010230
    - NIST-800-171-3.13.11
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - set_password_hashing_algorithm_systemauth

- name: Ensure "pam_unix.so" module has argument "sha512"
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+required\s+pam_unix.so(?:\s+\S+)*\s+sha512=)(?!)\S*((\s+\S+)*\s*\\*\s*)$
    line: \g<1>\g<2>
    backrefs: true
  when:
    - '"pam" in ansible_facts.packages'
    - argument_value|length
  tags:
    - CCE-83184-2
    - CJIS-5.6.2.2
    - DISA-STIG-SLES-12-010230
    - NIST-800-171-3.13.11
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - set_password_hashing_algorithm_systemauth

- name: Check the presence of "sha512" argument in "pam_unix.so" module
  shell: |
    set -o pipefail
    grep -E '^\s*password\s+required\s+pam_unix.so.*\s+sha512(=|\s|\s*$)' /etc/pam.d/common-password || true
  register: check_pam_module_argument_result
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-83184-2
    - CJIS-5.6.2.2
    - DISA-STIG-SLES-12-010230
    - NIST-800-171-3.13.11
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - set_password_hashing_algorithm_systemauth

- name: Add "sha512" argument to "pam_unix.so" module
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+required\s+pam_unix.so)((\s+\S+)*\s*(\\)*$)
    line: \g<1> sha512\g<2>
    backrefs: true
  when:
    - '"pam" in ansible_facts.packages'
    - '"sha512" not in check_pam_module_argument_result.stdout'
  tags:
    - CCE-83184-2
    - CJIS-5.6.2.2
    - DISA-STIG-SLES-12-010230
    - NIST-800-171-3.13.11
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - set_password_hashing_algorithm_systemauth

Set Password Hashing Rounds in /etc/login.defsrule

In /etc/login.defs, ensure SHA_CRYPT_MIN_ROUNDS and SHA_CRYPT_MAX_ROUNDS has the minimum value of 5000. For example:

SHA_CRYPT_MIN_ROUNDS 5000
SHA_CRYPT_MAX_ROUNDS 5000
Notice that if neither are set, they already have the default value of 5000. If either is set, they must have the minimum value of 5000.

Rationale:

Passwords need to be protected at all times, and encryption is the standard method for protecting passwords. If passwords are not encrypted, they can be plainly read (i.e., clear text) and easily compromised. Passwords that are encrypted with a weak algorithm are no more protected than if they are kept in plain text.

Using more hashing rounds makes password cracking attacks more difficult.

Remediation script:
- name: Ensure SHA_CRYPT_MIN_ROUNDS has minimum value of 5000
  replace:
    path: /etc/login.defs
    regexp: (^\s*SHA_CRYPT_MIN_ROUNDS\s+)(?!(?:[5-9]\d{3,}|\d{5,}))\S*(\s*$)
    replace: \g<1>5000\g<2>
    backup: false
  tags:
    - CCE-83171-9
    - DISA-STIG-SLES-12-010240
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-5(1).1(v)
    - NIST-800-53-IA-7
    - NIST-800-53-IA-7.1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - set_password_hashing_min_rounds_logindefs

- name: Check to see if SHA_CRYPT_MIN_ROUNDS is explicitly configured
  shell: |
    set -o pipefail
    grep -e '^\s*SHA_CRYPT_MIN_ROUNDS\s\+' /etc/login.defs || true
  register: check_sha_crypt_min_rounds_result
  tags:
    - CCE-83171-9
    - DISA-STIG-SLES-12-010240
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-5(1).1(v)
    - NIST-800-53-IA-7
    - NIST-800-53-IA-7.1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - set_password_hashing_min_rounds_logindefs

- name: Ensure SHA_CRYPT_MAX_ROUNDS has minimum value of 5000
  replace:
    path: /etc/login.defs
    regexp: (^\s*SHA_CRYPT_MAX_ROUNDS\s+)(?!(?:[5-9]\d{3,}|\d{5,}))\S*(\s*$)
    replace: \g<1>5000\g<2>
    backup: false
  when: '"SHA_CRYPT_MIN_ROUNDS" not in check_sha_crypt_min_rounds_result.stdout'
  tags:
    - CCE-83171-9
    - DISA-STIG-SLES-12-010240
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-5(1).1(v)
    - NIST-800-53-IA-7
    - NIST-800-53-IA-7.1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - set_password_hashing_min_rounds_logindefs

Set Password Quality Requirementsgroup

The default pam_pwquality PAM module provides strength checking for passwords. It performs a number of checks, such as making sure passwords are not similar to dictionary words, are of at least a certain length, are not the previous password reversed, and are not simply a change of case from the previous password. It can also require passwords to be in certain character classes. The pam_pwquality module is the preferred way of configuring password requirements.

The man pages pam_pwquality(8) provide information on the capabilities and configuration of each.

contains 7 rules

Set Password Quality Requirements, if using pam_cracklibgroup

The pam_cracklib PAM module can be configured to meet requirements for a variety of policies.

For example, to configure pam_cracklib to require at least one uppercase character, lowercase character, digit, and other (special) character, locate the following line in /etc/pam.d/system-auth:

password requisite pam_cracklib.so try_first_pass retry=3
and then alter it to read:
password required pam_cracklib.so try_first_pass retry=3 maxrepeat=3 minlen=14 dcredit=-1 ucredit=-1 ocredit=-1 lcredit=-1 difok=4
If no such line exists, add one as the first line of the password section in /etc/pam.d/system-auth. The arguments can be modified to ensure compliance with your organization's security policy. Discussion of each parameter follows.

warning  Note that the password quality requirements are not enforced for the root account for some reason.
contains 7 rules

Set Password Strength Minimum Digit Charactersrule

The pam_cracklib module's dcredit parameter controls requirements for usage of digits in a password. When set to a negative number, any password will be required to contain that many digits. When set to a positive number, pam_cracklib will grant +1 additional length credit for each digit. Add dcredit=-1 after pam_cracklib.so to require use of a digit in passwords.

Rationale:

Requiring digits makes password guessing attacks more difficult by ensuring a larger search space.

Remediation script:
- name: XCCDF Value var_password_pam_dcredit # promote to variable
  set_fact:
    var_password_pam_dcredit: !!str 1
  tags:
    - always

- name: Set control_flag fact
  set_fact:
    control_flag: requisite
  tags:
    - CCE-83168-5
    - DISA-STIG-SLES-12-010170
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_dcredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check to see if 'pam_cracklib.so' module is configured in '/etc/pam.d/common-password'
  shell: |
    set -o pipefail
    grep -E '^\s*password\s+\S+\s+pam_cracklib.so' /etc/pam.d/common-password || true
  register: check_pam_module_result
  tags:
    - CCE-83168-5
    - DISA-STIG-SLES-12-010170
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_dcredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Configure 'pam_cracklib.so' module in '/etc/pam.d/common-password'
  lineinfile:
    path: /etc/pam.d/common-password
    line: password requisite pam_cracklib.so
    state: present
  when: '"pam_cracklib.so" not in check_pam_module_result.stdout'
  tags:
    - CCE-83168-5
    - DISA-STIG-SLES-12-010170
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_dcredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure 'pam_cracklib.so' module has conforming control flag
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+)\S+(\s+pam_cracklib.so\s+.*)
    line: \g<1>requisite\g<2>
    backrefs: true
  when: control_flag|length
  tags:
    - CCE-83168-5
    - DISA-STIG-SLES-12-010170
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_dcredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure "pam_cracklib.so" module has argument "dcredit={{ var_password_pam_dcredit
    }}"
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+requisite\s+pam_cracklib.so(?:\s+\S+)*\s+dcredit=)(?:\S+)((\s+\S+)*\s*\\*\s*)$
    line: \g<1>{{ var_password_pam_dcredit }}\g<2>
    backrefs: true
  tags:
    - CCE-83168-5
    - DISA-STIG-SLES-12-010170
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_dcredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check the presence of "dcredit" argument in "pam_cracklib.so" module
  shell: |
    set -o pipefail
    grep -E '^\s*password\s+requisite\s+pam_cracklib.so.*\s+dcredit(=|\s|\s*$)' /etc/pam.d/common-password || true
  register: check_pam_module_argument_result
  tags:
    - CCE-83168-5
    - DISA-STIG-SLES-12-010170
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_dcredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Add "dcredit" argument to "pam_cracklib.so" module
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+requisite\s+pam_cracklib.so)((\s+\S+)*\s*(\\)*$)
    line: \g<1> dcredit={{ var_password_pam_dcredit }}\g<2>
    backrefs: true
  when: '"dcredit" not in check_pam_module_argument_result.stdout'
  tags:
    - CCE-83168-5
    - DISA-STIG-SLES-12-010170
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_dcredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Set Password Strength Minimum Different Charactersrule

The pam_cracklib module's difok parameter controls requirements for usage of different characters during a password change. The number of changed characters refers to the number of changes required with respect to the total number of positions in the current password. In other words, characters may be the same within the two passwords; however, the positions of the like characters must be different. Make sure the difok parameter for the pam_cracklib module is configured to greater than or equal to 8.

Rationale:

Requiring a minimum number of different characters during password changes ensures that newly changed passwords should not resemble previously compromised ones. Note that passwords which are changed on compromised systems will still be compromised, however.

Remediation script:
- name: XCCDF Value var_password_pam_difok # promote to variable
  set_fact:
    var_password_pam_difok: !!str 8
  tags:
    - always

- name: Set control_flag fact
  set_fact:
    control_flag: requisite
  tags:
    - CCE-83170-1
    - DISA-STIG-SLES-12-010190
    - NIST-800-53-IA-5(b)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_difok
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check to see if 'pam_cracklib.so' module is configured in '/etc/pam.d/common-password'
  shell: |
    set -o pipefail
    grep -E '^\s*password\s+\S+\s+pam_cracklib.so' /etc/pam.d/common-password || true
  register: check_pam_module_result
  tags:
    - CCE-83170-1
    - DISA-STIG-SLES-12-010190
    - NIST-800-53-IA-5(b)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_difok
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Configure 'pam_cracklib.so' module in '/etc/pam.d/common-password'
  lineinfile:
    path: /etc/pam.d/common-password
    line: password requisite pam_cracklib.so
    state: present
  when: '"pam_cracklib.so" not in check_pam_module_result.stdout'
  tags:
    - CCE-83170-1
    - DISA-STIG-SLES-12-010190
    - NIST-800-53-IA-5(b)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_difok
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure 'pam_cracklib.so' module has conforming control flag
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+)\S+(\s+pam_cracklib.so\s+.*)
    line: \g<1>requisite\g<2>
    backrefs: true
  when: control_flag|length
  tags:
    - CCE-83170-1
    - DISA-STIG-SLES-12-010190
    - NIST-800-53-IA-5(b)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_difok
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure "pam_cracklib.so" module has argument "difok={{ var_password_pam_difok
    }}"
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+requisite\s+pam_cracklib.so(?:\s+\S+)*\s+difok=)(?:\S+)((\s+\S+)*\s*\\*\s*)$
    line: \g<1>{{ var_password_pam_difok }}\g<2>
    backrefs: true
  tags:
    - CCE-83170-1
    - DISA-STIG-SLES-12-010190
    - NIST-800-53-IA-5(b)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_difok
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check the presence of "difok" argument in "pam_cracklib.so" module
  shell: |
    set -o pipefail
    grep -E '^\s*password\s+requisite\s+pam_cracklib.so.*\s+difok(=|\s|\s*$)' /etc/pam.d/common-password || true
  register: check_pam_module_argument_result
  tags:
    - CCE-83170-1
    - DISA-STIG-SLES-12-010190
    - NIST-800-53-IA-5(b)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_difok
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Add "difok" argument to "pam_cracklib.so" module
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+requisite\s+pam_cracklib.so)((\s+\S+)*\s*(\\)*$)
    line: \g<1> difok={{ var_password_pam_difok }}\g<2>
    backrefs: true
  when: '"difok" not in check_pam_module_argument_result.stdout'
  tags:
    - CCE-83170-1
    - DISA-STIG-SLES-12-010190
    - NIST-800-53-IA-5(b)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_difok
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Set Password Minimum Lengthrule

The pam_cracklib module's minlen parameter controls requirements for minimum characters required in a password. Add minlen=15 to set minimum password length requirements.

Rationale:

Password length is one factor of several that helps to determine strength and how long it takes to crack a password. Use of more characters in a password helps to exponentially increase the time and/or resources required to compromise the password.

Remediation script:
- name: XCCDF Value var_password_pam_minlen # promote to variable
  set_fact:
    var_password_pam_minlen: !!str 15
  tags:
    - always

- name: Set control_flag fact
  set_fact:
    control_flag: requisite
  tags:
    - CCE-83188-3
    - DISA-STIG-SLES-12-010250
    - NIST-800-53-IA-5(1)(a)
    - cracklib_accounts_password_pam_minlen
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check to see if 'pam_cracklib.so' module is configured in '/etc/pam.d/common-password'
  shell: |
    set -o pipefail
    grep -E '^\s*password\s+\S+\s+pam_cracklib.so' /etc/pam.d/common-password || true
  register: check_pam_module_result
  tags:
    - CCE-83188-3
    - DISA-STIG-SLES-12-010250
    - NIST-800-53-IA-5(1)(a)
    - cracklib_accounts_password_pam_minlen
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Configure 'pam_cracklib.so' module in '/etc/pam.d/common-password'
  lineinfile:
    path: /etc/pam.d/common-password
    line: password requisite pam_cracklib.so
    state: present
  when: '"pam_cracklib.so" not in check_pam_module_result.stdout'
  tags:
    - CCE-83188-3
    - DISA-STIG-SLES-12-010250
    - NIST-800-53-IA-5(1)(a)
    - cracklib_accounts_password_pam_minlen
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure 'pam_cracklib.so' module has conforming control flag
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+)\S+(\s+pam_cracklib.so\s+.*)
    line: \g<1>requisite\g<2>
    backrefs: true
  when: control_flag|length
  tags:
    - CCE-83188-3
    - DISA-STIG-SLES-12-010250
    - NIST-800-53-IA-5(1)(a)
    - cracklib_accounts_password_pam_minlen
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure "pam_cracklib.so" module has argument "minlen={{ var_password_pam_minlen
    }}"
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+requisite\s+pam_cracklib.so(?:\s+\S+)*\s+minlen=)(?:\S+)((\s+\S+)*\s*\\*\s*)$
    line: \g<1>{{ var_password_pam_minlen }}\g<2>
    backrefs: true
  tags:
    - CCE-83188-3
    - DISA-STIG-SLES-12-010250
    - NIST-800-53-IA-5(1)(a)
    - cracklib_accounts_password_pam_minlen
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check the presence of "minlen" argument in "pam_cracklib.so" module
  shell: |
    set -o pipefail
    grep -E '^\s*password\s+requisite\s+pam_cracklib.so.*\s+minlen(=|\s|\s*$)' /etc/pam.d/common-password || true
  register: check_pam_module_argument_result
  tags:
    - CCE-83188-3
    - DISA-STIG-SLES-12-010250
    - NIST-800-53-IA-5(1)(a)
    - cracklib_accounts_password_pam_minlen
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Add "minlen" argument to "pam_cracklib.so" module
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+requisite\s+pam_cracklib.so)((\s+\S+)*\s*(\\)*$)
    line: \g<1> minlen={{ var_password_pam_minlen }}\g<2>
    backrefs: true
  when: '"minlen" not in check_pam_module_argument_result.stdout'
  tags:
    - CCE-83188-3
    - DISA-STIG-SLES-12-010250
    - NIST-800-53-IA-5(1)(a)
    - cracklib_accounts_password_pam_minlen
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Set Password Retry Limitrule

The pam_cracklib module's retry parameter controls the maximum number of times to prompt the user for the password before returning with error. Make sure it is configured with a value that is no more than 3. For example, retry=1.

Rationale:

To reduce opportunities for successful guesses and brute-force attacks.

Remediation script:
- name: XCCDF Value var_password_pam_retry # promote to variable
  set_fact:
    var_password_pam_retry: !!str 3
  tags:
    - always

- name: Set control_flag fact
  set_fact:
    control_flag: requisite
  tags:
    - CCE-83174-3
    - DISA-STIG-SLES-12-010320
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1
    - cracklib_accounts_password_pam_retry
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check to see if 'pam_cracklib.so' module is configured in '/etc/pam.d/common-password'
  shell: |
    set -o pipefail
    grep -E '^\s*password\s+\S+\s+pam_cracklib.so' /etc/pam.d/common-password || true
  register: check_pam_module_result
  tags:
    - CCE-83174-3
    - DISA-STIG-SLES-12-010320
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1
    - cracklib_accounts_password_pam_retry
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Configure 'pam_cracklib.so' module in '/etc/pam.d/common-password'
  lineinfile:
    path: /etc/pam.d/common-password
    line: password requisite pam_cracklib.so
    state: present
  when: '"pam_cracklib.so" not in check_pam_module_result.stdout'
  tags:
    - CCE-83174-3
    - DISA-STIG-SLES-12-010320
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1
    - cracklib_accounts_password_pam_retry
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure 'pam_cracklib.so' module has conforming control flag
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+)\S+(\s+pam_cracklib.so\s+.*)
    line: \g<1>requisite\g<2>
    backrefs: true
  when: control_flag|length
  tags:
    - CCE-83174-3
    - DISA-STIG-SLES-12-010320
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1
    - cracklib_accounts_password_pam_retry
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure "pam_cracklib.so" module has argument "retry={{ var_password_pam_retry
    }}"
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+requisite\s+pam_cracklib.so(?:\s+\S+)*\s+retry=)(?:\S+)((\s+\S+)*\s*\\*\s*)$
    line: \g<1>{{ var_password_pam_retry }}\g<2>
    backrefs: true
  tags:
    - CCE-83174-3
    - DISA-STIG-SLES-12-010320
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1
    - cracklib_accounts_password_pam_retry
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check the presence of "retry" argument in "pam_cracklib.so" module
  shell: |
    set -o pipefail
    grep -E '^\s*password\s+requisite\s+pam_cracklib.so.*\s+retry(=|\s|\s*$)' /etc/pam.d/common-password || true
  register: check_pam_module_argument_result
  tags:
    - CCE-83174-3
    - DISA-STIG-SLES-12-010320
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1
    - cracklib_accounts_password_pam_retry
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Add "retry" argument to "pam_cracklib.so" module
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+requisite\s+pam_cracklib.so)((\s+\S+)*\s*(\\)*$)
    line: \g<1> retry={{ var_password_pam_retry }}\g<2>
    backrefs: true
  when: '"retry" not in check_pam_module_argument_result.stdout'
  tags:
    - CCE-83174-3
    - DISA-STIG-SLES-12-010320
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1
    - cracklib_accounts_password_pam_retry
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Set Password Strength Minimum Lowercase Charactersrule

The pam_cracklib module's lcredit= parameter controls requirements for usage of lowercase letters in a password. When set to a negative number, any password will be required to contain that many lowercase characters. When set to a positive number, pam_cracklib will grant +1 additional length credit for each lowercase character. Add lcredit=-1 after pam_cracklib.so to require use of a lowercase character in passwords.

Rationale:

Requiring a minimum number of lowercase characters makes password guessing attacks more difficult by ensuring a larger search space.

Remediation script:
- name: XCCDF Value var_password_pam_lcredit # promote to variable
  set_fact:
    var_password_pam_lcredit: !!str 1
  tags:
    - always

- name: Set control_flag fact
  set_fact:
    control_flag: requisite
  tags:
    - CCE-83167-7
    - DISA-STIG-SLES-12-010160
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_lcredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check to see if 'pam_cracklib.so' module is configured in '/etc/pam.d/common-password'
  shell: |
    set -o pipefail
    grep -E '^\s*password\s+\S+\s+pam_cracklib.so' /etc/pam.d/common-password || true
  register: check_pam_module_result
  tags:
    - CCE-83167-7
    - DISA-STIG-SLES-12-010160
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_lcredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Configure 'pam_cracklib.so' module in '/etc/pam.d/common-password'
  lineinfile:
    path: /etc/pam.d/common-password
    line: password requisite pam_cracklib.so
    state: present
  when: '"pam_cracklib.so" not in check_pam_module_result.stdout'
  tags:
    - CCE-83167-7
    - DISA-STIG-SLES-12-010160
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_lcredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure 'pam_cracklib.so' module has conforming control flag
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+)\S+(\s+pam_cracklib.so\s+.*)
    line: \g<1>requisite\g<2>
    backrefs: true
  when: control_flag|length
  tags:
    - CCE-83167-7
    - DISA-STIG-SLES-12-010160
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_lcredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure "pam_cracklib.so" module has argument "lcredit={{ var_password_pam_lcredit
    }}"
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+requisite\s+pam_cracklib.so(?:\s+\S+)*\s+lcredit=)(?:\S+)((\s+\S+)*\s*\\*\s*)$
    line: \g<1>{{ var_password_pam_lcredit }}\g<2>
    backrefs: true
  tags:
    - CCE-83167-7
    - DISA-STIG-SLES-12-010160
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_lcredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check the presence of "lcredit" argument in "pam_cracklib.so" module
  shell: |
    set -o pipefail
    grep -E '^\s*password\s+requisite\s+pam_cracklib.so.*\s+lcredit(=|\s|\s*$)' /etc/pam.d/common-password || true
  register: check_pam_module_argument_result
  tags:
    - CCE-83167-7
    - DISA-STIG-SLES-12-010160
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_lcredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Add "lcredit" argument to "pam_cracklib.so" module
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+requisite\s+pam_cracklib.so)((\s+\S+)*\s*(\\)*$)
    line: \g<1> lcredit={{ var_password_pam_lcredit }}\g<2>
    backrefs: true
  when: '"lcredit" not in check_pam_module_argument_result.stdout'
  tags:
    - CCE-83167-7
    - DISA-STIG-SLES-12-010160
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_lcredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Set Password Strength Minimum Uppercase Charactersrule

The pam_cracklib module's ucredit= parameter controls requirements for usage of uppercase letters in a password. When set to a negative number, any password will be required to contain that many uppercase characters. When set to a positive number, pam_cracklib will grant +1 additional length credit for each uppercase character. Add ucredit=-1 after pam_cracklib.so to require use of an upper case character in passwords.

Rationale:

Requiring a minimum number of uppercase characters makes password guessing attacks more difficult by ensuring a larger search space.

Remediation script:
- name: XCCDF Value var_password_pam_ucredit # promote to variable
  set_fact:
    var_password_pam_ucredit: !!str 1
  tags:
    - always

- name: Set control_flag fact
  set_fact:
    control_flag: requisite
  tags:
    - CCE-83166-9
    - DISA-STIG-SLES-12-010150
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_ucredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check to see if 'pam_cracklib.so' module is configured in '/etc/pam.d/common-password'
  shell: |
    set -o pipefail
    grep -E '^\s*password\s+\S+\s+pam_cracklib.so' /etc/pam.d/common-password || true
  register: check_pam_module_result
  tags:
    - CCE-83166-9
    - DISA-STIG-SLES-12-010150
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_ucredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Configure 'pam_cracklib.so' module in '/etc/pam.d/common-password'
  lineinfile:
    path: /etc/pam.d/common-password
    line: password requisite pam_cracklib.so
    state: present
  when: '"pam_cracklib.so" not in check_pam_module_result.stdout'
  tags:
    - CCE-83166-9
    - DISA-STIG-SLES-12-010150
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_ucredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure 'pam_cracklib.so' module has conforming control flag
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+)\S+(\s+pam_cracklib.so\s+.*)
    line: \g<1>requisite\g<2>
    backrefs: true
  when: control_flag|length
  tags:
    - CCE-83166-9
    - DISA-STIG-SLES-12-010150
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_ucredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure "pam_cracklib.so" module has argument "ucredit={{ var_password_pam_ucredit
    }}"
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+requisite\s+pam_cracklib.so(?:\s+\S+)*\s+ucredit=)(?:\S+)((\s+\S+)*\s*\\*\s*)$
    line: \g<1>{{ var_password_pam_ucredit }}\g<2>
    backrefs: true
  tags:
    - CCE-83166-9
    - DISA-STIG-SLES-12-010150
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_ucredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check the presence of "ucredit" argument in "pam_cracklib.so" module
  shell: |
    set -o pipefail
    grep -E '^\s*password\s+requisite\s+pam_cracklib.so.*\s+ucredit(=|\s|\s*$)' /etc/pam.d/common-password || true
  register: check_pam_module_argument_result
  tags:
    - CCE-83166-9
    - DISA-STIG-SLES-12-010150
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_ucredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Add "ucredit" argument to "pam_cracklib.so" module
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+requisite\s+pam_cracklib.so)((\s+\S+)*\s*(\\)*$)
    line: \g<1> ucredit={{ var_password_pam_ucredit }}\g<2>
    backrefs: true
  when: '"ucredit" not in check_pam_module_argument_result.stdout'
  tags:
    - CCE-83166-9
    - DISA-STIG-SLES-12-010150
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_ucredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Set Password Strength Minimum Special Charactersrule

The pam_cracklib module's ocredit= parameter controls requirements for usage of special (or ``other'') characters in a password. When set to a negative number, any password will be required to contain that many special characters. When set to a positive number, pam_cracklib will grant +1 additional length credit for each special character. Make sure the ocredit parameter for the pam_cracklib module is set to less than or equal to 1. For example, ocredit=1.

Rationale:

Requiring a minimum number of special characters makes password guessing attacks more difficult by ensuring a larger search space.

Remediation script:
- name: XCCDF Value var_password_pam_ocredit # promote to variable
  set_fact:
    var_password_pam_ocredit: !!str 1
  tags:
    - always

- name: Set control_flag fact
  set_fact:
    control_flag: requisite
  tags:
    - CCE-83169-3
    - DISA-STIG-SLES-12-010180
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_ocredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check to see if 'pam_cracklib.so' module is configured in '/etc/pam.d/common-password'
  shell: |
    set -o pipefail
    grep -E '^\s*password\s+\S+\s+pam_cracklib.so' /etc/pam.d/common-password || true
  register: check_pam_module_result
  tags:
    - CCE-83169-3
    - DISA-STIG-SLES-12-010180
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_ocredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Configure 'pam_cracklib.so' module in '/etc/pam.d/common-password'
  lineinfile:
    path: /etc/pam.d/common-password
    line: password requisite pam_cracklib.so
    state: present
  when: '"pam_cracklib.so" not in check_pam_module_result.stdout'
  tags:
    - CCE-83169-3
    - DISA-STIG-SLES-12-010180
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_ocredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure 'pam_cracklib.so' module has conforming control flag
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+)\S+(\s+pam_cracklib.so\s+.*)
    line: \g<1>requisite\g<2>
    backrefs: true
  when: control_flag|length
  tags:
    - CCE-83169-3
    - DISA-STIG-SLES-12-010180
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_ocredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure "pam_cracklib.so" module has argument "ocredit={{ var_password_pam_ocredit
    }}"
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+requisite\s+pam_cracklib.so(?:\s+\S+)*\s+ocredit=)(?:\S+)((\s+\S+)*\s*\\*\s*)$
    line: \g<1>{{ var_password_pam_ocredit }}\g<2>
    backrefs: true
  tags:
    - CCE-83169-3
    - DISA-STIG-SLES-12-010180
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_ocredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check the presence of "ocredit" argument in "pam_cracklib.so" module
  shell: |
    set -o pipefail
    grep -E '^\s*password\s+requisite\s+pam_cracklib.so.*\s+ocredit(=|\s|\s*$)' /etc/pam.d/common-password || true
  register: check_pam_module_argument_result
  tags:
    - CCE-83169-3
    - DISA-STIG-SLES-12-010180
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_ocredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Add "ocredit" argument to "pam_cracklib.so" module
  lineinfile:
    path: /etc/pam.d/common-password
    regexp: ^(\s*password\s+requisite\s+pam_cracklib.so)((\s+\S+)*\s*(\\)*$)
    line: \g<1> ocredit={{ var_password_pam_ocredit }}\g<2>
    backrefs: true
  when: '"ocredit" not in check_pam_module_argument_result.stdout'
  tags:
    - CCE-83169-3
    - DISA-STIG-SLES-12-010180
    - NIST-800-53-IA-5(a)
    - NIST-800-53-IA-5(v)
    - cracklib_accounts_password_pam_ocredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

The PAM configuration should not be changed automaticallyrule

Verify the SUSE operating system is configured to not overwrite Pluggable Authentication Modules (PAM) configuration on package changes.

Rationale:

pam-config is a command line utility that automatically generates a system PAM configuration as packages are installed, updated or removed from the system. pam-config removes configurations for PAM modules and parameters that it does not know about. It may render ineffective PAM configuration by the system administrator and thus impact system security.

Remediation script:

for link in $(find /etc/pam.d/ -type l -iname "common-*") ; do
    target=$(readlink -f "$link")
    cp -p --remove-destination "$target" "$link"
done
Remediation script:
- name: Find soft links /etc/pam.d/
  find:
    paths: /etc/pam.d
    file_type: link
    patterns: common-.*
    use_regex: true
  register: find_pam_soft_links_result
  tags:
    - CCE-83113-1
    - DISA-STIG-SLES-12-010910
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1(iv)
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - pam_disable_automatic_configuration
    - restrict_strategy

- name: Remove soft links in /etc/pam.d/
  shell: |
    set -o pipefail
    target=$(readlink -f "{{ item.path }}")
    cp -p --remove-destination "$target" "{{ item.path }}"
  with_items: '{{ find_pam_soft_links_result.files }}'
  tags:
    - CCE-83113-1
    - DISA-STIG-SLES-12-010910
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1(iv)
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - pam_disable_automatic_configuration
    - restrict_strategy

System Accounting with auditdgroup

The audit service provides substantial capabilities for recording system activities. By default, the service audits about SELinux AVC denials and certain types of security-relevant events such as system logins, account modifications, and authentication events performed by programs such as sudo. Under its default configuration, auditd has modest disk space requirements, and should not noticeably impact system performance.

NOTE: The Linux Audit daemon auditd can be configured to use the augenrules program to read audit rules files (*.rules) located in /etc/audit/rules.d location and compile them to create the resulting form of the /etc/audit/audit.rules configuration file during the daemon startup (default configuration). Alternatively, the auditd daemon can use the auditctl utility to read audit rules from the /etc/audit/audit.rules configuration file during daemon startup, and load them into the kernel. The expected behavior is configured via the appropriate ExecStartPost directive setting in the /usr/lib/systemd/system/auditd.service configuration file. To instruct the auditd daemon to use the augenrules program to read audit rules (default configuration), use the following setting:

ExecStartPost=-/sbin/augenrules --load
in the /usr/lib/systemd/system/auditd.service configuration file. In order to instruct the auditd daemon to use the auditctl utility to read audit rules, use the following setting:
ExecStartPost=-/sbin/auditctl -R /etc/audit/audit.rules
in the /usr/lib/systemd/system/auditd.service configuration file. Refer to [Service] section of the /usr/lib/systemd/system/auditd.service configuration file for further details.

Government networks often have substantial auditing requirements and auditd can be configured to meet these requirements. Examining some example audit records demonstrates how the Linux audit system satisfies common requirements. The following example from Fedora Documentation available at https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/SELinux_Users_and_Administrators_Guide/sect-Security-Enhanced_Linux-Troubleshooting-Fixing_Problems.html#sect-Security-Enhanced_Linux-Fixing_Problems-Raw_Audit_Messages shows the substantial amount of information captured in a two typical "raw" audit messages, followed by a breakdown of the most important fields. In this example the message is SELinux-related and reports an AVC denial (and the associated system call) that occurred when the Apache HTTP Server attempted to access the /var/www/html/file1 file (labeled with the samba_share_t type):
type=AVC msg=audit(1226874073.147:96): avc:  denied  { getattr } for pid=2465 comm="httpd"
path="/var/www/html/file1" dev=dm-0 ino=284133 scontext=unconfined_u:system_r:httpd_t:s0
tcontext=unconfined_u:object_r:samba_share_t:s0 tclass=file

type=SYSCALL msg=audit(1226874073.147:96): arch=40000003 syscall=196 success=no exit=-13
a0=b98df198 a1=bfec85dc a2=54dff4 a3=2008171 items=0 ppid=2463 pid=2465 auid=502 uid=48
gid=48 euid=48 suid=48 fsuid=48 egid=48 sgid=48 fsgid=48 tty=(none) ses=6 comm="httpd"
exe="/usr/sbin/httpd" subj=unconfined_u:system_r:httpd_t:s0 key=(null)
  • msg=audit(1226874073.147:96)
    • The number in parentheses is the unformatted time stamp (Epoch time) for the event, which can be converted to standard time by using the date command.
  • { getattr }
    • The item in braces indicates the permission that was denied. getattr indicates the source process was trying to read the target file's status information. This occurs before reading files. This action is denied due to the file being accessed having the wrong label. Commonly seen permissions include getattr, read, and write.
  • comm="httpd"
    • The executable that launched the process. The full path of the executable is found in the exe= section of the system call (SYSCALL) message, which in this case, is exe="/usr/sbin/httpd".
  • path="/var/www/html/file1"
    • The path to the object (target) the process attempted to access.
  • scontext="unconfined_u:system_r:httpd_t:s0"
    • The SELinux context of the process that attempted the denied action. In this case, it is the SELinux context of the Apache HTTP Server, which is running in the httpd_t domain.
  • tcontext="unconfined_u:object_r:samba_share_t:s0"
    • The SELinux context of the object (target) the process attempted to access. In this case, it is the SELinux context of file1. Note: the samba_share_t type is not accessible to processes running in the httpd_t domain.
  • From the system call (SYSCALL) message, two items are of interest:
    • success=no: indicates whether the denial (AVC) was enforced or not. success=no indicates the system call was not successful (SELinux denied access). success=yes indicates the system call was successful - this can be seen for permissive domains or unconfined domains, such as initrc_t and kernel_t.
    • exe="/usr/sbin/httpd": the full path to the executable that launched the process, which in this case, is exe="/usr/sbin/httpd".

contains 67 rules

Configure auditd Rules for Comprehensive Auditinggroup

The auditd program can perform comprehensive monitoring of system activity. This section describes recommended configuration settings for comprehensive auditing, but a full description of the auditing system's capabilities is beyond the scope of this guide. The mailing list linux-audit@redhat.com exists to facilitate community discussion of the auditing system.

The audit subsystem supports extensive collection of events, including:

  • Tracing of arbitrary system calls (identified by name or number) on entry or exit.
  • Filtering by PID, UID, call success, system call argument (with some limitations), etc.
  • Monitoring of specific files for modifications to the file's contents or metadata.

Auditing rules at startup are controlled by the file /etc/audit/audit.rules. Add rules to it to meet the auditing requirements for your organization. Each line in /etc/audit/audit.rules represents a series of arguments that can be passed to auditctl and can be individually tested during runtime. See documentation in /usr/share/doc/audit-VERSION and in the related man pages for more details.

If copying any example audit rulesets from /usr/share/doc/audit-VERSION, be sure to comment out the lines containing arch= which are not appropriate for your system's architecture. Then review and understand the following rules, ensuring rules are activated as needed for the appropriate architecture.

After reviewing all the rules, reading the following sections, and editing as needed, the new rules can be activated as follows:
$ sudo service auditd restart

contains 57 rules

Record Events that Modify the System's Discretionary Access Controlsgroup

At a minimum, the audit system should collect file permission changes for all users and root. Note that the "-F arch=b32" lines should be present even on a 64 bit system. These commands identify system calls for auditing. Even if the system is 64 bit it can still execute 32 bit system calls. Additionally, these rules can be configured in a number of ways while still achieving the desired effect. An example of this is that the "-S" calls could be split up and placed on separate lines, however, this is less efficient. Add the following to /etc/audit/audit.rules:

-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod
    -a always,exit -F arch=b32 -S chown,fchown,fchownat,lchown -F auid>=1000 -F auid!=unset -F key=perm_mod
    -a always,exit -F arch=b32 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod
If your system is 64 bit then these lines should be duplicated and the arch=b32 replaced with arch=b64 as follows:
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod
    -a always,exit -F arch=b64 -S chown,fchown,fchownat,lchown -F auid>=1000 -F auid!=unset -F key=perm_mod
    -a always,exit -F arch=b64 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod

contains 14 rules

Record Events that Modify the System's Discretionary Access Controls - fremovexattrrule

At a minimum, the audit system should collect file permission changes for all users and root.

If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod


If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod


If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod


If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S fremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and unauthorized users.

Remediation script:
- name: Set architecture for audit fremovexattr tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83138-8
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020410
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fremovexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_fremovexattr
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83138-8
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020410
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fremovexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_fremovexattr.matched is defined and find_fremovexattr.matched == 0
  tags:
    - CCE-83138-8
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020410
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fremovexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_fremovexattr.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_fremovexattr.matched is defined and find_fremovexattr.matched > 0
  tags:
    - CCE-83138-8
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020410
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fremovexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fremovexattr rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b32 -S fremovexattr -F auid>=1000 -F auid!=unset
      -F key=perm_mod
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83138-8
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020410
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fremovexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fremovexattr rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b64 -S fremovexattr -F auid>=1000 -F auid!=unset
      -F key=perm_mod
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83138-8
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020410
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fremovexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fremovexattr rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: -a always,exit -F arch=b32 -S fremovexattr -F auid>=1000 -F auid!=unset
      -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83138-8
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020410
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fremovexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fremovexattr rule in audit.rules when on x86_64
  lineinfile:
    line: -a always,exit -F arch=b64 -S fremovexattr -F auid>=1000 -F auid!=unset
      -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83138-8
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020410
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fremovexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Events that Modify the System's Discretionary Access Controls - fchownrule

At a minimum, the audit system should collect file permission changes for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S fchown -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S fchown -F auid>=1000 -F auid!=unset -F key=perm_mod
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S fchown -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S fchown -F auid>=1000 -F auid!=unset -F key=perm_mod

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and unauthorized users.

Remediation script:
- name: Set architecture for audit fchown tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83136-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020430
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_fchown
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83136-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020430
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_fchown.matched is defined and find_fchown.matched == 0
  tags:
    - CCE-83136-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020430
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_fchown.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_fchown.matched is defined and find_fchown.matched > 0
  tags:
    - CCE-83136-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020430
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fchown rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b32 -S fchown -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83136-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020430
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fchown rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b64 -S fchown -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83136-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020430
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fchown rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: -a always,exit -F arch=b32 -S fchown -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83136-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020430
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fchown rule in audit.rules when on x86_64
  lineinfile:
    line: -a always,exit -F arch=b64 -S fchown -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83136-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020430
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Events that Modify the System's Discretionary Access Controls - umount2rule

At a minimum, the audit system should collect file system umount2 changes. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S umount2 -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S umount2 -F auid>=1000 -F auid!=unset -F key=perm_mod
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S umount2 -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S umount2 -F auid>=1000 -F auid!=unset -F key=perm_mod

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and unauthorized users.

Remediation script:
- name: Set architecture for audit umount2 tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83219-6
    - DISA-STIG-SLES-12-020300
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_dac_modification_umount2
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_umount2
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83219-6
    - DISA-STIG-SLES-12-020300
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_dac_modification_umount2
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_umount2.matched is defined and find_umount2.matched == 0
  tags:
    - CCE-83219-6
    - DISA-STIG-SLES-12-020300
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_dac_modification_umount2
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_umount2.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_umount2.matched is defined and find_umount2.matched > 0
  tags:
    - CCE-83219-6
    - DISA-STIG-SLES-12-020300
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_dac_modification_umount2
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the umount2 rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b32 -S umount2 -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83219-6
    - DISA-STIG-SLES-12-020300
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_dac_modification_umount2
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the umount2 rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b64 -S umount2 -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83219-6
    - DISA-STIG-SLES-12-020300
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_dac_modification_umount2
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the umount2 rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: -a always,exit -F arch=b32 -S umount2 -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83219-6
    - DISA-STIG-SLES-12-020300
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_dac_modification_umount2
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the umount2 rule in audit.rules when on x86_64
  lineinfile:
    line: -a always,exit -F arch=b64 -S umount2 -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83219-6
    - DISA-STIG-SLES-12-020300
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_dac_modification_umount2
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Events that Modify the System's Discretionary Access Controls - setxattrrule

At a minimum, the audit system should collect file permission changes for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S setxattr -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S setxattr -F auid>=1000 -F auid!=unset -F key=perm_mod
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S setxattr -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S setxattr -F auid>=1000 -F auid!=unset -F key=perm_mod

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and unauthorized users.

Remediation script:
- name: Set architecture for audit setxattr tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83142-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020370
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_setxattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_setxattr
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83142-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020370
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_setxattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_setxattr.matched is defined and find_setxattr.matched == 0
  tags:
    - CCE-83142-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020370
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_setxattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_setxattr.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_setxattr.matched is defined and find_setxattr.matched > 0
  tags:
    - CCE-83142-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020370
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_setxattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the setxattr rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b32 -S setxattr -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83142-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020370
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_setxattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the setxattr rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b64 -S setxattr -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83142-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020370
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_setxattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the setxattr rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: -a always,exit -F arch=b32 -S setxattr -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83142-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020370
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_setxattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the setxattr rule in audit.rules when on x86_64
  lineinfile:
    line: -a always,exit -F arch=b64 -S setxattr -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83142-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020370
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_setxattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Events that Modify the System's Discretionary Access Controls - lremovexattrrule

At a minimum, the audit system should collect file permission changes for all users and root.

If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S lremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod


If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S lremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod


If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S lremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod


If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S lremovexattr -F auid>=1000 -F auid!=unset -F key=perm_mod

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and unauthorized users.

Remediation script:
- name: Set architecture for audit lremovexattr tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83139-6
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020400
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_lremovexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_lremovexattr
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83139-6
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020400
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_lremovexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_lremovexattr.matched is defined and find_lremovexattr.matched == 0
  tags:
    - CCE-83139-6
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020400
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_lremovexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_lremovexattr.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_lremovexattr.matched is defined and find_lremovexattr.matched > 0
  tags:
    - CCE-83139-6
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020400
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_lremovexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the lremovexattr rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b32 -S lremovexattr -F auid>=1000 -F auid!=unset
      -F key=perm_mod
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83139-6
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020400
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_lremovexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the lremovexattr rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b64 -S lremovexattr -F auid>=1000 -F auid!=unset
      -F key=perm_mod
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83139-6
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020400
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_lremovexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the lremovexattr rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: -a always,exit -F arch=b32 -S lremovexattr -F auid>=1000 -F auid!=unset
      -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83139-6
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020400
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_lremovexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the lremovexattr rule in audit.rules when on x86_64
  lineinfile:
    line: -a always,exit -F arch=b64 -S lremovexattr -F auid>=1000 -F auid!=unset
      -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83139-6
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020400
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_lremovexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Events that Modify the System's Discretionary Access Controls - chownrule

At a minimum, the audit system should collect file permission changes for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S chown -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S chown -F auid>=1000 -F auid!=unset -F key=perm_mod
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S chown -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S chown -F auid>=1000 -F auid!=unset -F key=perm_mod

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and unauthorized users.

Remediation script:
- name: Set architecture for audit chown tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83137-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020420
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_chown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_chown
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83137-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020420
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_chown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_chown.matched is defined and find_chown.matched == 0
  tags:
    - CCE-83137-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020420
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_chown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_chown.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_chown.matched is defined and find_chown.matched > 0
  tags:
    - CCE-83137-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020420
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_chown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the chown rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b32 -S chown -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83137-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020420
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_chown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the chown rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b64 -S chown -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83137-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020420
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_chown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the chown rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: -a always,exit -F arch=b32 -S chown -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83137-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020420
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_chown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the chown rule in audit.rules when on x86_64
  lineinfile:
    line: -a always,exit -F arch=b64 -S chown -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83137-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020420
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_chown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Events that Modify the System's Discretionary Access Controls - chmodrule

At a minimum, the audit system should collect file permission changes for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S chmod -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S chmod -F auid>=1000 -F auid!=unset -F key=perm_mod
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S chmod -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S chmod -F auid>=1000 -F auid!=unset -F key=perm_mod

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and unauthorized users.

Remediation script:
- name: Set architecture for audit chmod tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83106-5
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020460
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_chmod
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_chmod
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83106-5
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020460
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_chmod
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_chmod.matched is defined and find_chmod.matched == 0
  tags:
    - CCE-83106-5
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020460
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_chmod
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_chmod.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_chmod.matched is defined and find_chmod.matched > 0
  tags:
    - CCE-83106-5
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020460
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_chmod
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the chmod rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b32 -S chmod -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83106-5
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020460
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_chmod
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the chmod rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b64 -S chmod -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83106-5
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020460
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_chmod
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the chmod rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: -a always,exit -F arch=b32 -S chmod -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83106-5
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020460
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_chmod
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the chmod rule in audit.rules when on x86_64
  lineinfile:
    line: -a always,exit -F arch=b64 -S chmod -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83106-5
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020460
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_chmod
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Events that Modify the System's Discretionary Access Controls - umountrule

At a minimum, the audit system should collect file system umount changes. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S umount -F auid>=1000 -F auid!=unset -F key=perm_mod
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S umount -F auid>=1000 -F auid!=unset -F key=perm_mod

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and unauthorized users.

Remediation script:
- name: Set architecture for audit umount tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83218-8
    - DISA-STIG-SLES-12-020300
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_dac_modification_umount
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_umount
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83218-8
    - DISA-STIG-SLES-12-020300
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_dac_modification_umount
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_umount.matched is defined and find_umount.matched == 0
  tags:
    - CCE-83218-8
    - DISA-STIG-SLES-12-020300
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_dac_modification_umount
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_umount.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_umount.matched is defined and find_umount.matched > 0
  tags:
    - CCE-83218-8
    - DISA-STIG-SLES-12-020300
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_dac_modification_umount
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the umount rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b32 -S umount -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83218-8
    - DISA-STIG-SLES-12-020300
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_dac_modification_umount
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the umount rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b64 -S umount -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83218-8
    - DISA-STIG-SLES-12-020300
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_dac_modification_umount
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the umount rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: -a always,exit -F arch=b32 -S umount -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83218-8
    - DISA-STIG-SLES-12-020300
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_dac_modification_umount
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the umount rule in audit.rules when on x86_64
  lineinfile:
    line: -a always,exit -F arch=b64 -S umount -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83218-8
    - DISA-STIG-SLES-12-020300
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_dac_modification_umount
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Events that Modify the System's Discretionary Access Controls - fchmodatrule

At a minimum, the audit system should collect file permission changes for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and unauthorized users.

Remediation script:
- name: Set architecture for audit fchmodat tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83132-1
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020480
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchmodat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_fchmodat
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83132-1
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020480
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchmodat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_fchmodat.matched is defined and find_fchmodat.matched == 0
  tags:
    - CCE-83132-1
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020480
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchmodat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_fchmodat.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_fchmodat.matched is defined and find_fchmodat.matched > 0
  tags:
    - CCE-83132-1
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020480
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchmodat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fchmodat rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b32 -S fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83132-1
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020480
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchmodat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fchmodat rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b64 -S fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83132-1
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020480
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchmodat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fchmodat rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: -a always,exit -F arch=b32 -S fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83132-1
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020480
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchmodat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fchmodat rule in audit.rules when on x86_64
  lineinfile:
    line: -a always,exit -F arch=b64 -S fchmodat -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83132-1
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020480
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchmodat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Events that Modify the System's Discretionary Access Controls - fchownatrule

At a minimum, the audit system should collect file permission changes for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S fchownat -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S fchownat -F auid>=1000 -F auid!=unset -F key=perm_mod
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S fchownat -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S fchownat -F auid>=1000 -F auid!=unset -F key=perm_mod

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and unauthorized users.

Remediation script:
- name: Set architecture for audit fchownat tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83134-7
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020450
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchownat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_fchownat
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83134-7
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020450
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchownat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_fchownat.matched is defined and find_fchownat.matched == 0
  tags:
    - CCE-83134-7
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020450
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchownat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_fchownat.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_fchownat.matched is defined and find_fchownat.matched > 0
  tags:
    - CCE-83134-7
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020450
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchownat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fchownat rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b32 -S fchownat -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83134-7
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020450
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchownat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fchownat rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b64 -S fchownat -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83134-7
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020450
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchownat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fchownat rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: -a always,exit -F arch=b32 -S fchownat -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83134-7
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020450
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchownat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fchownat rule in audit.rules when on x86_64
  lineinfile:
    line: -a always,exit -F arch=b64 -S fchownat -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83134-7
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020450
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchownat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Events that Modify the System's Discretionary Access Controls - fchmodrule

At a minimum, the audit system should collect file permission changes for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S fchmod -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S fchmod -F auid>=1000 -F auid!=unset -F key=perm_mod
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S fchmod -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S fchmod -F auid>=1000 -F auid!=unset -F key=perm_mod

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and unauthorized users.

Remediation script:
- name: Set architecture for audit fchmod tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83133-9
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020470
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchmod
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_fchmod
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83133-9
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020470
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchmod
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_fchmod.matched is defined and find_fchmod.matched == 0
  tags:
    - CCE-83133-9
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020470
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchmod
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_fchmod.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_fchmod.matched is defined and find_fchmod.matched > 0
  tags:
    - CCE-83133-9
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020470
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchmod
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fchmod rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b32 -S fchmod -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83133-9
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020470
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchmod
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fchmod rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b64 -S fchmod -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83133-9
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020470
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchmod
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fchmod rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: -a always,exit -F arch=b32 -S fchmod -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83133-9
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020470
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchmod
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fchmod rule in audit.rules when on x86_64
  lineinfile:
    line: -a always,exit -F arch=b64 -S fchmod -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83133-9
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020470
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fchmod
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Events that Modify the System's Discretionary Access Controls - fsetxattrrule

At a minimum, the audit system should collect file permission changes for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S fsetxattr -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S fsetxattr -F auid>=1000 -F auid!=unset -F key=perm_mod
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S fsetxattr -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S fsetxattr -F auid>=1000 -F auid!=unset -F key=perm_mod

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and unauthorized users.

Remediation script:
- name: Set architecture for audit fsetxattr tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83141-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020380
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fsetxattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_fsetxattr
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83141-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020380
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fsetxattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_fsetxattr.matched is defined and find_fsetxattr.matched == 0
  tags:
    - CCE-83141-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020380
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fsetxattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_fsetxattr.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_fsetxattr.matched is defined and find_fsetxattr.matched > 0
  tags:
    - CCE-83141-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020380
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fsetxattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fsetxattr rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b32 -S fsetxattr -F auid>=1000 -F auid!=unset -F
      key=perm_mod
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83141-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020380
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fsetxattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fsetxattr rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b64 -S fsetxattr -F auid>=1000 -F auid!=unset -F
      key=perm_mod
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83141-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020380
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fsetxattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fsetxattr rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: -a always,exit -F arch=b32 -S fsetxattr -F auid>=1000 -F auid!=unset -F
      key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83141-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020380
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fsetxattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the fsetxattr rule in audit.rules when on x86_64
  lineinfile:
    line: -a always,exit -F arch=b64 -S fsetxattr -F auid>=1000 -F auid!=unset -F
      key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83141-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020380
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_fsetxattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Events that Modify the System's Discretionary Access Controls - lchownrule

At a minimum, the audit system should collect file permission changes for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S lchown -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S lchown -F auid>=1000 -F auid!=unset -F key=perm_mod
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S lchown -F auid>=1000 -F auid!=unset -F key=perm_mod
If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S lchown -F auid>=1000 -F auid!=unset -F key=perm_mod

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and unauthorized users.

Remediation script:
- name: Set architecture for audit lchown tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83135-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020440
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_lchown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_lchown
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83135-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020440
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_lchown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_lchown.matched is defined and find_lchown.matched == 0
  tags:
    - CCE-83135-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020440
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_lchown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_lchown.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_lchown.matched is defined and find_lchown.matched > 0
  tags:
    - CCE-83135-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020440
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_lchown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the lchown rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b32 -S lchown -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83135-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020440
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_lchown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the lchown rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b64 -S lchown -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83135-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020440
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_lchown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the lchown rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: -a always,exit -F arch=b32 -S lchown -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83135-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020440
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_lchown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the lchown rule in audit.rules when on x86_64
  lineinfile:
    line: -a always,exit -F arch=b64 -S lchown -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83135-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020440
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_lchown
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Events that Modify the System's Discretionary Access Controls - removexattrrule

At a minimum, the audit system should collect file permission changes for all users and root.

If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S removexattr -F auid>=1000 -F auid!=unset -F key=perm_mod


If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S removexattr -F auid>=1000 -F auid!=unset -F key=perm_mod


If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S removexattr -F auid>=1000 -F auid!=unset -F key=perm_mod


If the system is 64 bit then also add the following line:
-a always,exit -F arch=b64 -S removexattr -F auid>=1000 -F auid!=unset -F key=perm_mod

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

The changing of file permissions could indicate that a user is attempting to gain access to information that would otherwise be disallowed. Auditing DAC modifications can facilitate the identification of patterns of abuse among both authorized and unauthorized users.

Remediation script:
- name: Set architecture for audit removexattr tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83140-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020390
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_removexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_removexattr
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83140-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020390
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_removexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_removexattr.matched is defined and find_removexattr.matched == 0
  tags:
    - CCE-83140-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020390
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_removexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_removexattr.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_removexattr.matched is defined and find_removexattr.matched > 0
  tags:
    - CCE-83140-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020390
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_removexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the removexattr rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b32 -S removexattr -F auid>=1000 -F auid!=unset -F
      key=perm_mod
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83140-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020390
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_removexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the removexattr rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b64 -S removexattr -F auid>=1000 -F auid!=unset -F
      key=perm_mod
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83140-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020390
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_removexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the removexattr rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: -a always,exit -F arch=b32 -S removexattr -F auid>=1000 -F auid!=unset -F
      key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83140-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020390
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_removexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the removexattr rule in audit.rules when on x86_64
  lineinfile:
    line: -a always,exit -F arch=b64 -S removexattr -F auid>=1000 -F auid!=unset -F
      key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83140-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020390
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.5.5
    - audit_rules_dac_modification_removexattr
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy
contains 3 rules

Record Execution Attempts to Run ACL Privileged Commandsgroup

At a minimum, the audit system should collect the execution of ACL privileged commands for all users and root.

contains 3 rules

Record Any Attempts to Run chmodrule

At a minimum, the audit system should collect any execution attempt of the chmod command for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/bin/chmod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file:
-a always,exit -F path=/usr/bin/chmod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Without generating audit records that are specific to the security and mission needs of the organization, it would be difficult to establish, correlate, and investigate the events relating to an incident or identify those responsible for one. Audit records can be generated from various components within the information system (e.g., module or policy filter).

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/bin/chmod.*$
    patterns: '*.rules'
  register: find_chmod
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83214-7
    - DISA-STIG-SLES-12-020600
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_chmod
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_chmod.matched is defined and find_chmod.matched == 0
  tags:
    - CCE-83214-7
    - DISA-STIG-SLES-12-020600
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_chmod
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_chmod.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_chmod.matched is defined and find_chmod.matched > 0
  tags:
    - CCE-83214-7
    - DISA-STIG-SLES-12-020600
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_chmod
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the chmod rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/bin/chmod -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83214-7
    - DISA-STIG-SLES-12-020600
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_chmod
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the chmod rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/bin/chmod -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83214-7
    - DISA-STIG-SLES-12-020600
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_chmod
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Record Any Attempts to Run setfaclrule

At a minimum, the audit system should collect any execution attempt of the setfacl command for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file:
-a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Without generating audit records that are specific to the security and mission needs of the organization, it would be difficult to establish, correlate, and investigate the events relating to an incident or identify those responsible for one. Audit records can be generated from various components within the information system (e.g., module or policy filter).

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/bin/setfacl.*$
    patterns: '*.rules'
  register: find_setfacl
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83189-1
    - DISA-STIG-SLES-12-020610
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_setfacl
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_setfacl.matched is defined and find_setfacl.matched == 0
  tags:
    - CCE-83189-1
    - DISA-STIG-SLES-12-020610
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_setfacl
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_setfacl.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_setfacl.matched is defined and find_setfacl.matched > 0
  tags:
    - CCE-83189-1
    - DISA-STIG-SLES-12-020610
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_setfacl
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the setfacl rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83189-1
    - DISA-STIG-SLES-12-020610
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_setfacl
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the setfacl rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83189-1
    - DISA-STIG-SLES-12-020610
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_setfacl
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Record Any Attempts to Run chaclrule

At a minimum, the audit system should collect any execution attempt of the chacl command for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file:
-a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Without generating audit records that are specific to the security and mission needs of the organization, it would be difficult to establish, correlate, and investigate the events relating to an incident or identify those responsible for one. Audit records can be generated from various components within the information system (e.g., module or policy filter).

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/bin/chacl.*$
    patterns: '*.rules'
  register: find_chacl
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83190-9
    - DISA-STIG-SLES-12-020620
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_chacl
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_chacl.matched is defined and find_chacl.matched == 0
  tags:
    - CCE-83190-9
    - DISA-STIG-SLES-12-020620
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_chacl
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_chacl.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_chacl.matched is defined and find_chacl.matched > 0
  tags:
    - CCE-83190-9
    - DISA-STIG-SLES-12-020620
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_chacl
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the chacl rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83190-9
    - DISA-STIG-SLES-12-020620
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_chacl
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the chacl rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83190-9
    - DISA-STIG-SLES-12-020620
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_chacl
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Record Information on the Use of Privileged Commandsgroup

At a minimum, the audit system should collect the execution of privileged commands for all users and root.

contains 18 rules

Ensure auditd Collects Information on the Use of Privileged Commands - chagerule

At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/bin/chage -F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules:
-a always,exit -F path=/usr/bin/chage -F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats.

Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for unusual activity.

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/bin/chage.*$
    patterns: '*.rules'
  register: find_chage
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83110-7
    - DISA-STIG-SLES-12-020690
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_chage
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_chage.matched is defined and find_chage.matched == 0
  tags:
    - CCE-83110-7
    - DISA-STIG-SLES-12-020690
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_chage
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_chage.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_chage.matched is defined and find_chage.matched > 0
  tags:
    - CCE-83110-7
    - DISA-STIG-SLES-12-020690
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_chage
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the chage rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83110-7
    - DISA-STIG-SLES-12-020690
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_chage
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the chage rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83110-7
    - DISA-STIG-SLES-12-020690
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_chage
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Ensure auditd Collects Information on the Use of Privileged Commands - crontabrule

At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/bin/crontab -F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules:
-a always,exit -F path=/usr/bin/crontab -F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats.

Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for unusual activity.

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/bin/crontab.*$
    patterns: '*.rules'
  register: find_crontab
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83126-3
    - DISA-STIG-SLES-12-020710
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_crontab
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_crontab.matched is defined and find_crontab.matched == 0
  tags:
    - CCE-83126-3
    - DISA-STIG-SLES-12-020710
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_crontab
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_crontab.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_crontab.matched is defined and find_crontab.matched > 0
  tags:
    - CCE-83126-3
    - DISA-STIG-SLES-12-020710
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_crontab
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the crontab rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83126-3
    - DISA-STIG-SLES-12-020710
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_crontab
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the crontab rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83126-3
    - DISA-STIG-SLES-12-020710
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_crontab
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Ensure auditd Collects Information on the Use of Privileged Commands - chshrule

At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/bin/chsh -F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules:
-a always,exit -F path=/usr/bin/chsh -F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats.

Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for unusual activity.

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/bin/chsh.*$
    patterns: '*.rules'
  register: find_chsh
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83163-6
    - DISA-STIG-SLES-12-020580
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_chsh
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_chsh.matched is defined and find_chsh.matched == 0
  tags:
    - CCE-83163-6
    - DISA-STIG-SLES-12-020580
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_chsh
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_chsh.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_chsh.matched is defined and find_chsh.matched > 0
  tags:
    - CCE-83163-6
    - DISA-STIG-SLES-12-020580
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_chsh
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the chsh rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83163-6
    - DISA-STIG-SLES-12-020580
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_chsh
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the chsh rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83163-6
    - DISA-STIG-SLES-12-020580
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_chsh
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Ensure auditd Collects Information on the Use of Privileged Commands - usermodrule

At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/bin/usermod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules:
-a always,exit -F path=/usr/bin/usermod -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats.

Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for unusual activity.

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/bin/usermod.*$
    patterns: '*.rules'
  register: find_usermod
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83191-7
    - DISA-STIG-SLES-12-020700
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_usermod
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_usermod.matched is defined and find_usermod.matched == 0
  tags:
    - CCE-83191-7
    - DISA-STIG-SLES-12-020700
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_usermod
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_usermod.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_usermod.matched is defined and find_usermod.matched > 0
  tags:
    - CCE-83191-7
    - DISA-STIG-SLES-12-020700
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_usermod
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the usermod rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/bin/usermod -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83191-7
    - DISA-STIG-SLES-12-020700
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_usermod
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the usermod rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/bin/usermod -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83191-7
    - DISA-STIG-SLES-12-020700
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_usermod
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Ensure auditd Collects Information on the Use of Privileged Commands - pam_timestamp_checkrule

At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/sbin/pam_timestamp_check
-F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules:
-a always,exit -F path=/sbin/pam_timestamp_check
-F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats.

Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for unusual activity.

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/sbin/pam_timestamp_check.*$
    patterns: '*.rules'
  register: find_pam_timestamp_check
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83127-1
    - DISA-STIG-SLES-12-020720
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_pam_timestamp_check
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_pam_timestamp_check.matched is defined and find_pam_timestamp_check.matched
      == 0
  tags:
    - CCE-83127-1
    - DISA-STIG-SLES-12-020720
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_pam_timestamp_check
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_pam_timestamp_check.files | map(attribute=''path'') | list | first
        }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_pam_timestamp_check.matched is defined and find_pam_timestamp_check.matched
      > 0
  tags:
    - CCE-83127-1
    - DISA-STIG-SLES-12-020720
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_pam_timestamp_check
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the pam_timestamp_check rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/sbin/pam_timestamp_check -F perm=x -F auid>=1000
      -F auid!=unset -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83127-1
    - DISA-STIG-SLES-12-020720
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_pam_timestamp_check
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the pam_timestamp_check rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/sbin/pam_timestamp_check -F perm=x -F auid>=1000
      -F auid!=unset -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83127-1
    - DISA-STIG-SLES-12-020720
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_pam_timestamp_check
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Ensure auditd Collects Information on the Use of Privileged Commands - newgrprule

At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/bin/newgrp -F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules:
-a always,exit -F path=/usr/bin/newgrp -F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats.

Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for unusual activity.

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/bin/newgrp.*$
    patterns: '*.rules'
  register: find_newgrp
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83162-8
    - DISA-STIG-SLES-12-020570
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_newgrp
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_newgrp.matched is defined and find_newgrp.matched == 0
  tags:
    - CCE-83162-8
    - DISA-STIG-SLES-12-020570
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_newgrp
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_newgrp.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_newgrp.matched is defined and find_newgrp.matched > 0
  tags:
    - CCE-83162-8
    - DISA-STIG-SLES-12-020570
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_newgrp
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the newgrp rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83162-8
    - DISA-STIG-SLES-12-020570
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_newgrp
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the newgrp rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83162-8
    - DISA-STIG-SLES-12-020570
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_newgrp
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Ensure auditd Collects Information on the Use of Privileged Commands - passmassrule

At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/bin/passmass -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules:
-a always,exit -F path=/usr/bin/passmass -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats.

Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for unusual activity.

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/bin/passmass.*$
    patterns: '*.rules'
  register: find_passmass
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83193-3
    - DISA-STIG-SLES-12-020670
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_passmass
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_passmass.matched is defined and find_passmass.matched == 0
  tags:
    - CCE-83193-3
    - DISA-STIG-SLES-12-020670
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_passmass
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_passmass.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_passmass.matched is defined and find_passmass.matched > 0
  tags:
    - CCE-83193-3
    - DISA-STIG-SLES-12-020670
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_passmass
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the passmass rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/bin/passmass -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83193-3
    - DISA-STIG-SLES-12-020670
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_passmass
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the passmass rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/bin/passmass -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83193-3
    - DISA-STIG-SLES-12-020670
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_passmass
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Ensure auditd Collects Information on the Use of Privileged Commands - passwdrule

At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/bin/passwd -F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules:
-a always,exit -F path=/usr/bin/passwd -F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats.

Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for unusual activity.

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/bin/passwd.*$
    patterns: '*.rules'
  register: find_passwd
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83160-2
    - DISA-STIG-SLES-12-020550
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_passwd
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_passwd.matched is defined and find_passwd.matched == 0
  tags:
    - CCE-83160-2
    - DISA-STIG-SLES-12-020550
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_passwd
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_passwd.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_passwd.matched is defined and find_passwd.matched > 0
  tags:
    - CCE-83160-2
    - DISA-STIG-SLES-12-020550
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_passwd
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the passwd rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83160-2
    - DISA-STIG-SLES-12-020550
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_passwd
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the passwd rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83160-2
    - DISA-STIG-SLES-12-020550
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_passwd
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Ensure auditd Collects Information on the Use of Privileged Commands - mountrule

At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/bin/mount -F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules:
-a always,exit -F path=/usr/bin/mount -F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats.

Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for unusual activity.

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/bin/mount.*$
    patterns: '*.rules'
  register: find_mount
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83145-3
    - DISA-STIG-SLES-12-020290
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_mount
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_mount.matched is defined and find_mount.matched == 0
  tags:
    - CCE-83145-3
    - DISA-STIG-SLES-12-020290
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_mount
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_mount.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_mount.matched is defined and find_mount.matched > 0
  tags:
    - CCE-83145-3
    - DISA-STIG-SLES-12-020290
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_mount
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the mount rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83145-3
    - DISA-STIG-SLES-12-020290
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_mount
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the mount rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83145-3
    - DISA-STIG-SLES-12-020290
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_mount
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Ensure auditd Collects Information on the Use of Privileged Commands - ssh-keysignrule

At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/lib/ssh/ssh-keysign
 -F auid>=1000 
-F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules:
-a always,exit -F path=/usr/lib/ssh/ssh-keysign

-F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats.

Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for unusual activity.

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/lib/ssh/ssh-keysign.*$
    patterns: '*.rules'
  register: find_ssh_keysign
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83159-4
    - DISA-STIG-SLES-12-020320
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_ssh_keysign
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_ssh_keysign.matched is defined and find_ssh_keysign.matched == 0
  tags:
    - CCE-83159-4
    - DISA-STIG-SLES-12-020320
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_ssh_keysign
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_ssh_keysign.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_ssh_keysign.matched is defined and find_ssh_keysign.matched > 0
  tags:
    - CCE-83159-4
    - DISA-STIG-SLES-12-020320
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_ssh_keysign
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the ssh_keysign rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/lib/ssh/ssh-keysign -F perm=x -F auid>=1000
      -F auid!=unset -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83159-4
    - DISA-STIG-SLES-12-020320
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_ssh_keysign
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the ssh_keysign rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/lib/ssh/ssh-keysign -F perm=x -F auid>=1000
      -F auid!=unset -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83159-4
    - DISA-STIG-SLES-12-020320
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_ssh_keysign
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Ensure auditd Collects Information on the Use of Privileged Commands - kmodrule

At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with suffix .rules in the directory /etc/audit/rules.d:

-w /usr/bin/kmod -p x -k modules
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules:
-w /usr/bin/kmod -p x -k modules

Rationale:

Without generating audit records that are specific to the security and mission needs of the organization, it would be difficult to establish, correlate, and investigate the events relating to an incident or identify those responsible for one. Audit records can be generated from various components within the information system (e.g., module or policy filter).

Remediation script:
- name: Service facts
  service_facts: null
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83207-1
    - DISA-STIG-SLES-12-020360
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_kmod
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check the rules script being used
  command: grep '^ExecStartPost' /usr/lib/systemd/system/auditd.service
  register: check_rules_scripts_result
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83207-1
    - DISA-STIG-SLES-12-020360
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_kmod
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Update kmod in /etc/audit/rules.d/audit.rules
  lineinfile:
    path: /etc/audit/rules.d/audit.rules
    line: -w /usr/bin/kmod -p x -k modules
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"auditd.service" in ansible_facts.services'
    - '"augenrules" in check_rules_scripts_result.stdout'
  register: augenrules_audit_rules_kmod_update_result
  tags:
    - CCE-83207-1
    - DISA-STIG-SLES-12-020360
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_kmod
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Update kmod in /etc/audit/audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -w /usr/bin/kmod -p x -k modules
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"auditd.service" in ansible_facts.services'
    - '"auditctl" in check_rules_scripts_result.stdout'
  register: auditctl_audit_rules_kmod_update_result
  tags:
    - CCE-83207-1
    - DISA-STIG-SLES-12-020360
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_kmod
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Restart auditd.service
  systemd:
    name: auditd.service
    state: restarted
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - (augenrules_audit_rules_kmod_update_result.changed or auditctl_audit_rules_kmod_update_result.changed)
    - ansible_facts.services["auditd.service"].state == "running"
  tags:
    - CCE-83207-1
    - DISA-STIG-SLES-12-020360
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_kmod
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Ensure auditd Collects Information on the Use of Privileged Commands - unix_chkpwdrule

At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/sbin/unix_chkpwd -F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules:
-a always,exit -F path=/usr/sbin/unix_chkpwd -F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats.

Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for unusual activity.

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/sbin/unix_chkpwd.*$
    patterns: '*.rules'
  register: find_unix_chkpwd
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83109-9
    - DISA-STIG-SLES-12-020680
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_unix_chkpwd
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_unix_chkpwd.matched is defined and find_unix_chkpwd.matched == 0
  tags:
    - CCE-83109-9
    - DISA-STIG-SLES-12-020680
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_unix_chkpwd
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_unix_chkpwd.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_unix_chkpwd.matched is defined and find_unix_chkpwd.matched > 0
  tags:
    - CCE-83109-9
    - DISA-STIG-SLES-12-020680
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_unix_chkpwd
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the unix_chkpwd rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F
      auid!=unset -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83109-9
    - DISA-STIG-SLES-12-020680
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_unix_chkpwd
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the unix_chkpwd rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F
      auid!=unset -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83109-9
    - DISA-STIG-SLES-12-020680
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_unix_chkpwd
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Ensure auditd Collects Information on the Use of Privileged Commands - gpasswdrule

At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/bin/gpasswd -F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules:
-a always,exit -F path=/usr/bin/gpasswd -F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats.

Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for unusual activity.

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/bin/gpasswd.*$
    patterns: '*.rules'
  register: find_gpasswd
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83161-0
    - DISA-STIG-SLES-12-020560
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_gpasswd
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_gpasswd.matched is defined and find_gpasswd.matched == 0
  tags:
    - CCE-83161-0
    - DISA-STIG-SLES-12-020560
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_gpasswd
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_gpasswd.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_gpasswd.matched is defined and find_gpasswd.matched > 0
  tags:
    - CCE-83161-0
    - DISA-STIG-SLES-12-020560
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_gpasswd
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the gpasswd rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83161-0
    - DISA-STIG-SLES-12-020560
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_gpasswd
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the gpasswd rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83161-0
    - DISA-STIG-SLES-12-020560
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_gpasswd
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Ensure auditd Collects Information on the Use of Privileged Commands - chfnrule

At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/bin/chfn -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules:
-a always,exit -F path=/usr/bin/chfn -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Without generating audit records that are specific to the security and mission needs of the organization, it would be difficult to establish, correlate, and investigate the events relating to an incident or identify those responsible for one. Audit records can be generated from various components within the information system (e.g., module or policy filter).

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/bin/chfn.*$
    patterns: '*.rules'
  register: find_chfn
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83187-5
    - DISA-STIG-SLES-12-020280
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_chfn
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_chfn.matched is defined and find_chfn.matched == 0
  tags:
    - CCE-83187-5
    - DISA-STIG-SLES-12-020280
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_chfn
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_chfn.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_chfn.matched is defined and find_chfn.matched > 0
  tags:
    - CCE-83187-5
    - DISA-STIG-SLES-12-020280
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_chfn
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the chfn rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/bin/chfn -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83187-5
    - DISA-STIG-SLES-12-020280
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_chfn
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the chfn rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/bin/chfn -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83187-5
    - DISA-STIG-SLES-12-020280
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-3
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_chfn
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Record Any Attempts to Run ssh-agentrule

At a minimum, the audit system should collect any execution attempt of the ssh-agent command for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-agent
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file:
-a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset -k privileged-ssh-agent

Rationale:

Without generating audit records that are specific to the security and mission needs of the organization, it would be difficult to establish, correlate, and investigate the events relating to an incident or identify those responsible for one. Audit records can be generated from various components within the information system (e.g., module or policy filter).

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/bin/ssh-agent.*$
    patterns: '*.rules'
  register: find_ssh_agent
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83199-0
    - DISA-STIG-SLES-12-020310
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(a)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_ssh_agent
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_ssh_agent.matched is defined and find_ssh_agent.matched == 0
  tags:
    - CCE-83199-0
    - DISA-STIG-SLES-12-020310
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(a)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_ssh_agent
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_ssh_agent.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_ssh_agent.matched is defined and find_ssh_agent.matched > 0
  tags:
    - CCE-83199-0
    - DISA-STIG-SLES-12-020310
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(a)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_ssh_agent
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the ssh_agent rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83199-0
    - DISA-STIG-SLES-12-020310
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(a)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_ssh_agent
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the ssh_agent rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83199-0
    - DISA-STIG-SLES-12-020310
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(a)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_privileged_commands_ssh_agent
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Ensure auditd Collects Information on the Use of Privileged Commands - surule

At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/bin/su -F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules:
-a always,exit -F path=/usr/bin/su -F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats.

Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for unusual activity.

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/bin/su.*$
    patterns: '*.rules'
  register: find_su
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83143-8
    - DISA-STIG-SLES-12-020250
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_su
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_su.matched is defined and find_su.matched == 0
  tags:
    - CCE-83143-8
    - DISA-STIG-SLES-12-020250
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_su
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_su.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_su.matched is defined and find_su.matched > 0
  tags:
    - CCE-83143-8
    - DISA-STIG-SLES-12-020250
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_su
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the su rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83143-8
    - DISA-STIG-SLES-12-020250
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_su
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the su rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83143-8
    - DISA-STIG-SLES-12-020250
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_su
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Ensure auditd Collects Information on the Use of Privileged Commands - sudorule

At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/bin/sudo -F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules:
-a always,exit -F path=/usr/bin/sudo -F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats.

Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for unusual activity.

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/bin/sudo.*$
    patterns: '*.rules'
  register: find_sudo
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83144-6
    - DISA-STIG-SLES-12-020260
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_sudo
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_sudo.matched is defined and find_sudo.matched == 0
  tags:
    - CCE-83144-6
    - DISA-STIG-SLES-12-020260
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_sudo
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_sudo.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_sudo.matched is defined and find_sudo.matched > 0
  tags:
    - CCE-83144-6
    - DISA-STIG-SLES-12-020260
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_sudo
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the sudo rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83144-6
    - DISA-STIG-SLES-12-020260
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_sudo
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the sudo rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83144-6
    - DISA-STIG-SLES-12-020260
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_sudo
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Ensure auditd Collects Information on the Use of Privileged Commands - umountrule

At a minimum, the audit system should collect the execution of privileged commands for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add a line of the following form to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/bin/umount -F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add a line of the following form to /etc/audit/audit.rules:
-a always,exit -F path=/usr/bin/umount -F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats.

Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for unusual activity.

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/bin/umount.*$
    patterns: '*.rules'
  register: find_umount
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83158-6
    - DISA-STIG-SLES-12-020300
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_umount
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_umount.matched is defined and find_umount.matched == 0
  tags:
    - CCE-83158-6
    - DISA-STIG-SLES-12-020300
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_umount
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_umount.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_umount.matched is defined and find_umount.matched > 0
  tags:
    - CCE-83158-6
    - DISA-STIG-SLES-12-020300
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_umount
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the umount rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83158-6
    - DISA-STIG-SLES-12-020300
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_umount
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the umount rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83158-6
    - DISA-STIG-SLES-12-020300
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - audit_rules_privileged_commands_umount
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Record Unauthorized Access Attempts Events to Files (unsuccessful)group

At a minimum, the audit system should collect unauthorized file accesses for all users and root. Note that the "-F arch=b32" lines should be present even on a 64 bit system. These commands identify system calls for auditing. Even if the system is 64 bit it can still execute 32 bit system calls. Additionally, these rules can be configured in a number of ways while still achieving the desired effect. An example of this is that the "-S" calls could be split up and placed on separate lines, however, this is less efficient. Add the following to /etc/audit/audit.rules:

-a always,exit -F arch=b32 -S creat,open,openat,open_by_handle_at,truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
    -a always,exit -F arch=b32 -S creat,open,openat,open_by_handle_at,truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
If your system is 64 bit then these lines should be duplicated and the arch=b32 replaced with arch=b64 as follows:
-a always,exit -F arch=b64 -S creat,open,openat,open_by_handle_at,truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
    -a always,exit -F arch=b64 -S creat,open,openat,open_by_handle_at,truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access

contains 6 rules

Record Unsuccessful Access Attempts to Files - openrule

At a minimum, the audit system should collect unauthorized file accesses for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b32 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
If the system is 64 bit then also add the following lines:
-a always,exit -F arch=b64 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b64 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b32 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
If the system is 64 bit then also add the following lines:
-a always,exit -F arch=b64 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b64 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing these events could serve as evidence of potential system compromise.

Remediation script:
- name: Set architecture for audit open tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83131-3
    - DISA-STIG-SLES-12-020490
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_open
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_open
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83131-3
    - DISA-STIG-SLES-12-020490
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_open
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/access.rules as
    the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/access.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_open.matched is defined and find_open.matched == 0
  tags:
    - CCE-83131-3
    - DISA-STIG-SLES-12-020490
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_open
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_open.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_open.matched is defined and find_open.matched > 0
  tags:
    - CCE-83131-3
    - DISA-STIG-SLES-12-020490
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_open
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the open rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: '{{ item }}'
    create: true
  with_items:
    - -a always,exit -F arch=b32 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b32 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83131-3
    - DISA-STIG-SLES-12-020490
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_open
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the open rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: '{{ item }}'
    create: true
  with_items:
    - -a always,exit -F arch=b64 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b64 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83131-3
    - DISA-STIG-SLES-12-020490
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_open
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the open rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: '{{ item }}'
    state: present
    dest: /etc/audit/audit.rules
    create: true
  with_items:
    - -a always,exit -F arch=b32 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b32 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83131-3
    - DISA-STIG-SLES-12-020490
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_open
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the open rule in audit.rules when on x86_64
  lineinfile:
    line: '{{ item }}'
    state: present
    dest: /etc/audit/audit.rules
    create: true
  with_items:
    - -a always,exit -F arch=b64 -S open -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b64 -S open -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83131-3
    - DISA-STIG-SLES-12-020490
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_open
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Unsuccessful Access Attempts to Files - open_by_handle_atrule

At a minimum, the audit system should collect unauthorized file accesses for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
If the system is 64 bit then also add the following lines:
-a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S open_by_handle_at,truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b32 -S open_by_handle_at,truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
If the system is 64 bit then also add the following lines:
-a always,exit -F arch=b64 -S open_by_handle_at,truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b64 -S open_by_handle_at,truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing these events could serve as evidence of potential system compromise.

Remediation script:
- name: Set architecture for audit open_by_handle_at tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83094-3
    - DISA-STIG-SLES-12-020540
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_open_by_handle_at
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_open_by_handle_at
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83094-3
    - DISA-STIG-SLES-12-020540
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_open_by_handle_at
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/access.rules as
    the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/access.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_open_by_handle_at.matched is defined and find_open_by_handle_at.matched
      == 0
  tags:
    - CCE-83094-3
    - DISA-STIG-SLES-12-020540
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_open_by_handle_at
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_open_by_handle_at.files | map(attribute=''path'') | list | first
        }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_open_by_handle_at.matched is defined and find_open_by_handle_at.matched
      > 0
  tags:
    - CCE-83094-3
    - DISA-STIG-SLES-12-020540
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_open_by_handle_at
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the open_by_handle_at rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: '{{ item }}'
    create: true
  with_items:
    - -a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EACCES -F auid>=1000
      -F auid!=unset -F key=access
    - -a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EPERM -F auid>=1000
      -F auid!=unset -F key=access
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83094-3
    - DISA-STIG-SLES-12-020540
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_open_by_handle_at
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the open_by_handle_at rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: '{{ item }}'
    create: true
  with_items:
    - -a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EACCES -F auid>=1000
      -F auid!=unset -F key=access
    - -a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EPERM -F auid>=1000
      -F auid!=unset -F key=access
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83094-3
    - DISA-STIG-SLES-12-020540
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_open_by_handle_at
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the open_by_handle_at rule in /etc/audit/audit.rules when
    on x86
  lineinfile:
    line: '{{ item }}'
    state: present
    dest: /etc/audit/audit.rules
    create: true
  with_items:
    - -a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EACCES -F auid>=1000
      -F auid!=unset -F key=access
    - -a always,exit -F arch=b32 -S open_by_handle_at -F exit=-EPERM -F auid>=1000
      -F auid!=unset -F key=access
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83094-3
    - DISA-STIG-SLES-12-020540
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_open_by_handle_at
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the open_by_handle_at rule in audit.rules when on x86_64
  lineinfile:
    line: '{{ item }}'
    state: present
    dest: /etc/audit/audit.rules
    create: true
  with_items:
    - -a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EACCES -F auid>=1000
      -F auid!=unset -F key=access
    - -a always,exit -F arch=b64 -S open_by_handle_at -F exit=-EPERM -F auid>=1000
      -F auid!=unset -F key=access
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83094-3
    - DISA-STIG-SLES-12-020540
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_open_by_handle_at
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Unsuccessful Access Attempts to Files - creatrule

At a minimum, the audit system should collect unauthorized file accesses for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
If the system is 64 bit then also add the following lines:
-a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
If the system is 64 bit then also add the following lines:
-a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing these events could serve as evidence of potential system compromise.

Remediation script:
- name: Set architecture for audit creat tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83092-7
    - DISA-STIG-SLES-12-020520
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_creat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_creat
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83092-7
    - DISA-STIG-SLES-12-020520
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_creat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/access.rules as
    the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/access.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_creat.matched is defined and find_creat.matched == 0
  tags:
    - CCE-83092-7
    - DISA-STIG-SLES-12-020520
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_creat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_creat.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_creat.matched is defined and find_creat.matched > 0
  tags:
    - CCE-83092-7
    - DISA-STIG-SLES-12-020520
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_creat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the creat rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: '{{ item }}'
    create: true
  with_items:
    - -a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83092-7
    - DISA-STIG-SLES-12-020520
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_creat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the creat rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: '{{ item }}'
    create: true
  with_items:
    - -a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83092-7
    - DISA-STIG-SLES-12-020520
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_creat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the creat rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: '{{ item }}'
    state: present
    dest: /etc/audit/audit.rules
    create: true
  with_items:
    - -a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83092-7
    - DISA-STIG-SLES-12-020520
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_creat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the creat rule in audit.rules when on x86_64
  lineinfile:
    line: '{{ item }}'
    state: present
    dest: /etc/audit/audit.rules
    create: true
  with_items:
    - -a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83092-7
    - DISA-STIG-SLES-12-020520
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_creat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Unsuccessful Access Attempts to Files - openatrule

At a minimum, the audit system should collect unauthorized file accesses for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b32 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
If the system is 64 bit then also add the following lines:
-a always,exit -F arch=b64 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b64 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b32 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
If the system is 64 bit then also add the following lines:
-a always,exit -F arch=b64 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b64 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing these events could serve as evidence of potential system compromise.

Remediation script:
- name: Set architecture for audit openat tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83093-5
    - DISA-STIG-SLES-12-020530
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_openat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_openat
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83093-5
    - DISA-STIG-SLES-12-020530
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_openat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/access.rules as
    the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/access.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_openat.matched is defined and find_openat.matched == 0
  tags:
    - CCE-83093-5
    - DISA-STIG-SLES-12-020530
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_openat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_openat.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_openat.matched is defined and find_openat.matched > 0
  tags:
    - CCE-83093-5
    - DISA-STIG-SLES-12-020530
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_openat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the openat rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: '{{ item }}'
    create: true
  with_items:
    - -a always,exit -F arch=b32 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b32 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83093-5
    - DISA-STIG-SLES-12-020530
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_openat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the openat rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: '{{ item }}'
    create: true
  with_items:
    - -a always,exit -F arch=b64 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b64 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83093-5
    - DISA-STIG-SLES-12-020530
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_openat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the openat rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: '{{ item }}'
    state: present
    dest: /etc/audit/audit.rules
    create: true
  with_items:
    - -a always,exit -F arch=b32 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b32 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83093-5
    - DISA-STIG-SLES-12-020530
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_openat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the openat rule in audit.rules when on x86_64
  lineinfile:
    line: '{{ item }}'
    state: present
    dest: /etc/audit/audit.rules
    create: true
  with_items:
    - -a always,exit -F arch=b64 -S openat -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b64 -S openat -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83093-5
    - DISA-STIG-SLES-12-020530
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_openat
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Unsuccessful Access Attempts to Files - truncaterule

At a minimum, the audit system should collect unauthorized file accesses for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b32 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
If the system is 64 bit then also add the following lines:
-a always,exit -F arch=b64 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b64 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b32 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
If the system is 64 bit then also add the following lines:
-a always,exit -F arch=b64 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b64 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing these events could serve as evidence of potential system compromise.

Remediation script:
- name: Set architecture for audit truncate tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83085-1
    - DISA-STIG-SLES-12-020500
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_truncate
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_truncate
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83085-1
    - DISA-STIG-SLES-12-020500
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_truncate
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/access.rules as
    the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/access.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_truncate.matched is defined and find_truncate.matched == 0
  tags:
    - CCE-83085-1
    - DISA-STIG-SLES-12-020500
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_truncate
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_truncate.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_truncate.matched is defined and find_truncate.matched > 0
  tags:
    - CCE-83085-1
    - DISA-STIG-SLES-12-020500
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_truncate
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the truncate rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: '{{ item }}'
    create: true
  with_items:
    - -a always,exit -F arch=b32 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b32 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83085-1
    - DISA-STIG-SLES-12-020500
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_truncate
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the truncate rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: '{{ item }}'
    create: true
  with_items:
    - -a always,exit -F arch=b64 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b64 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83085-1
    - DISA-STIG-SLES-12-020500
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_truncate
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the truncate rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: '{{ item }}'
    state: present
    dest: /etc/audit/audit.rules
    create: true
  with_items:
    - -a always,exit -F arch=b32 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b32 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83085-1
    - DISA-STIG-SLES-12-020500
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_truncate
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the truncate rule in audit.rules when on x86_64
  lineinfile:
    line: '{{ item }}'
    state: present
    dest: /etc/audit/audit.rules
    create: true
  with_items:
    - -a always,exit -F arch=b64 -S truncate -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b64 -S truncate -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83085-1
    - DISA-STIG-SLES-12-020500
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_truncate
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Unsuccessful Access Attempts to Files - ftruncaterule

At a minimum, the audit system should collect unauthorized file accesses for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F arch=b32 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b32 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
If the system is 64 bit then also add the following lines:
-a always,exit -F arch=b64 -S ftruncate -F exiu=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b64 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file:
-a always,exit -F arch=b32 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b32 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access
If the system is 64 bit then also add the following lines:
-a always,exit -F arch=b64 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=access
-a always,exit -F arch=b64 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=access

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect. Here the system calls have been placed independent of other system calls. Grouping these system calls with others as identifying earlier in this guide is more efficient.
Rationale:

Unsuccessful attempts to access files could be an indicator of malicious activity on a system. Auditing these events could serve as evidence of potential system compromise.

Remediation script:
- name: Set architecture for audit ftruncate tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83091-9
    - DISA-STIG-SLES-12-020510
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_ftruncate
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_ftruncate
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83091-9
    - DISA-STIG-SLES-12-020510
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_ftruncate
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/access.rules as
    the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/access.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_ftruncate.matched is defined and find_ftruncate.matched == 0
  tags:
    - CCE-83091-9
    - DISA-STIG-SLES-12-020510
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_ftruncate
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_ftruncate.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_ftruncate.matched is defined and find_ftruncate.matched > 0
  tags:
    - CCE-83091-9
    - DISA-STIG-SLES-12-020510
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_ftruncate
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the ftruncate rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: '{{ item }}'
    create: true
  with_items:
    - -a always,exit -F arch=b32 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b32 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83091-9
    - DISA-STIG-SLES-12-020510
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_ftruncate
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the ftruncate rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: '{{ item }}'
    create: true
  with_items:
    - -a always,exit -F arch=b64 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b64 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83091-9
    - DISA-STIG-SLES-12-020510
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_ftruncate
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the ftruncate rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: '{{ item }}'
    state: present
    dest: /etc/audit/audit.rules
    create: true
  with_items:
    - -a always,exit -F arch=b32 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b32 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83091-9
    - DISA-STIG-SLES-12-020510
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_ftruncate
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the ftruncate rule in audit.rules when on x86_64
  lineinfile:
    line: '{{ item }}'
    state: present
    dest: /etc/audit/audit.rules
    create: true
  with_items:
    - -a always,exit -F arch=b64 -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset
      -F key=access
    - -a always,exit -F arch=b64 -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset
      -F key=access
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83091-9
    - DISA-STIG-SLES-12-020510
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.1
    - PCI-DSS-Req-10.2.4
    - audit_rules_unsuccessful_file_modification_ftruncate
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Information on Kernel Modules Loading and Unloadinggroup

To capture kernel module loading and unloading events, use following lines, setting ARCH to either b32 for 32-bit system, or having two lines for both b32 and b64 in case your system is 64-bit:

-a always,exit -F arch=ARCH -S init_module,delete_module -F key=modules
Place to add the lines depends on a way auditd daemon is configured. If it is configured to use the augenrules program (the default), add the lines to a file with suffix .rules in the directory /etc/audit/rules.d. If the auditd daemon is configured to use the auditctl utility, add the lines to file /etc/audit/audit.rules.

contains 3 rules

Ensure auditd Collects Information on Kernel Module Loading and Unloading - finit_modulerule

If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d to capture kernel module loading and unloading events, setting ARCH to either b32 or b64 as appropriate for your system:

-a always,exit -F arch=ARCH -S finit_module -F key=modules
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file in order to capture kernel module loading and unloading events, setting ARCH to either b32 or b64 as appropriate for your system:
-a always,exit -F arch=ARCH -S finit_module -F key=modules

Rationale:

The addition/removal of kernel modules can be used to alter the behavior of the kernel and potentially introduce malicious code into kernel space. It is important to have an audit trail of modules that have been introduced into the kernel.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then



# First perform the remediation of the syscall rule
# Retrieve hardware architecture of the underlying system
# Note: 32-bit and 64-bit kernel syscall numbers not always line up =>
#       it's required on a 64-bit system to check also for the presence
#       of 32-bit's equivalent of the corresponding rule.
#       (See `man 7 audit.rules` for details )
[ "$(getconf LONG_BIT)" = "32" ] && RULE_ARCHS=("b32") || RULE_ARCHS=("b32" "b64")

for ARCH in "${RULE_ARCHS[@]}"
do
	PATTERN="-a always,exit -F arch=$ARCH -S finit_module \(-F key=\|-k \).*"
	GROUP="modules"
	FULL_RULE="-a always,exit -F arch=$ARCH -S finit_module -k modules"
	# Perform the remediation for both possible tools: 'auditctl' and 'augenrules'
# Function to fix syscall audit rule for given system call. It is
# based on example audit syscall rule definitions as outlined in
# /usr/share/doc/audit-2.3.7/stig.rules file provided with the audit
# package. It will combine multiple system calls belonging to the same
# syscall group into one audit rule (rather than to create audit rule per
# different system call) to avoid audit infrastructure performance penalty
# in the case of 'one-audit-rule-definition-per-one-system-call'. See:
#
#   https://www.redhat.com/archives/linux-audit/2014-November/msg00009.html
#
# for further details.
#
# Expects five arguments (each of them is required) in the form of:
# * audit tool				tool used to load audit rules,
# 					either 'auditctl', or 'augenrules
# * audit rules' pattern		audit rule skeleton for same syscall
# * syscall group			greatest common string this rule shares
# 					with other rules from the same group
# * architecture			architecture this rule is intended for
# * full form of new rule to add	expected full form of audit rule as to be
# 					added into audit.rules file
#
# Note: The 2-th up to 4-th arguments are used to determine how many existing
# audit rules will be inspected for resemblance with the new audit rule
# (5-th argument) the function is going to add. The rule's similarity check
# is performed to optimize audit.rules definition (merge syscalls of the same
# group into one rule) to avoid the "single-syscall-per-audit-rule" performance
# penalty.
#
# Example call:
#
#	See e.g. 'audit_rules_file_deletion_events.sh' remediation script
#
function fix_audit_syscall_rule {

# Load function arguments into local variables
local tool="$1"
local pattern="$2"
local group="$3"
local arch="$4"
local full_rule="$5"

# Check sanity of the input
if [ $# -ne "5" ]
then
	echo "Usage: fix_audit_syscall_rule 'tool' 'pattern' 'group' 'arch' 'full rule'"
	echo "Aborting."
	exit 1
fi

# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
# 
# -----------------------------------------------------------------------------------------
#  Tool used to load audit rules | Rule already defined  |  Audit rules file to inspect    |
# -----------------------------------------------------------------------------------------
#        auditctl                |     Doesn't matter    |  /etc/audit/audit.rules         |
# -----------------------------------------------------------------------------------------
#        augenrules              |          Yes          |  /etc/audit/rules.d/*.rules     |
#        augenrules              |          No           |  /etc/audit/rules.d/$key.rules  |
# -----------------------------------------------------------------------------------------
#
declare -a files_to_inspect

retval=0

# First check sanity of the specified audit tool
if [ "$tool" != 'auditctl' ] && [ "$tool" != 'augenrules' ]
then
	echo "Unknown audit rules loading tool: $1. Aborting."
	echo "Use either 'auditctl' or 'augenrules'!"
	return 1
# If audit tool is 'auditctl', then add '/etc/audit/audit.rules'
# file to the list of files to be inspected
elif [ "$tool" == 'auditctl' ]
then
	files_to_inspect+=('/etc/audit/audit.rules' )
# If audit tool is 'augenrules', then check if the audit rule is defined
# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection
# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection
elif [ "$tool" == 'augenrules' ]
then
	# Extract audit $key from audit rule so we can use it later
	matches=()
	key=$(expr "$full_rule" : '.*-k[[:space:]]\([^[:space:]]\+\)' '|' "$full_rule" : '.*-F[[:space:]]key=\([^[:space:]]\+\)')
	readarray -t matches < <(sed -s -n -e "\;${pattern};!d" -e "/${arch}/!d" -e "/${group}/!d;F" /etc/audit/rules.d/*.rules)
	if [ $? -ne 0 ]
	then
		retval=1
	fi
	for match in "${matches[@]}"
	do
		files_to_inspect+=("${match}")
	done
	# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet
	if [ ${#files_to_inspect[@]} -eq "0" ]
	then
		file_to_inspect="/etc/audit/rules.d/$key.rules"
		files_to_inspect=("$file_to_inspect")
		if [ ! -e "$file_to_inspect" ]
		then
			touch "$file_to_inspect"
			chmod 0640 "$file_to_inspect"
		fi
	fi
fi

#
# Indicator that we want to append $full_rule into $audit_file by default
local append_expected_rule=0

for audit_file in "${files_to_inspect[@]}"
do
	# Filter existing $audit_file rules' definitions to select those that:
	# * follow the rule pattern, and
	# * meet the hardware architecture requirement, and
	# * are current syscall group specific
	readarray -t existing_rules < <(sed -e "\;${pattern};!d" -e "/${arch}/!d" -e "/${group}/!d"  "$audit_file")
	if [ $? -ne 0 ]
	then
		retval=1
	fi

	# Process rules found case-by-case
	for rule in "${existing_rules[@]}"
	do
		# Found rule is for same arch & key, but differs (e.g. in count of -S arguments)
		if [ "${rule}" != "${full_rule}" ]
		then
			# If so, isolate just '(-S \w)+' substring of that rule
			rule_syscalls=$(echo "$rule" | grep -o -P '(-S \w+ )+')
			# Check if list of '-S syscall' arguments of that rule is subset
			# of '-S syscall' list of expected $full_rule
			if grep -q -- "$rule_syscalls" <<< "$full_rule"
			then
				# Rule is covered (i.e. the list of -S syscalls for this rule is
				# subset of -S syscalls of $full_rule => existing rule can be deleted
				# Thus delete the rule from audit.rules & our array
				sed -i -e "\;${rule};d" "$audit_file"
				if [ $? -ne 0 ]
				then
					retval=1
				fi
				existing_rules=("${existing_rules[@]//$rule/}")
			else
				# Rule isn't covered by $full_rule - it besides -S syscall arguments
				# for this group contains also -S syscall arguments for other syscall
				# group. Example: '-S lchown -S fchmod -S fchownat' => group='chown'
				# since 'lchown' & 'fchownat' share 'chown' substring
				# Therefore:
				# * 1) delete the original rule from audit.rules
				# (original '-S lchown -S fchmod -S fchownat' rule would be deleted)
				# * 2) delete the -S syscall arguments for this syscall group, but
				# keep those not belonging to this syscall group
				# (original '-S lchown -S fchmod -S fchownat' would become '-S fchmod'
				# * 3) append the modified (filtered) rule again into audit.rules
				# if the same rule not already present
				#
				# 1) Delete the original rule
				sed -i -e "\;${rule};d" "$audit_file"
				if [ $? -ne 0 ]
				then
					retval=1
				fi

				# 2) Delete syscalls for this group, but keep those from other groups
				# Convert current rule syscall's string into array splitting by '-S' delimiter
				IFS_BKP="$IFS"
				IFS=$'-S'
				read -a rule_syscalls_as_array <<< "$rule_syscalls"
				# Reset IFS back to default
				IFS="$IFS_BKP"
				# Splitting by "-S" can't be replaced by the readarray functionality easily

				# Declare new empty string to hold '-S syscall' arguments from other groups
				new_syscalls_for_rule=''
				# Walk through existing '-S syscall' arguments
				for syscall_arg in "${rule_syscalls_as_array[@]}"
				do
					# Skip empty $syscall_arg values
					if [ "$syscall_arg" == '' ]
					then
						continue
					fi
					# If the '-S syscall' doesn't belong to current group add it to the new list
					# (together with adding '-S' delimiter back for each of such item found)
					if grep -q -v -- "$group" <<< "$syscall_arg"
					then
						new_syscalls_for_rule="$new_syscalls_for_rule -S $syscall_arg"
					fi
				done
				# Replace original '-S syscall' list with the new one for this rule
				updated_rule=${rule//$rule_syscalls/$new_syscalls_for_rule}
				# Squeeze repeated whitespace characters in rule definition (if any) into one
				updated_rule=$(echo "$updated_rule" | tr -s '[:space:]')
				# 3) Append the modified / filtered rule again into audit.rules
				#    (but only in case it's not present yet to prevent duplicate definitions)
				if ! grep -q -- "$updated_rule" "$audit_file"
				then
					echo "$updated_rule" >> "$audit_file"
				fi
			fi
		else
			# $audit_file already contains the expected rule form for this
			# architecture & key => don't insert it second time
			append_expected_rule=1
		fi
	done

	# We deleted all rules that were subset of the expected one for this arch & key.
	# Also isolated rules containing system calls not from this system calls group.
	# Now append the expected rule if it's not present in $audit_file yet
	if [[ ${append_expected_rule} -eq "0" ]]
	then
		echo "$full_rule" >> "$audit_file"
	fi
done

return $retval

}
	fix_audit_syscall_rule "auditctl" "$PATTERN" "$GROUP" "$ARCH" "$FULL_RULE"
	fix_audit_syscall_rule "augenrules" "$PATTERN" "$GROUP" "$ARCH" "$FULL_RULE"
done

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Set architecture for audit finit_module tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83129-7
    - DISA-STIG-SLES-12-020740
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_finit
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*finit_module.*$
    patterns: '*.rules'
  register: find_finit_module
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83129-7
    - DISA-STIG-SLES-12-020740
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_finit
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_finit_module.matched is defined and find_finit_module.matched == 0
  tags:
    - CCE-83129-7
    - DISA-STIG-SLES-12-020740
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_finit
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_finit_module.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_finit_module.matched is defined and find_finit_module.matched > 0
  tags:
    - CCE-83129-7
    - DISA-STIG-SLES-12-020740
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_finit
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Inserts/replaces the finit_module rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b32 -S finit_module -k module-change
    state: present
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83129-7
    - DISA-STIG-SLES-12-020740
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_finit
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Inserts/replaces the finit_module rule in rules.d on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b64 -S finit_module -k module-change
    state: present
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83129-7
    - DISA-STIG-SLES-12-020740
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_finit
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Inserts/replaces the finit_module rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F arch=b32 -S finit_module -k module-change
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83129-7
    - DISA-STIG-SLES-12-020740
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_finit
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Inserts/replaces the finit_module rule in audit.rules when on x86_64
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F arch=b64 -S finit_module -k module-change
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83129-7
    - DISA-STIG-SLES-12-020740
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_finit
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

Ensure auditd Collects Information on Kernel Module Loading - init_modulerule

To capture kernel module loading events, use following line, setting ARCH to either b32 for 32-bit system, or having two lines for both b32 and b64 in case your system is 64-bit:

-a always,exit -F arch=ARCH -S init_module -F key=modules
Place to add the line depends on a way auditd daemon is configured. If it is configured to use the augenrules program (the default), add the line to a file with suffix .rules in the directory /etc/audit/rules.d. If the auditd daemon is configured to use the auditctl utility, add the line to file /etc/audit/audit.rules.

Rationale:

The addition of kernel modules can be used to alter the behavior of the kernel and potentially introduce malicious code into kernel space. It is important to have an audit trail of modules that have been introduced into the kernel.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then



# First perform the remediation of the syscall rule
# Retrieve hardware architecture of the underlying system
# Note: 32-bit and 64-bit kernel syscall numbers not always line up =>
#       it's required on a 64-bit system to check also for the presence
#       of 32-bit's equivalent of the corresponding rule.
#       (See `man 7 audit.rules` for details )
[ "$(getconf LONG_BIT)" = "32" ] && RULE_ARCHS=("b32") || RULE_ARCHS=("b32" "b64")

for ARCH in "${RULE_ARCHS[@]}"
do
	PATTERN="-a always,exit -F arch=$ARCH -S init_module \(-F key=\|-k \).*"
	GROUP="modules"
	FULL_RULE="-a always,exit -F arch=$ARCH -S init_module -k modules"
	# Perform the remediation for both possible tools: 'auditctl' and 'augenrules'
# Function to fix syscall audit rule for given system call. It is
# based on example audit syscall rule definitions as outlined in
# /usr/share/doc/audit-2.3.7/stig.rules file provided with the audit
# package. It will combine multiple system calls belonging to the same
# syscall group into one audit rule (rather than to create audit rule per
# different system call) to avoid audit infrastructure performance penalty
# in the case of 'one-audit-rule-definition-per-one-system-call'. See:
#
#   https://www.redhat.com/archives/linux-audit/2014-November/msg00009.html
#
# for further details.
#
# Expects five arguments (each of them is required) in the form of:
# * audit tool				tool used to load audit rules,
# 					either 'auditctl', or 'augenrules
# * audit rules' pattern		audit rule skeleton for same syscall
# * syscall group			greatest common string this rule shares
# 					with other rules from the same group
# * architecture			architecture this rule is intended for
# * full form of new rule to add	expected full form of audit rule as to be
# 					added into audit.rules file
#
# Note: The 2-th up to 4-th arguments are used to determine how many existing
# audit rules will be inspected for resemblance with the new audit rule
# (5-th argument) the function is going to add. The rule's similarity check
# is performed to optimize audit.rules definition (merge syscalls of the same
# group into one rule) to avoid the "single-syscall-per-audit-rule" performance
# penalty.
#
# Example call:
#
#	See e.g. 'audit_rules_file_deletion_events.sh' remediation script
#
function fix_audit_syscall_rule {

# Load function arguments into local variables
local tool="$1"
local pattern="$2"
local group="$3"
local arch="$4"
local full_rule="$5"

# Check sanity of the input
if [ $# -ne "5" ]
then
	echo "Usage: fix_audit_syscall_rule 'tool' 'pattern' 'group' 'arch' 'full rule'"
	echo "Aborting."
	exit 1
fi

# Create a list of audit *.rules files that should be inspected for presence and correctness
# of a particular audit rule. The scheme is as follows:
# 
# -----------------------------------------------------------------------------------------
#  Tool used to load audit rules | Rule already defined  |  Audit rules file to inspect    |
# -----------------------------------------------------------------------------------------
#        auditctl                |     Doesn't matter    |  /etc/audit/audit.rules         |
# -----------------------------------------------------------------------------------------
#        augenrules              |          Yes          |  /etc/audit/rules.d/*.rules     |
#        augenrules              |          No           |  /etc/audit/rules.d/$key.rules  |
# -----------------------------------------------------------------------------------------
#
declare -a files_to_inspect

retval=0

# First check sanity of the specified audit tool
if [ "$tool" != 'auditctl' ] && [ "$tool" != 'augenrules' ]
then
	echo "Unknown audit rules loading tool: $1. Aborting."
	echo "Use either 'auditctl' or 'augenrules'!"
	return 1
# If audit tool is 'auditctl', then add '/etc/audit/audit.rules'
# file to the list of files to be inspected
elif [ "$tool" == 'auditctl' ]
then
	files_to_inspect+=('/etc/audit/audit.rules' )
# If audit tool is 'augenrules', then check if the audit rule is defined
# If rule is defined, add '/etc/audit/rules.d/*.rules' to the list for inspection
# If rule isn't defined yet, add '/etc/audit/rules.d/$key.rules' to the list for inspection
elif [ "$tool" == 'augenrules' ]
then
	# Extract audit $key from audit rule so we can use it later
	matches=()
	key=$(expr "$full_rule" : '.*-k[[:space:]]\([^[:space:]]\+\)' '|' "$full_rule" : '.*-F[[:space:]]key=\([^[:space:]]\+\)')
	readarray -t matches < <(sed -s -n -e "\;${pattern};!d" -e "/${arch}/!d" -e "/${group}/!d;F" /etc/audit/rules.d/*.rules)
	if [ $? -ne 0 ]
	then
		retval=1
	fi
	for match in "${matches[@]}"
	do
		files_to_inspect+=("${match}")
	done
	# Case when particular rule isn't defined in /etc/audit/rules.d/*.rules yet
	if [ ${#files_to_inspect[@]} -eq "0" ]
	then
		file_to_inspect="/etc/audit/rules.d/$key.rules"
		files_to_inspect=("$file_to_inspect")
		if [ ! -e "$file_to_inspect" ]
		then
			touch "$file_to_inspect"
			chmod 0640 "$file_to_inspect"
		fi
	fi
fi

#
# Indicator that we want to append $full_rule into $audit_file by default
local append_expected_rule=0

for audit_file in "${files_to_inspect[@]}"
do
	# Filter existing $audit_file rules' definitions to select those that:
	# * follow the rule pattern, and
	# * meet the hardware architecture requirement, and
	# * are current syscall group specific
	readarray -t existing_rules < <(sed -e "\;${pattern};!d" -e "/${arch}/!d" -e "/${group}/!d"  "$audit_file")
	if [ $? -ne 0 ]
	then
		retval=1
	fi

	# Process rules found case-by-case
	for rule in "${existing_rules[@]}"
	do
		# Found rule is for same arch & key, but differs (e.g. in count of -S arguments)
		if [ "${rule}" != "${full_rule}" ]
		then
			# If so, isolate just '(-S \w)+' substring of that rule
			rule_syscalls=$(echo "$rule" | grep -o -P '(-S \w+ )+')
			# Check if list of '-S syscall' arguments of that rule is subset
			# of '-S syscall' list of expected $full_rule
			if grep -q -- "$rule_syscalls" <<< "$full_rule"
			then
				# Rule is covered (i.e. the list of -S syscalls for this rule is
				# subset of -S syscalls of $full_rule => existing rule can be deleted
				# Thus delete the rule from audit.rules & our array
				sed -i -e "\;${rule};d" "$audit_file"
				if [ $? -ne 0 ]
				then
					retval=1
				fi
				existing_rules=("${existing_rules[@]//$rule/}")
			else
				# Rule isn't covered by $full_rule - it besides -S syscall arguments
				# for this group contains also -S syscall arguments for other syscall
				# group. Example: '-S lchown -S fchmod -S fchownat' => group='chown'
				# since 'lchown' & 'fchownat' share 'chown' substring
				# Therefore:
				# * 1) delete the original rule from audit.rules
				# (original '-S lchown -S fchmod -S fchownat' rule would be deleted)
				# * 2) delete the -S syscall arguments for this syscall group, but
				# keep those not belonging to this syscall group
				# (original '-S lchown -S fchmod -S fchownat' would become '-S fchmod'
				# * 3) append the modified (filtered) rule again into audit.rules
				# if the same rule not already present
				#
				# 1) Delete the original rule
				sed -i -e "\;${rule};d" "$audit_file"
				if [ $? -ne 0 ]
				then
					retval=1
				fi

				# 2) Delete syscalls for this group, but keep those from other groups
				# Convert current rule syscall's string into array splitting by '-S' delimiter
				IFS_BKP="$IFS"
				IFS=$'-S'
				read -a rule_syscalls_as_array <<< "$rule_syscalls"
				# Reset IFS back to default
				IFS="$IFS_BKP"
				# Splitting by "-S" can't be replaced by the readarray functionality easily

				# Declare new empty string to hold '-S syscall' arguments from other groups
				new_syscalls_for_rule=''
				# Walk through existing '-S syscall' arguments
				for syscall_arg in "${rule_syscalls_as_array[@]}"
				do
					# Skip empty $syscall_arg values
					if [ "$syscall_arg" == '' ]
					then
						continue
					fi
					# If the '-S syscall' doesn't belong to current group add it to the new list
					# (together with adding '-S' delimiter back for each of such item found)
					if grep -q -v -- "$group" <<< "$syscall_arg"
					then
						new_syscalls_for_rule="$new_syscalls_for_rule -S $syscall_arg"
					fi
				done
				# Replace original '-S syscall' list with the new one for this rule
				updated_rule=${rule//$rule_syscalls/$new_syscalls_for_rule}
				# Squeeze repeated whitespace characters in rule definition (if any) into one
				updated_rule=$(echo "$updated_rule" | tr -s '[:space:]')
				# 3) Append the modified / filtered rule again into audit.rules
				#    (but only in case it's not present yet to prevent duplicate definitions)
				if ! grep -q -- "$updated_rule" "$audit_file"
				then
					echo "$updated_rule" >> "$audit_file"
				fi
			fi
		else
			# $audit_file already contains the expected rule form for this
			# architecture & key => don't insert it second time
			append_expected_rule=1
		fi
	done

	# We deleted all rules that were subset of the expected one for this arch & key.
	# Also isolated rules containing system calls not from this system calls group.
	# Now append the expected rule if it's not present in $audit_file yet
	if [[ ${append_expected_rule} -eq "0" ]]
	then
		echo "$full_rule" >> "$audit_file"
	fi
done

return $retval

}
	fix_audit_syscall_rule "auditctl" "$PATTERN" "$GROUP" "$ARCH" "$FULL_RULE"
	fix_audit_syscall_rule "augenrules" "$PATTERN" "$GROUP" "$ARCH" "$FULL_RULE"
done

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Set architecture for audit init_module tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83130-5
    - DISA-STIG-SLES-12-020750
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_init
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*init_module.*$
    patterns: '*.rules'
  register: find_init_module
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83130-5
    - DISA-STIG-SLES-12-020750
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_init
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_init_module.matched is defined and find_init_module.matched == 0
  tags:
    - CCE-83130-5
    - DISA-STIG-SLES-12-020750
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_init
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_init_module.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_init_module.matched is defined and find_init_module.matched > 0
  tags:
    - CCE-83130-5
    - DISA-STIG-SLES-12-020750
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_init
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Inserts/replaces the init_module rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b32 -S init_module -k module-change
    state: present
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83130-5
    - DISA-STIG-SLES-12-020750
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_init
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Inserts/replaces the init_module rule in rules.d on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b64 -S init_module -k module-change
    state: present
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83130-5
    - DISA-STIG-SLES-12-020750
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_init
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Inserts/replaces the init_module rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F arch=b32 -S init_module -k module-change
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83130-5
    - DISA-STIG-SLES-12-020750
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_init
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Inserts/replaces the init_module rule in audit.rules when on x86_64
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F arch=b64 -S init_module -k module-change
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83130-5
    - DISA-STIG-SLES-12-020750
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_init
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

Ensure auditd Collects Information on Kernel Module Unloading - delete_modulerule

To capture kernel module unloading events, use following line, setting ARCH to either b32 for 32-bit system, or having two lines for both b32 and b64 in case your system is 64-bit:

-a always,exit -F arch=ARCH -S delete_module -F key=modules
Place to add the line depends on a way auditd daemon is configured. If it is configured to use the augenrules program (the default), add the line to a file with suffix .rules in the directory /etc/audit/rules.d. If the auditd daemon is configured to use the auditctl utility, add the line to file /etc/audit/audit.rules.

Rationale:

The removal of kernel modules can be used to alter the behavior of the kernel and potentially introduce malicious code into kernel space. It is important to have an audit trail of modules that have been introduced into the kernel.

Remediation script:
- name: Set architecture for audit delete_module tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83128-9
    - DISA-STIG-SLES-12-020730
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_delete
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*delete_module.*$
    patterns: '*.rules'
  register: find_delete_module
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83128-9
    - DISA-STIG-SLES-12-020730
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_delete
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_delete_module.matched is defined and find_delete_module.matched == 0
  tags:
    - CCE-83128-9
    - DISA-STIG-SLES-12-020730
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_delete
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_delete_module.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_delete_module.matched is defined and find_delete_module.matched > 0
  tags:
    - CCE-83128-9
    - DISA-STIG-SLES-12-020730
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_delete
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Inserts/replaces the delete_module rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b32 -S delete_module -k module-change
    state: present
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83128-9
    - DISA-STIG-SLES-12-020730
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_delete
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Inserts/replaces the delete_module rule in rules.d on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b64 -S delete_module -k module-change
    state: present
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83128-9
    - DISA-STIG-SLES-12-020730
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_delete
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Inserts/replaces the delete_module rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F arch=b32 -S delete_module -k module-change
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83128-9
    - DISA-STIG-SLES-12-020730
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_delete
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Inserts/replaces the delete_module rule in audit.rules when on x86_64
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F arch=b64 -S delete_module -k module-change
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83128-9
    - DISA-STIG-SLES-12-020730
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_kernel_module_loading_delete
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

Record Execution Attempts to Run SELinux Privileged Commandsgroup

At a minimum, the audit system should collect the execution of SELinux privileged commands for all users and root.

contains 2 rules

Record Any Attempts to Run chconrule

At a minimum, the audit system should collect any execution attempt of the chcon command for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file:
-a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider and advanced persistent threats.

Privileged programs are subject to escalation-of-privilege attacks, which attempt to subvert their normal role of providing some necessary but limited capability. As such, motivation exists to monitor these programs for unusual activity.

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/bin/chcon.*$
    patterns: '*.rules'
  register: find_chcon
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83215-4
    - DISA-STIG-SLES-12-020630
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_chcon
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_chcon.matched is defined and find_chcon.matched == 0
  tags:
    - CCE-83215-4
    - DISA-STIG-SLES-12-020630
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_chcon
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_chcon.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_chcon.matched is defined and find_chcon.matched > 0
  tags:
    - CCE-83215-4
    - DISA-STIG-SLES-12-020630
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_chcon
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the chcon rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83215-4
    - DISA-STIG-SLES-12-020630
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_chcon
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the chcon rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83215-4
    - DISA-STIG-SLES-12-020630
    - NIST-800-171-3.1.7
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_chcon
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Record Any Attempts to Run rmrule

At a minimum, the audit system should collect any execution attempt of the rm command for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d:

-a always,exit -F path=/usr/bin/rm -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file:
-a always,exit -F path=/usr/bin/rm -F perm=x -F auid>=1000 -F auid!=unset -F key=privileged

Rationale:

Without generating audit records that are specific to the security and mission needs of the organization, it would be difficult to establish, correlate, and investigate the events relating to an incident or identify those responsible for one. Audit records can be generated from various components within the information system (e.g., module or policy filter).

Remediation script:
- name: Search /etc/audit/rules.d for audit rule entries
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: ^.*path=/usr/bin/rm.*$
    patterns: '*.rules'
  register: find_rm
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83216-2
    - DISA-STIG-SLES-12-020640
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_rm
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use /etc/audit/rules.d/privileged.rules as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_rm.matched is defined and find_rm.matched == 0
  tags:
    - CCE-83216-2
    - DISA-STIG-SLES-12-020640
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_rm
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_rm.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_rm.matched is defined and find_rm.matched > 0
  tags:
    - CCE-83216-2
    - DISA-STIG-SLES-12-020640
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_rm
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the rm rule in rules.d
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F path=/usr/bin/rm -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83216-2
    - DISA-STIG-SLES-12-020640
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_rm
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Inserts/replaces the rm rule in audit.rules
  lineinfile:
    path: /etc/audit/audit.rules
    line: -a always,exit -F path=/usr/bin/rm -F perm=x -F auid>=1000 -F auid!=unset
      -F key=privileged
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83216-2
    - DISA-STIG-SLES-12-020640
    - NIST-800-53-AU-12(a)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(ii)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3.1
    - NIST-800-53-MA-4(1)(a)
    - audit_rules_execution_rm
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Record Events When Privileged Executables Are Runrule

Verify the SUSE operating system generates an audit record when privileged functions are executed.

# grep -iw execve /etc/audit/audit.rules
-a always,exit -F arch=b32 -S execve -C uid!=euid -F euid=0 -k setuid
-a always,exit -F arch=b64 -S execve -C uid!=euid -F euid=0 -k setuid
-a always,exit -F arch=b32 -S execve -C gid!=egid -F egid=0 -k setgid
-a always,exit -F arch=b64 -S execve -C gid!=egid -F egid=0 -k setgid
If both the "b32" and "b64" audit rules for "SUID" files are not defined, this is a finding. If both the "b32" and "b64" audit rules for "SGID" files are not defined, this is a finding.

warning  Note that these rules can be configured in a number of ways while still achieving the desired effect.
Rationale:

Misuse of privileged functions, either intentionally or unintentionally by authorized users, or by unauthorized external entities that have compromised information system accounts, is a serious and ongoing concern and can have significant adverse impacts on organizations. Auditing the use of privileged functions is one way to detect such misuse and identify the risk from insider threats and the advanced persistent threat.

Remediation script:
- name: Service facts
  service_facts: null
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83200-6
    - DISA-STIG-SLES-12-020240
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(3)
    - NIST-800-53-AU-7(a)
    - NIST-800-53-AU-7(b)
    - NIST-800-53-AU-8(b)
    - NIST-800-53-CM-5(1)
    - audit_rules_suid_privilege_function
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check the rules script being used
  command: grep '^ExecStartPost' /usr/lib/systemd/system/auditd.service
  register: check_rules_scripts_result
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83200-6
    - DISA-STIG-SLES-12-020240
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(3)
    - NIST-800-53-AU-7(a)
    - NIST-800-53-AU-7(b)
    - NIST-800-53-AU-8(b)
    - NIST-800-53-CM-5(1)
    - audit_rules_suid_privilege_function
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Set suid_audit_rules fact
  set_fact:
    suid_audit_rules:
      - -a always,exit -F arch=b32 -S execve -C gid!=egid -F egid=0 -k setgid
      - -a always,exit -F arch=b64 -S execve -C gid!=egid -F egid=0 -k setgid
      - -a always,exit -F arch=b32 -S execve -C uid!=euid -F euid=0 -k setuid
      - -a always,exit -F arch=b64 -S execve -C uid!=euid -F euid=0 -k setuid
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83200-6
    - DISA-STIG-SLES-12-020240
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(3)
    - NIST-800-53-AU-7(a)
    - NIST-800-53-AU-7(b)
    - NIST-800-53-AU-8(b)
    - NIST-800-53-CM-5(1)
    - audit_rules_suid_privilege_function
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Update /etc/audit/rules.d/audit.rules to audit privileged functions
  lineinfile:
    path: /etc/audit/rules.d/audit.rules
    line: '{{  item  }}'
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"auditd.service" in ansible_facts.services'
    - '"augenrules" in check_rules_scripts_result.stdout'
  register: augenrules_audit_rules_privilege_function_update_result
  with_items: '{{ suid_audit_rules }}'
  tags:
    - CCE-83200-6
    - DISA-STIG-SLES-12-020240
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(3)
    - NIST-800-53-AU-7(a)
    - NIST-800-53-AU-7(b)
    - NIST-800-53-AU-8(b)
    - NIST-800-53-CM-5(1)
    - audit_rules_suid_privilege_function
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Update Update /etc/audit/audit.rules to audit privileged functions
  lineinfile:
    path: /etc/audit/audit.rules
    line: '{{  item  }}'
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"auditd.service" in ansible_facts.services'
    - '"auditctl" in check_rules_scripts_result.stdout'
  register: auditctl_audit_rules_privilege_function_update_result
  with_items: '{{ suid_audit_rules }}'
  tags:
    - CCE-83200-6
    - DISA-STIG-SLES-12-020240
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(3)
    - NIST-800-53-AU-7(a)
    - NIST-800-53-AU-7(b)
    - NIST-800-53-AU-8(b)
    - NIST-800-53-CM-5(1)
    - audit_rules_suid_privilege_function
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Restart auditd.service
  systemd:
    name: auditd.service
    state: restarted
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - (augenrules_audit_rules_privilege_function_update_result.changed or auditctl_audit_rules_privilege_function_update_result.changed)
    - ansible_facts.services["auditd.service"].state == "running"
  tags:
    - CCE-83200-6
    - DISA-STIG-SLES-12-020240
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(3)
    - NIST-800-53-AU-7(a)
    - NIST-800-53-AU-7(b)
    - NIST-800-53-AU-8(b)
    - NIST-800-53-CM-5(1)
    - audit_rules_suid_privilege_function
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Record Events that Modify User/Group Information - /etc/gshadowrule

If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d, in order to capture events that modify account changes:

-w /etc/gshadow -p wa -k audit_rules_usergroup_modification


If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file, in order to capture events that modify account changes:

-w /etc/gshadow -p wa -k audit_rules_usergroup_modification

Rationale:

In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected users, groups, or modifications should be investigated for legitimacy.

identifiers:  CCE-83095-0

references:  1, 11, 12, 13, 14, 15, 16, 18, 19, 2, 3, 4, 5, 6, 7, 8, 9, 5.4.1.1, APO10.01, APO10.03, APO10.04, APO10.05, APO11.04, APO12.06, APO13.01, BAI03.05, BAI08.02, DSS01.03, DSS01.04, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS03.05, DSS05.02, DSS05.03, DSS05.04, DSS05.05, DSS05.07, DSS06.03, MEA01.01, MEA01.02, MEA01.03, MEA01.04, MEA01.05, MEA02.01, 3.1.7, CCI-000018, CCI-000172, CCI-001403, CCI-001404, CCI-001405, CCI-001683, CCI-001684, CCI-001685, CCI-001686, CCI-002130, CCI-002132, 164.308(a)(1)(ii)(D), 164.308(a)(3)(ii)(A), 164.308(a)(5)(ii)(C), 164.312(a)(2)(i), 164.312(b), 164.312(d), 164.312(e), 4.2.3.10, 4.3.2.6.7, 4.3.3.2.2, 4.3.3.3.9, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.8, 4.3.3.6.6, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.4.7, 4.3.4.5.6, 4.3.4.5.7, 4.3.4.5.8, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 1.1, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.10, SR 2.11, SR 2.12, SR 2.6, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.1, SR 6.2, SR 7.1, SR 7.6, A.11.2.6, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.7, A.15.2.1, A.15.2.2, A.16.1.4, A.16.1.5, A.16.1.7, A.6.1.2, A.6.2.1, A.6.2.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, AC-2(4), AU-2(d), AU-12(c), AC-6(9), CM-6(a), DE.AE-3, DE.AE-5, DE.CM-1, DE.CM-3, DE.CM-7, ID.SC-4, PR.AC-1, PR.AC-3, PR.AC-4, PR.AC-6, PR.PT-1, PR.PT-4, RS.AN-1, RS.AN-4, FAU_GEN.1.1.c, Req-10.2.5, SRG-OS-000004-GPOS-00004, SLES-12-020590, SV-217240r603262_rule, SRG-OS-000004-VMM-000040, SRG-OS-000239-VMM-000810, SRG-OS-000240-VMM-000820, SRG-OS-000241-VMM-000830, SRG-OS-000274-VMM-000960, SRG-OS-000275-VMM-000970, SRG-OS-000276-VMM-000980, SRG-OS-000277-VMM-000990, SRG-OS-000303-VMM-001090, SRG-OS-000304-VMM-001100, SRG-OS-000476-VMM-001960

Remediation script:
- name: Set architecture for audit gshadow tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83095-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020590
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_gshadow
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other user/group modification audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -k audit_rules_usergroup_modification$
    patterns: '*.rules'
  register: find_gshadow
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83095-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020590
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_gshadow
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing user/group modification ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_gshadow.matched is defined and find_gshadow.matched == 0
  tags:
    - CCE-83095-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020590
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_gshadow
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_gshadow.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_gshadow.matched is defined and find_gshadow.matched > 0
  tags:
    - CCE-83095-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020590
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_gshadow
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the gshadow rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -w /etc/gshadow -p wa -k audit_rules_usergroup_modification
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83095-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020590
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_gshadow
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the gshadow rule in /etc/audit/audit.rules
  lineinfile:
    line: -w /etc/gshadow -p wa -k audit_rules_usergroup_modification
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83095-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020590
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_gshadow
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Remove Default Configuration to Disable Syscall Auditingrule

By default, SUSE Linux Enterprise 12 ships an audit rule to disable syscall auditing for performance reasons. To make sure that syscall auditing works, this line must be removed from /etc/audit/rules.d/audit.rules and /etc/audit/audit.rules:

-a task,never

Rationale:

Audit rules for syscalls do not take effect unless this line is removed.

identifiers:  CCE-83119-8

references:  CCI-000366, SRG-OS-000480-GPOS-00227, SLES-12-020199, SV-217204r646746_rule

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if [ -f "/usr/lib/systemd/system/auditd.service" ] ; then
    EXECSTARTPOST_SCRIPT=$(grep '^ExecStartPost=' /usr/lib/systemd/system/auditd.service | sed 's/ExecStartPost=//')

    if [[ "$EXECSTARTPOST_SCRIPT" == *"augenrules"* ]] ; then
        for f in /etc/audit/rules.d/*.rules ; do
            sed -E -i --follow-symlinks 's/^(\s*-a\s+task,never)/#\1/' "$f"
        done
    else
        # auditctl is used
        sed -E -i --follow-symlinks 's/^(\s*-a\s+task,never)/#\1/' /etc/audit/audit.rules
    fi

    systemctl is-active --quiet auditd.service
    if [ $? -ne 0 ] ; then
        systemctl restart auditd.service
    fi
fi

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Service facts
  service_facts: null
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83119-8
    - DISA-STIG-SLES-12-020199
    - audit_rules_enable_syscall_auditing
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check the rules script being used
  command: grep '^ExecStartPost' /usr/lib/systemd/system/auditd.service
  register: check_rules_scripts_result
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83119-8
    - DISA-STIG-SLES-12-020199
    - audit_rules_enable_syscall_auditing
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Find audit rules in /etc/audit/rules.d
  find:
    paths: /etc/audit/rules.d
    file_type: file
    follow: true
  register: find_audit_rules_result
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"auditd.service" in ansible_facts.services'
    - '"augenrules" in check_rules_scripts_result.stdout'
  tags:
    - CCE-83119-8
    - DISA-STIG-SLES-12-020199
    - audit_rules_enable_syscall_auditing
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Enable syscall auditing (augenrules)
  lineinfile:
    path: '{{ item.path }}'
    regex: ^(?i)(\s*-a\s+task,never)\s*$
    line: '#-a task,never'
  with_items: '{{ find_audit_rules_result.files }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"auditd.service" in ansible_facts.services'
    - '"augenrules" in check_rules_scripts_result.stdout'
  register: augenrules_syscall_auditing_rule_update_result
  tags:
    - CCE-83119-8
    - DISA-STIG-SLES-12-020199
    - audit_rules_enable_syscall_auditing
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Enable syscall auditing (auditctl)
  lineinfile:
    path: /etc/audit/audit.rules
    regex: ^(?i)(\s*-a\s+task,never)\s*$
    line: '#-a task,never'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"auditd.service" in ansible_facts.services'
    - '"auditctl" in check_rules_scripts_result.stdout'
  register: auditctl_syscall_auditing_rule_update_result
  tags:
    - CCE-83119-8
    - DISA-STIG-SLES-12-020199
    - audit_rules_enable_syscall_auditing
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Restart auditd.service
  systemd:
    name: auditd.service
    state: restarted
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ansible_facts.services["auditd.service"].state == "running"
    - (augenrules_syscall_auditing_rule_update_result.changed or auditctl_syscall_auditing_rule_update_result.changed)
  tags:
    - CCE-83119-8
    - DISA-STIG-SLES-12-020199
    - audit_rules_enable_syscall_auditing
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Record Events that Modify User/Group Information - /etc/passwdrule

If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d, in order to capture events that modify account changes:

-w /etc/passwd -p wa -k audit_rules_usergroup_modification


If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file, in order to capture events that modify account changes:

-w /etc/passwd -p wa -k audit_rules_usergroup_modification

Rationale:

In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected users, groups, or modifications should be investigated for legitimacy.

identifiers:  CCE-83120-6

references:  1, 11, 12, 13, 14, 15, 16, 18, 19, 2, 3, 4, 5, 6, 7, 8, 9, 5.4.1.1, APO10.01, APO10.03, APO10.04, APO10.05, APO11.04, APO12.06, APO13.01, BAI03.05, BAI08.02, DSS01.03, DSS01.04, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS03.05, DSS05.02, DSS05.03, DSS05.04, DSS05.05, DSS05.07, DSS06.03, MEA01.01, MEA01.02, MEA01.03, MEA01.04, MEA01.05, MEA02.01, 3.1.7, CCI-000018, CCI-000172, CCI-001403, CCI-001404, CCI-001405, CCI-001683, CCI-001684, CCI-001685, CCI-001686, CCI-002130, CCI-002132, 164.308(a)(1)(ii)(D), 164.308(a)(3)(ii)(A), 164.308(a)(5)(ii)(C), 164.312(a)(2)(i), 164.312(b), 164.312(d), 164.312(e), 4.2.3.10, 4.3.2.6.7, 4.3.3.2.2, 4.3.3.3.9, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.8, 4.3.3.6.6, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.4.7, 4.3.4.5.6, 4.3.4.5.7, 4.3.4.5.8, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 1.1, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.10, SR 2.11, SR 2.12, SR 2.6, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.1, SR 6.2, SR 7.1, SR 7.6, A.11.2.6, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.7, A.15.2.1, A.15.2.2, A.16.1.4, A.16.1.5, A.16.1.7, A.6.1.2, A.6.2.1, A.6.2.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, AC-2(4), AU-2(d), AU-12(c), AC-6(9), CM-6(a), DE.AE-3, DE.AE-5, DE.CM-1, DE.CM-3, DE.CM-7, ID.SC-4, PR.AC-1, PR.AC-3, PR.AC-4, PR.AC-6, PR.PT-1, PR.PT-4, RS.AN-1, RS.AN-4, FAU_GEN.1.1.c, Req-10.2.5, SRG-OS-000004-GPOS-00004, SRG-OS-000239-GPOS-00089, SRG-OS-000240-GPOS-00090, SRG-OS-000241-GPOS-00091, SRG-OS-000274-GPOS-00104, SRG-OS-000275-GPOS-00105, SRG-OS-000276-GPOS-00106, SRG-OS-000277-GPOS-00107, SRG-OS-000303-GPOS-00120, SRG-OS-000476-GPOS-00221, SLES-12-020200, SV-217205r603262_rule, SRG-OS-000004-VMM-000040, SRG-OS-000239-VMM-000810, SRG-OS-000240-VMM-000820, SRG-OS-000241-VMM-000830, SRG-OS-000274-VMM-000960, SRG-OS-000275-VMM-000970, SRG-OS-000276-VMM-000980, SRG-OS-000277-VMM-000990, SRG-OS-000303-VMM-001090, SRG-OS-000304-VMM-001100, SRG-OS-000476-VMM-001960

Remediation script:
- name: Set architecture for audit passwd tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83120-6
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020200
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_passwd
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other user/group modification audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -k audit_rules_usergroup_modification$
    patterns: '*.rules'
  register: find_passwd
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83120-6
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020200
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_passwd
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing user/group modification ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_passwd.matched is defined and find_passwd.matched == 0
  tags:
    - CCE-83120-6
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020200
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_passwd
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_passwd.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_passwd.matched is defined and find_passwd.matched > 0
  tags:
    - CCE-83120-6
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020200
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_passwd
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the passwd rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -w /etc/passwd -p wa -k audit_rules_usergroup_modification
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83120-6
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020200
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_passwd
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the passwd rule in /etc/audit/audit.rules
  lineinfile:
    line: -w /etc/passwd -p wa -k audit_rules_usergroup_modification
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83120-6
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020200
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_passwd
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Events that Modify User/Group Information - /etc/grouprule

If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d, in order to capture events that modify account changes:

-w /etc/group -p wa -k audit_rules_usergroup_modification


If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file, in order to capture events that modify account changes:

-w /etc/group -p wa -k audit_rules_usergroup_modification

Rationale:

In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected users, groups, or modifications should be investigated for legitimacy.

identifiers:  CCE-83121-4

references:  1, 11, 12, 13, 14, 15, 16, 18, 19, 2, 3, 4, 5, 6, 7, 8, 9, 5.4.1.1, APO10.01, APO10.03, APO10.04, APO10.05, APO11.04, APO12.06, APO13.01, BAI03.05, BAI08.02, DSS01.03, DSS01.04, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS03.05, DSS05.02, DSS05.03, DSS05.04, DSS05.05, DSS05.07, DSS06.03, MEA01.01, MEA01.02, MEA01.03, MEA01.04, MEA01.05, MEA02.01, 3.1.7, CCI-000018, CCI-000172, CCI-001403, CCI-001404, CCI-001405, CCI-001683, CCI-001684, CCI-001685, CCI-001686, CCI-002130, CCI-002132, 164.308(a)(1)(ii)(D), 164.308(a)(3)(ii)(A), 164.308(a)(5)(ii)(C), 164.312(a)(2)(i), 164.312(b), 164.312(d), 164.312(e), 4.2.3.10, 4.3.2.6.7, 4.3.3.2.2, 4.3.3.3.9, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.8, 4.3.3.6.6, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.4.7, 4.3.4.5.6, 4.3.4.5.7, 4.3.4.5.8, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 1.1, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.10, SR 2.11, SR 2.12, SR 2.6, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.1, SR 6.2, SR 7.1, SR 7.6, A.11.2.6, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.7, A.15.2.1, A.15.2.2, A.16.1.4, A.16.1.5, A.16.1.7, A.6.1.2, A.6.2.1, A.6.2.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, AC-2(4), AU-2(d), AU-12(c), AC-6(9), CM-6(a), DE.AE-3, DE.AE-5, DE.CM-1, DE.CM-3, DE.CM-7, ID.SC-4, PR.AC-1, PR.AC-3, PR.AC-4, PR.AC-6, PR.PT-1, PR.PT-4, RS.AN-1, RS.AN-4, FAU_GEN.1.1.c, Req-10.2.5, SRG-OS-000004-GPOS-00004, SLES-12-020210, SV-217206r603262_rule, SRG-OS-000004-VMM-000040, SRG-OS-000239-VMM-000810, SRG-OS-000240-VMM-000820, SRG-OS-000241-VMM-000830, SRG-OS-000274-VMM-000960, SRG-OS-000275-VMM-000970, SRG-OS-000276-VMM-000980, SRG-OS-000277-VMM-000990, SRG-OS-000303-VMM-001090, SRG-OS-000304-VMM-001100, SRG-OS-000476-VMM-001960

Remediation script:
- name: Set architecture for audit group tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83121-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020210
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_group
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other user/group modification audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -k audit_rules_usergroup_modification$
    patterns: '*.rules'
  register: find_group
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83121-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020210
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_group
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing user/group modification ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_group.matched is defined and find_group.matched == 0
  tags:
    - CCE-83121-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020210
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_group
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_group.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_group.matched is defined and find_group.matched > 0
  tags:
    - CCE-83121-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020210
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_group
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the group rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -w /etc/group -p wa -k audit_rules_usergroup_modification
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83121-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020210
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_group
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the group rule in /etc/audit/audit.rules
  lineinfile:
    line: -w /etc/group -p wa -k audit_rules_usergroup_modification
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83121-4
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020210
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_group
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Events that Modify User/Group Information - /etc/shadowrule

If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d, in order to capture events that modify account changes:

-w /etc/shadow -p wa -k audit_rules_usergroup_modification


If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file, in order to capture events that modify account changes:

-w /etc/shadow -p wa -k audit_rules_usergroup_modification

Rationale:

In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected users, groups, or modifications should be investigated for legitimacy.

identifiers:  CCE-83122-2

references:  1, 11, 12, 13, 14, 15, 16, 18, 19, 2, 3, 4, 5, 6, 7, 8, 9, 5.4.1.1, APO10.01, APO10.03, APO10.04, APO10.05, APO11.04, APO12.06, APO13.01, BAI03.05, BAI08.02, DSS01.03, DSS01.04, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS03.05, DSS05.02, DSS05.03, DSS05.04, DSS05.05, DSS05.07, DSS06.03, MEA01.01, MEA01.02, MEA01.03, MEA01.04, MEA01.05, MEA02.01, 3.1.7, CCI-000018, CCI-000172, CCI-001403, CCI-001404, CCI-001405, CCI-001683, CCI-001684, CCI-001685, CCI-001686, CCI-002130, CCI-002132, 164.308(a)(1)(ii)(D), 164.308(a)(3)(ii)(A), 164.308(a)(5)(ii)(C), 164.312(a)(2)(i), 164.312(b), 164.312(d), 164.312(e), 4.2.3.10, 4.3.2.6.7, 4.3.3.2.2, 4.3.3.3.9, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.8, 4.3.3.6.6, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.4.7, 4.3.4.5.6, 4.3.4.5.7, 4.3.4.5.8, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 1.1, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.10, SR 2.11, SR 2.12, SR 2.6, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.1, SR 6.2, SR 7.1, SR 7.6, A.11.2.6, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.7, A.15.2.1, A.15.2.2, A.16.1.4, A.16.1.5, A.16.1.7, A.6.1.2, A.6.2.1, A.6.2.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, AC-2(4), AU-2(d), AU-12(c), AC-6(9), CM-6(a), DE.AE-3, DE.AE-5, DE.CM-1, DE.CM-3, DE.CM-7, ID.SC-4, PR.AC-1, PR.AC-3, PR.AC-4, PR.AC-6, PR.PT-1, PR.PT-4, RS.AN-1, RS.AN-4, FAU_GEN.1.1.c, Req-10.2.5, SRG-OS-000004-GPOS-00004, SRG-OS-000239-GPOS-00089, SRG-OS-000240-GPOS-00090, SRG-OS-000241-GPOS-00091, SRG-OS-000303-GPOS-00120, SRG-OS-000476-GPOS-00221, SLES-12-020220, SV-217207r603262_rule, SRG-OS-000004-VMM-000040, SRG-OS-000239-VMM-000810, SRG-OS-000240-VMM-000820, SRG-OS-000241-VMM-000830, SRG-OS-000274-VMM-000960, SRG-OS-000275-VMM-000970, SRG-OS-000276-VMM-000980, SRG-OS-000277-VMM-000990, SRG-OS-000303-VMM-001090, SRG-OS-000304-VMM-001100, SRG-OS-000476-VMM-001960

Remediation script:
- name: Set architecture for audit shadow tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83122-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020220
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_shadow
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other user/group modification audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -k audit_rules_usergroup_modification$
    patterns: '*.rules'
  register: find_shadow
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83122-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020220
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_shadow
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing user/group modification ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_shadow.matched is defined and find_shadow.matched == 0
  tags:
    - CCE-83122-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020220
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_shadow
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_shadow.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_shadow.matched is defined and find_shadow.matched > 0
  tags:
    - CCE-83122-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020220
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_shadow
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the shadow rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -w /etc/shadow -p wa -k audit_rules_usergroup_modification
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83122-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020220
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_shadow
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the shadow rule in /etc/audit/audit.rules
  lineinfile:
    line: -w /etc/shadow -p wa -k audit_rules_usergroup_modification
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83122-2
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020220
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_shadow
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Ensure auditd Collects Information on Exporting to Media (successful)rule

At a minimum, the audit system should collect media exportation events for all users and root. If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following line to a file with suffix .rules in the directory /etc/audit/rules.d, setting ARCH to either b32 or b64 as appropriate for your system:

-a always,exit -F arch=ARCH -S mount -F auid>=1000 -F auid!=unset -F key=export
If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following line to /etc/audit/audit.rules file, setting ARCH to either b32 or b64 as appropriate for your system:
-a always,exit -F arch=ARCH -S mount -F auid>=1000 -F auid!=unset -F key=export

Rationale:

The unauthorized exportation of data to external media could result in an information leak where classified information, Privacy Act information, and intellectual property could be lost. An audit trail should be created each time a filesystem is mounted to help identify and guard against information loss.

Remediation script:
- name: Set architecture for audit mount tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83217-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020290
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_media_export
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other DAC audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -F key=perm_mod$
    patterns: '*.rules'
  register: find_mount
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83217-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020290
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_media_export
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing DAC ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_mount.matched is defined and find_mount.matched == 0
  tags:
    - CCE-83217-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020290
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_media_export
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_mount.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_mount.matched is defined and find_mount.matched > 0
  tags:
    - CCE-83217-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020290
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_media_export
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the mount rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b32 -S mount -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83217-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020290
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_media_export
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the mount rule in rules.d when on x86_64
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -a always,exit -F arch=b64 -S mount -F auid>=1000 -F auid!=unset -F key=perm_mod
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83217-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020290
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_media_export
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the mount rule in /etc/audit/audit.rules when on x86
  lineinfile:
    line: -a always,exit -F arch=b32 -S mount -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83217-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020290
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_media_export
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the mount rule in audit.rules when on x86_64
  lineinfile:
    line: -a always,exit -F arch=b64 -S mount -F auid>=1000 -F auid!=unset -F key=perm_mod
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - audit_arch is defined and audit_arch == 'b64'
  tags:
    - CCE-83217-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020290
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.7
    - audit_rules_media_export
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Record Events that Modify User/Group Information - /etc/security/opasswdrule

If the auditd daemon is configured to use the augenrules program to read audit rules during daemon startup (the default), add the following lines to a file with suffix .rules in the directory /etc/audit/rules.d, in order to capture events that modify account changes:

-w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification


If the auditd daemon is configured to use the auditctl utility to read audit rules during daemon startup, add the following lines to /etc/audit/audit.rules file, in order to capture events that modify account changes:

-w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification

Rationale:

In addition to auditing new user and group accounts, these watches will alert the system administrator(s) to any modifications. Any unexpected users, groups, or modifications should be investigated for legitimacy.

identifiers:  CCE-83123-0

references:  1, 11, 12, 13, 14, 15, 16, 18, 19, 2, 3, 4, 5, 6, 7, 8, 9, 5.4.1.1, APO10.01, APO10.03, APO10.04, APO10.05, APO11.04, APO12.06, APO13.01, BAI03.05, BAI08.02, DSS01.03, DSS01.04, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS03.05, DSS05.02, DSS05.03, DSS05.04, DSS05.05, DSS05.07, DSS06.03, MEA01.01, MEA01.02, MEA01.03, MEA01.04, MEA01.05, MEA02.01, 3.1.7, CCI-000018, CCI-000172, CCI-001403, CCI-001404, CCI-001405, CCI-001683, CCI-001684, CCI-001685, CCI-001686, CCI-002130, CCI-002132, 164.308(a)(1)(ii)(D), 164.308(a)(3)(ii)(A), 164.308(a)(5)(ii)(C), 164.312(a)(2)(i), 164.312(b), 164.312(d), 164.312(e), 4.2.3.10, 4.3.2.6.7, 4.3.3.2.2, 4.3.3.3.9, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.8, 4.3.3.6.6, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.4.7, 4.3.4.5.6, 4.3.4.5.7, 4.3.4.5.8, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 1.1, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.10, SR 2.11, SR 2.12, SR 2.6, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.1, SR 6.2, SR 7.1, SR 7.6, A.11.2.6, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.7, A.15.2.1, A.15.2.2, A.16.1.4, A.16.1.5, A.16.1.7, A.6.1.2, A.6.2.1, A.6.2.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, AC-2(4), AU-2(d), AU-12(c), AC-6(9), CM-6(a), DE.AE-3, DE.AE-5, DE.CM-1, DE.CM-3, DE.CM-7, ID.SC-4, PR.AC-1, PR.AC-3, PR.AC-4, PR.AC-6, PR.PT-1, PR.PT-4, RS.AN-1, RS.AN-4, FAU_GEN.1.1.c, Req-10.2.5, SRG-OS-000004-GPOS-00004, SRG-OS-000239-GPOS-00089, SRG-OS-000240-GPOS-00090, SRG-OS-000241-GPOS-00091, SRG-OS-000303-GPOS-00120, SRG-OS-000463-GPOS-00207, SRG-OS-000476-GPOS-00221, SLES-12-020230, SV-217208r603262_rule, SRG-OS-000004-VMM-000040, SRG-OS-000239-VMM-000810, SRG-OS-000240-VMM-000820, SRG-OS-000241-VMM-000830, SRG-OS-000274-VMM-000960, SRG-OS-000275-VMM-000970, SRG-OS-000276-VMM-000980, SRG-OS-000277-VMM-000990, SRG-OS-000303-VMM-001090, SRG-OS-000304-VMM-001100, SRG-OS-000476-VMM-001960

Remediation script:
- name: Set architecture for audit opasswd tasks
  set_fact:
    audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }}
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83123-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020230
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_opasswd
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Search /etc/audit/rules.d for other user/group modification audit rules
  find:
    paths: /etc/audit/rules.d
    recurse: false
    contains: -k audit_rules_usergroup_modification$
    patterns: '*.rules'
  register: find_opasswd
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83123-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020230
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_opasswd
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: If existing user/group modification ruleset not found, use /etc/audit/rules.d/privileged.rules
    as the recipient for the rule
  set_fact:
    all_files:
      - /etc/audit/rules.d/privileged.rules
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_opasswd.matched is defined and find_opasswd.matched == 0
  tags:
    - CCE-83123-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020230
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_opasswd
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Use matched file as the recipient for the rule
  set_fact:
    all_files:
      - '{{ find_opasswd.files | map(attribute=''path'') | list | first }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - find_opasswd.matched is defined and find_opasswd.matched > 0
  tags:
    - CCE-83123-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020230
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_opasswd
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the opasswd rule in rules.d when on x86
  lineinfile:
    path: '{{ all_files[0] }}'
    line: -w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83123-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020230
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_opasswd
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Inserts/replaces the opasswd rule in /etc/audit/audit.rules
  lineinfile:
    line: -w /etc/security/opasswd -p wa -k audit_rules_usergroup_modification
    state: present
    dest: /etc/audit/audit.rules
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83123-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020230
    - NIST-800-171-3.1.7
    - NIST-800-53-AC-2(4)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-10.2.5
    - audit_rules_usergroup_modification_opasswd
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

Configure auditd Data Retentiongroup

The audit system writes data to /var/log/audit/audit.log. By default, auditd rotates 5 logs by size (6MB), retaining a maximum of 30MB of data in total, and refuses to write entries when the disk is too full. This minimizes the risk of audit data filling its partition and impacting other services. This also minimizes the risk of the audit daemon temporarily disabling the system if it cannot write audit log (which it can be configured to do). For a busy system or a system which is thoroughly auditing system activity, the default settings for data retention may be insufficient. The log file size needed will depend heavily on what types of events are being audited. First configure auditing to log all the events of interest. Then monitor the log size manually for awhile to determine what file size will allow you to keep the required data for the correct time period.

Using a dedicated partition for /var/log/audit prevents the auditd logs from disrupting system functionality if they fill, and, more importantly, prevents other activity in /var from filling the partition and stopping the audit trail. (The audit logs are size-limited and therefore unlikely to grow without bound unless configured to do so.) Some machines may have requirements that no actions occur which cannot be audited. If this is the case, then auditd can be configured to halt the machine if it runs out of space. Note: Since older logs are rotated, configuring auditd this way does not prevent older logs from being rotated away before they can be viewed. If your system is configured to halt when logging cannot be performed, make sure this can never happen under normal circumstances! Ensure that /var/log/audit is on its own partition, and that this partition is larger than the maximum amount of data auditd will retain normally.

contains 7 rules

Configure auditd Disk Full Action when Disk Space Is Fullrule

The auditd service can be configured to take an action when disk space is running low but prior to running out of space completely. Edit the file /etc/audit/auditd.conf. Add or modify the following line, substituting ACTION appropriately:

disk_full_action = ACTION
Set this value to single to cause the system to switch to single-user mode for corrective action. Acceptable values also include syslog, single, and halt. For certain systems, the need for availability outweighs the need to log all actions, and a different setting should be determined. Details regarding all possible values for ACTION are described in the auditd.conf man page.

Rationale:

Taking appropriate action in case of a filled audit storage volume will minimize the possibility of losing audit records.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then


var_auditd_disk_full_action="single"
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
  # Otherwise, regular sed command will do.
  sed_command=('sed' '-i')
  if test -L "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="${cce}"
  else
    cce="CCE"
  fi

  # Strip any search characters in the key arg so that the key can be replaced without
  # adding any search characters to the config file.
  stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$value"

  # If the key exists, change it. Otherwise, add it to the config_file.
  # We search for the key string followed by a word boundary (matched by \>),
  # so if we search for 'setting', 'setting2' won't match.
  if LC_ALL=C grep -q -m 1 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}
replace_or_append /etc/audit/auditd.conf '^disk_full_action' "$var_auditd_disk_full_action" "CCE-83032-3"

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: XCCDF Value var_auditd_disk_full_action # promote to variable
  set_fact:
    var_auditd_disk_full_action: !!str single
  tags:
    - always

- name: Configure auditd Disk Full Action when Disk Space Is Full
  lineinfile:
    dest: /etc/audit/auditd.conf
    line: disk_full_action = {{ var_auditd_disk_full_action }}
    regexp: ^\s*disk_full_action\s*=\s*.*$
    state: present
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83032-3
    - DISA-STIG-SLES-12-020060
    - NIST-800-53-AU-5(b)
    - NIST-800-53-AU-5.1(iv)
    - auditd_data_disk_full_action
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Configure auditd space_left on Low Disk Spacerule

The auditd service can be configured to take an action when disk space is running low but prior to running out of space completely. Edit the file /etc/audit/auditd.conf. Add or modify the following line, substituting SIZE_in_MB appropriately:

space_left = SIZE_in_MB
Set this value to the appropriate size in Megabytes cause the system to notify the user of an issue.

Rationale:

Notifying administrators of an impending disk space problem may allow them to take corrective action prior to any disruption.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then


var_auditd_space_left="100"



grep -q "^space_left[[:space:]]*=.*$" /etc/audit/auditd.conf && \
  sed -i "s/^space_left[[:space:]]*=.*$/space_left = $var_auditd_space_left/g" /etc/audit/auditd.conf || \
  echo "space_left = $var_auditd_space_left" >> /etc/audit/auditd.conf

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: XCCDF Value var_auditd_space_left # promote to variable
  set_fact:
    var_auditd_space_left: !!str 100
  tags:
    - always

- name: Configure auditd space_left on Low Disk Space
  lineinfile:
    dest: /etc/audit/auditd.conf
    line: space_left = {{ var_auditd_space_left }}
    regexp: ^\s*space_left\s*=\s*.*$
    state: present
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83026-5
    - DISA-STIG-SLES-12-020030
    - NIST-800-53-AU-5(1)
    - PCI-DSS-Req-10.7
    - auditd_data_retention_space_left
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Configure a Sufficiently Large Partition for Audit Logsrule

The SUSE operating system must allocate audit record storage capacity to store at least one weeks worth of audit records when audit records are not immediately sent to a central audit record storage facility. The partition size needed to capture a week's worth of audit records is based on the activity level of the system and the total storage capacity available. In normal circumstances, 10.0 GB of storage space for audit records will be sufficient. Determine which partition the audit records are being written to with the following command:

# grep log_file /etc/audit/auditd.conf
log_file = /var/log/audit/audit.log
Check the size of the partition that audit records are written to with the following command:
# df -h /var/log/audit/
/dev/sda2 24G 10.4G 13.6G 43% /var/log/audit

Rationale:

Information stored in one location is vulnerable to accidental or incidental deletion or alteration.Off-loading is a common process in information systems with limited audit storage capacity.

Configure auditd mail_acct Action on Low Disk Spacerule

The auditd service can be configured to send email to a designated account in certain situations. Add or correct the following line in /etc/audit/auditd.conf to ensure that administrators are notified via email for those situations:

action_mail_acct = root

Rationale:

Email sent to the root account is typically aliased to the administrators of the system, who can take appropriate action.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then


var_auditd_action_mail_acct="root"



AUDITCONFIG=/etc/audit/auditd.conf
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
  # Otherwise, regular sed command will do.
  sed_command=('sed' '-i')
  if test -L "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="${cce}"
  else
    cce="CCE"
  fi

  # Strip any search characters in the key arg so that the key can be replaced without
  # adding any search characters to the config file.
  stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$value"

  # If the key exists, change it. Otherwise, add it to the config_file.
  # We search for the key string followed by a word boundary (matched by \>),
  # so if we search for 'setting', 'setting2' won't match.
  if LC_ALL=C grep -q -m 1 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}
replace_or_append $AUDITCONFIG '^action_mail_acct' "$var_auditd_action_mail_acct" "CCE-83030-7"

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: XCCDF Value var_auditd_action_mail_acct # promote to variable
  set_fact:
    var_auditd_action_mail_acct: !!str root
  tags:
    - always

- name: Configure auditd mail_acct Action on Low Disk Space
  lineinfile:
    dest: /etc/audit/auditd.conf
    line: action_mail_acct = {{ var_auditd_action_mail_acct }}
    state: present
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83030-7
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020040
    - NIST-800-171-3.3.1
    - NIST-800-53-AU-5(a)
    - NIST-800-53-AU-5.1(ii)
    - PCI-DSS-Req-10.7.a
    - auditd_data_retention_action_mail_acct
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Configure audispd's Plugin disk_full_action When Disk Is Fullrule

Configure the action the operating system takes if the disk the audit records are written to becomes full. Edit the file /etc/audisp/audisp-remote.conf. Add or modify the following line, substituting ACTION appropriately:

disk_full_action = ACTION
Set this value to single to cause the system to switch to single user mode for corrective action. Acceptable values also include syslog and halt. For certain systems, the need for availability outweighs the need to log all actions, and a different setting should be determined.

Rationale:

Taking appropriate action in case of a filled audit storage volume will minimize the possibility of losing audit records.

Encrypt Audit Records Sent With audispd Pluginrule

Configure the operating system to encrypt the transfer of off-loaded audit records onto a different system or media from the system being audited. Uncomment the enable_krb5 option in

/etc/audisp/audisp-remote.conf
, and set it with the following line:
enable_krb5 = yes

Rationale:

Information stored in one location is vulnerable to accidental or incidental deletion or alteration. Off-loading is a common process in information systems with limited audit storage capacity.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then




AUDISP_REMOTE_CONFIG="/etc/audisp/audisp-remote.conf"
option="^enable_krb5"
value="yes"
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
  # Otherwise, regular sed command will do.
  sed_command=('sed' '-i')
  if test -L "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="${cce}"
  else
    cce="CCE"
  fi

  # Strip any search characters in the key arg so that the key can be replaced without
  # adding any search characters to the config file.
  stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$value"

  # If the key exists, change it. Otherwise, add it to the config_file.
  # We search for the key string followed by a word boundary (matched by \>),
  # so if we search for 'setting', 'setting2' won't match.
  if LC_ALL=C grep -q -m 1 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}
replace_or_append $AUDISP_REMOTE_CONFIG "$option" "$value" "CCE-83063-8"

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Configure Kerberos 5 Encryption in Audit Event Multiplexor (audispd)
  lineinfile:
    dest: /etc/audisp/audisp-remote.conf
    line: enable_krb5 = yes
    regexp: ^\s*enable_krb5\s*=\s*.*$
    state: present
    mode: 416
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83063-8
    - DISA-STIG-SLES-12-020080
    - NIST-800-53-AU-9(3)
    - NIST-800-53-CM-6(a)
    - auditd_audispd_encrypt_sent_records
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

Configure audispd's Plugin network_failure_action On Network Failurerule

Configure the action the operating system takes if there is an error sending audit records to a remote system. Edit the file /etc/audisp/audisp-remote.conf. Add or modify the following line, substituting ACTION appropriately:

network_failure_action = ACTION
Set this value to single to cause the system to switch to single user mode for corrective action. Acceptable values also include syslog and halt. For certain systems, the need for availability outweighs the need to log all actions, and a different setting should be determined. This profile configures the action to be single.

Rationale:

Taking appropriate action when there is an error sending audit records to a remote system will minimize the possibility of losing audit records.

Ensure the default plugins for the audit dispatcher are Installedrule

The audit-audispd-plugins package should be installed.

Rationale:

Information stored in one location is vulnerable to accidental or incidental deletion or alteration. Off-loading is a common process in information systems with limited audit storage capacity.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

zypper install -y "audit-audispd-plugins"

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Ensure audit-audispd-plugins is installed
  package:
    name: audit-audispd-plugins
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83033-1
    - DISA-STIG-SLES-12-020070
    - NIST-800-53-AU-4(1)
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_audit-audispd-plugins_installed
Remediation script:
include install_audit-audispd-plugins

class install_audit-audispd-plugins {
  package { 'audit-audispd-plugins':
    ensure => 'installed',
  }
}
Remediation script:

[[packages]]
name = "audit-audispd-plugins"
version = "*"

Ensure the audit Subsystem is Installedrule

The audit package should be installed.

Rationale:

The auditd service is an access monitoring and accounting daemon, watching system calls to audit any access, in comparison with potential local access control policy such as SELinux policy.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

zypper install -y "audit"

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Ensure audit is installed
  package:
    name: audit
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83023-2
    - DISA-STIG-SLES-12-020000
    - NIST-800-53-AU-12(3)
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-12.1(iv)
    - NIST-800-53-AU-7(a)
    - NIST-800-53-AU-7(b)
    - NIST-800-53-AU-8(b)
    - NIST-800-53-CM-5(1)
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_audit_installed
Remediation script:
include install_audit

class install_audit {
  package { 'audit':
    ensure => 'installed',
  }
}
Remediation script:

[[packages]]
name = "audit"
version = "*"

Enable auditd Servicerule

The auditd service is an essential userspace component of the Linux Auditing System, as it is responsible for writing audit records to disk. The auditd service can be enabled with the following command:

$ sudo systemctl enable auditd.service

Rationale:

Without establishing what type of events occurred, it would be difficult to establish, correlate, and investigate the events leading up to an outage or attack. Ensuring the auditd service is active ensures audit records generated by the kernel are appropriately recorded.

Additionally, a properly configured audit subsystem ensures that actions of individual system users can be uniquely traced to those users so they can be held accountable for their actions.

identifiers:  CCE-83024-0

references:  1, 11, 12, 13, 14, 15, 16, 19, 2, 3, 4, 5, 6, 7, 8, 9, 5.4.1.1, APO10.01, APO10.03, APO10.04, APO10.05, APO11.04, APO12.06, APO13.01, BAI03.05, BAI08.02, DSS01.03, DSS01.04, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS03.05, DSS05.02, DSS05.03, DSS05.04, DSS05.05, DSS05.07, MEA01.01, MEA01.02, MEA01.03, MEA01.04, MEA01.05, MEA02.01, 3.3.1, 3.3.2, 3.3.6, CCI-000126, CCI-000130, CCI-000131, CCI-000132, CCI-000133, CCI-000134, CCI-000135, CCI-000154, CCI-000158, CCI-000366, CCI-001464, CCI-001487, CCI-001814, CCI-001876, CCI-002884, CCI-000169, 164.308(a)(1)(ii)(D), 164.308(a)(5)(ii)(C), 164.310(a)(2)(iv), 164.310(d)(2)(iii), 164.312(b), 4.2.3.10, 4.3.2.6.7, 4.3.3.3.9, 4.3.3.5.8, 4.3.3.6.6, 4.3.4.4.7, 4.3.4.5.6, 4.3.4.5.7, 4.3.4.5.8, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 1.13, SR 2.10, SR 2.11, SR 2.12, SR 2.6, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 6.1, SR 6.2, SR 7.1, SR 7.6, A.11.2.6, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.7, A.15.2.1, A.15.2.2, A.16.1.4, A.16.1.5, A.16.1.7, A.6.2.1, A.6.2.2, AU-3, AU-3(1), AU-3(1).1(ii), AU-3.1, AU-6(4), AU-6(4).1, AU-7(1), AU-7(1).1, AU-7(a), AU-14(1), AU-14(1).1, CM-6(b), CM-6.1(iv), MA-4(1)(a), DE.AE-3, DE.AE-5, DE.CM-1, DE.CM-3, DE.CM-7, ID.SC-4, PR.AC-3, PR.PT-1, PR.PT-4, RS.AN-1, RS.AN-4, Req-10.1, SRG-OS-000037-GPOS-00015, SRG-OS-000038-GPOS-00016, SRG-OS-000039-GPOS-00017, SRG-OS-000040-GPOS-00018, SRG-OS-000041-GPOS-00019, SRG-OS-000042-GPOS-00021, SRG-OS-000051-GPOS-00024, SRG-OS-000054-GPOS-00025, SRG-OS-000122-GPOS-00063, SRG-OS-000254-GPOS-00095, SRG-OS-000255-GPOS-00096, SRG-OS-000365-GPOS-00152, SRG-OS-000392-GPOS-00172, SRG-OS-000480-GPOS-00227, SRG-OS-000062-GPOS-00031, SLES-12-020010, SV-217191r603262_rule, SRG-OS-000037-VMM-000150, SRG-OS-000063-VMM-000310, SRG-OS-000038-VMM-000160, SRG-OS-000039-VMM-000170, SRG-OS-000040-VMM-000180, SRG-OS-000041-VMM-000190

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

SYSTEMCTL_EXEC='/usr/bin/systemctl'
"$SYSTEMCTL_EXEC" unmask 'auditd.service'
"$SYSTEMCTL_EXEC" start 'auditd.service'
"$SYSTEMCTL_EXEC" enable 'auditd.service'

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Enable service auditd
  block:

    - name: Gather the package facts
      package_facts:
        manager: auto

    - name: Enable service auditd
      service:
        name: auditd
        enabled: 'yes'
        state: started
        masked: 'no'
      when:
        - '"audit" in ansible_facts.packages'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83024-0
    - CJIS-5.4.1.1
    - DISA-STIG-SLES-12-020010
    - NIST-800-171-3.3.1
    - NIST-800-171-3.3.2
    - NIST-800-171-3.3.6
    - NIST-800-53-AU-14(1)
    - NIST-800-53-AU-14(1).1
    - NIST-800-53-AU-3
    - NIST-800-53-AU-3(1)
    - NIST-800-53-AU-3(1).1(ii)
    - NIST-800-53-AU-3.1
    - NIST-800-53-AU-6(4)
    - NIST-800-53-AU-6(4).1
    - NIST-800-53-AU-7(1)
    - NIST-800-53-AU-7(1).1
    - NIST-800-53-AU-7(a)
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1(iv)
    - NIST-800-53-MA-4(1)(a)
    - PCI-DSS-Req-10.1
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_auditd_enabled
Remediation script:
include enable_auditd

class enable_auditd {
  service {'auditd':
    enable => true,
    ensure => 'running',
  }
}

Network Configuration and Firewallsgroup

Most systems must be connected to a network of some sort, and this brings with it the substantial risk of network attack. This section discusses the security impact of decisions about networking which must be made when configuring a system.

This section also discusses firewalls, network access controls, and other network security frameworks, which allow system-level rules to be written that can limit an attackers' ability to connect to your system. These rules can specify that network traffic should be allowed or denied from certain IP addresses, hosts, and networks. The rules can also specify which of the system's network services are available to particular hosts or networks.

contains 17 rules

Wireless Networkinggroup

Wireless networking, such as 802.11 (WiFi) and Bluetooth, can present a security risk to sensitive or classified systems and networks. Wireless networking hardware is much more likely to be included in laptop or portable systems than in desktops or servers.

Removal of hardware provides the greatest assurance that the wireless capability remains disabled. Acquisition policies often include provisions to prevent the purchase of equipment that will be used in sensitive spaces and includes wireless capabilities. If it is impractical to remove the wireless hardware, and policy permits the device to enter sensitive spaces as long as wireless is disabled, efforts should instead focus on disabling wireless capability via software.

contains 1 rule

Disable Wireless Through Software Configurationgroup

If it is impossible to remove the wireless hardware from the device in question, disable as much of it as possible through software. The following methods can disable software support for wireless networking, but note that these methods do not prevent malicious software or careless users from re-activating the devices.

contains 1 rule

Deactivate Wireless Network Interfacesrule

Deactivating wireless network interfaces should prevent normal usage of the wireless capability.

Configure the system to disable wireless network interfaces by issuing the following command for every active <WIFI-INTERFACE> in the system:

$ sudo wicked ifdown <WIFI-INTERFACE>
Also remove the configuration files for every wifi adapter from /etc/wicked/ifconfig/<WIFI-INTERFACE>.xml to prevent future connections.

Rationale:

The use of wireless networking can introduce many different attack vectors into the organization's network. Common attack vectors such as malicious association and ad hoc networks will allow an attacker to spoof a wireless access point (AP), allowing validated systems to connect to the malicious AP and enabling the attacker to monitor and record network traffic. These malicious APs can also serve to create a man-in-the-middle attack or be used to create a denial of service to valid network resources.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

nmcli radio wifi off

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Deactivate Wireless Network Interfaces
  command: nmcli radio wifi off
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83148-7
    - DISA-STIG-SLES-12-030450
    - NIST-800-171-3.1.16
    - NIST-800-53-AC-18(1)
    - NIST-800-53-SC-8
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy
    - wireless_disable_interfaces

IPv6group

The system includes support for Internet Protocol version 6. A major and often-mentioned improvement over IPv4 is its enormous increase in the number of available addresses. Another important feature is its support for automatic configuration of many network settings.

contains 2 rules

Configure IPv6 Settings if Necessarygroup

A major feature of IPv6 is the extent to which systems implementing it can automatically configure their networking devices using information from the network. From a security perspective, manually configuring important configuration information is preferable to accepting it from the network in an unauthenticated fashion.

contains 2 rules

Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfacesrule

To set the runtime status of the net.ipv6.conf.default.accept_redirects kernel parameter, run the following command:

$ sudo sysctl -w net.ipv6.conf.default.accept_redirects=0
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
net.ipv6.conf.default.accept_redirects = 0

Rationale:

An illicit ICMP redirect message could result in a man-in-the-middle attack.

Remediation script:
- name: XCCDF Value sysctl_net_ipv6_conf_default_accept_redirects_value # promote to variable
  set_fact:
    sysctl_net_ipv6_conf_default_accept_redirects_value: !!str 0
  tags:
    - always

- name: Ensure sysctl net.ipv6.conf.default.accept_redirects is set
  sysctl:
    name: net.ipv6.conf.default.accept_redirects
    value: '{{ sysctl_net_ipv6_conf_default_accept_redirects_value }}'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83223-8
    - DISA-STIG-SLES-12-030401
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1(iv)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_net_ipv6_conf_default_accept_redirects

Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfacesrule

To set the runtime status of the net.ipv6.conf.all.accept_source_route kernel parameter, run the following command:

$ sudo sysctl -w net.ipv6.conf.all.accept_source_route=0
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
net.ipv6.conf.all.accept_source_route = 0

Rationale:

Source-routed packets allow the source of the packet to suggest routers forward the packet along a different path than configured on the router, which can be used to bypass network security measures. This requirement applies only to the forwarding of source-routerd traffic, such as when IPv6 forwarding is enabled and the system is functioning as a router.

Accepting source-routed packets in the IPv6 protocol has few legitimate uses. It should be disabled unless it is absolutely required.

Remediation script:
- name: XCCDF Value sysctl_net_ipv6_conf_all_accept_source_route_value # promote to variable
  set_fact:
    sysctl_net_ipv6_conf_all_accept_source_route_value: !!str 0
  tags:
    - always

- name: Ensure sysctl net.ipv6.conf.all.accept_source_route is set
  sysctl:
    name: net.ipv6.conf.all.accept_source_route
    value: '{{ sysctl_net_ipv6_conf_all_accept_source_route_value }}'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83078-6
    - DISA-STIG-SLES-12-030361
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_net_ipv6_conf_all_accept_source_route

Kernel Parameters Which Affect Networkinggroup

The sysctl utility is used to set parameters which affect the operation of the Linux kernel. Kernel parameters which affect networking and have security implications are described here.

contains 9 rules

Network Related Kernel Runtime Parameters for Hosts and Routersgroup

Certain kernel parameters should be set for systems which are acting as either hosts or routers to improve the system's ability defend against certain types of IPv4 protocol attacks.

contains 6 rules

Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces by Defaultrule

To set the runtime status of the net.ipv4.conf.default.accept_source_route kernel parameter, run the following command:

$ sudo sysctl -w net.ipv4.conf.default.accept_source_route=0
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
net.ipv4.conf.default.accept_source_route = 0

Rationale:

Source-routed packets allow the source of the packet to suggest routers forward the packet along a different path than configured on the router, which can be used to bypass network security measures.
Accepting source-routed packets in the IPv4 protocol has few legitimate uses. It should be disabled unless it is absolutely required, such as when IPv4 forwarding is enabled and the system is legitimately functioning as a router.

Remediation script:
- name: XCCDF Value sysctl_net_ipv4_conf_default_accept_source_route_value # promote to variable
  set_fact:
    sysctl_net_ipv4_conf_default_accept_source_route_value: !!str 0
  tags:
    - always

- name: Ensure sysctl net.ipv4.conf.default.accept_source_route is set
  sysctl:
    name: net.ipv4.conf.default.accept_source_route
    value: '{{ sysctl_net_ipv4_conf_default_accept_source_route_value }}'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83079-4
    - CJIS-5.10.1.1
    - DISA-STIG-SLES-12-030370
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-SC-5
    - NIST-800-53-SC-7(a)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_net_ipv4_conf_default_accept_source_route

Enable Kernel Parameter to Use TCP Syncookies on IPv4 Interfacesrule

To set the runtime status of the net.ipv4.tcp_syncookies kernel parameter, run the following command:

$ sudo sysctl -w net.ipv4.tcp_syncookies=1
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
net.ipv4.tcp_syncookies = 1

Rationale:

A TCP SYN flood attack can cause a denial of service by filling a system's TCP connection table with connections in the SYN_RCVD state. Syncookies can be used to track a connection when a subsequent ACK is received, verifying the initiator is attempting a valid connection and is not a flood source. This feature is activated when a flood condition is detected, and enables the system to continue servicing valid connection requests.

Remediation script:
- name: XCCDF Value sysctl_net_ipv4_tcp_syncookies_value # promote to variable
  set_fact:
    sysctl_net_ipv4_tcp_syncookies_value: !!str 1
  tags:
    - always

- name: Ensure sysctl net.ipv4.tcp_syncookies is set
  sysctl:
    name: net.ipv4.tcp_syncookies
    value: '{{ sysctl_net_ipv4_tcp_syncookies_value }}'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83179-2
    - CJIS-5.10.1.1
    - DISA-STIG-SLES-12-030350
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-SC-5(1)
    - NIST-800-53-SC-5(2)
    - NIST-800-53-SC-5(3)(a)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_net_ipv4_tcp_syncookies

Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfacesrule

To set the runtime status of the net.ipv4.conf.all.accept_source_route kernel parameter, run the following command:

$ sudo sysctl -w net.ipv4.conf.all.accept_source_route=0
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
net.ipv4.conf.all.accept_source_route = 0

Rationale:

Source-routed packets allow the source of the packet to suggest routers forward the packet along a different path than configured on the router, which can be used to bypass network security measures. This requirement applies only to the forwarding of source-routerd traffic, such as when IPv4 forwarding is enabled and the system is functioning as a router.

Accepting source-routed packets in the IPv4 protocol has few legitimate uses. It should be disabled unless it is absolutely required.

Remediation script:
- name: XCCDF Value sysctl_net_ipv4_conf_all_accept_source_route_value # promote to variable
  set_fact:
    sysctl_net_ipv4_conf_all_accept_source_route_value: !!str 0
  tags:
    - always

- name: Ensure sysctl net.ipv4.conf.all.accept_source_route is set
  sysctl:
    name: net.ipv4.conf.all.accept_source_route
    value: '{{ sysctl_net_ipv4_conf_all_accept_source_route_value }}'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83064-6
    - DISA-STIG-SLES-12-030360
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-SC-5
    - NIST-800-53-SC-7(a)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_net_ipv4_conf_all_accept_source_route

Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfacesrule

To set the runtime status of the net.ipv4.icmp_echo_ignore_broadcasts kernel parameter, run the following command:

$ sudo sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
net.ipv4.icmp_echo_ignore_broadcasts = 1

Rationale:

Responding to broadcast (ICMP) echoes facilitates network mapping and provides a vector for amplification attacks.
Ignoring ICMP echo requests (pings) sent to broadcast or multicast addresses makes the system slightly more difficult to enumerate on the network.

Remediation script:
- name: XCCDF Value sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value # promote to variable
  set_fact:
    sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value: !!str 1
  tags:
    - always

- name: Ensure sysctl net.ipv4.icmp_echo_ignore_broadcasts is set
  sysctl:
    name: net.ipv4.icmp_echo_ignore_broadcasts
    value: '{{ sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value }}'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83080-2
    - CJIS-5.10.1.1
    - DISA-STIG-SLES-12-030380
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-SC-5
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_net_ipv4_icmp_echo_ignore_broadcasts

Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfacesrule

To set the runtime status of the net.ipv4.conf.default.accept_redirects kernel parameter, run the following command:

$ sudo sysctl -w net.ipv4.conf.default.accept_redirects=0
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
net.ipv4.conf.default.accept_redirects = 0

Rationale:

ICMP redirect messages are used by routers to inform hosts that a more direct route exists for a particular destination. These messages modify the host's route table and are unauthenticated. An illicit ICMP redirect message could result in a man-in-the-middle attack.
This feature of the IPv4 protocol has few legitimate uses. It should be disabled unless absolutely required.

Remediation script:
- name: XCCDF Value sysctl_net_ipv4_conf_default_accept_redirects_value # promote to variable
  set_fact:
    sysctl_net_ipv4_conf_default_accept_redirects_value: !!str 0
  tags:
    - always

- name: Ensure sysctl net.ipv4.conf.default.accept_redirects is set
  sysctl:
    name: net.ipv4.conf.default.accept_redirects
    value: '{{ sysctl_net_ipv4_conf_default_accept_redirects_value }}'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83081-0
    - CJIS-5.10.1.1
    - DISA-STIG-SLES-12-030400
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-SC-7(a)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_net_ipv4_conf_default_accept_redirects

Disable Accepting ICMP Redirects for All IPv4 Interfacesrule

To set the runtime status of the net.ipv4.conf.all.accept_redirects kernel parameter, run the following command:

$ sudo sysctl -w net.ipv4.conf.all.accept_redirects=0
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
net.ipv4.conf.all.accept_redirects = 0

Rationale:

ICMP redirect messages are used by routers to inform hosts that a more direct route exists for a particular destination. These messages modify the host's route table and are unauthenticated. An illicit ICMP redirect message could result in a man-in-the-middle attack.
This feature of the IPv4 protocol has few legitimate uses. It should be disabled unless absolutely required."

Remediation script:
- name: XCCDF Value sysctl_net_ipv4_conf_all_accept_redirects_value # promote to variable
  set_fact:
    sysctl_net_ipv4_conf_all_accept_redirects_value: !!str 0
  tags:
    - always

- name: Ensure sysctl net.ipv4.conf.all.accept_redirects is set
  sysctl:
    name: net.ipv4.conf.all.accept_redirects
    value: '{{ sysctl_net_ipv4_conf_all_accept_redirects_value }}'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83090-1
    - CJIS-5.10.1.1
    - DISA-STIG-SLES-12-030390
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-SC-7(a)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_net_ipv4_conf_all_accept_redirects

Network Parameters for Hosts Onlygroup

If the system is not going to be used as a router, then setting certain kernel parameters ensure that the host will not perform routing of network traffic.

contains 3 rules

Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfacesrule

To set the runtime status of the net.ipv4.conf.all.send_redirects kernel parameter, run the following command:

$ sudo sysctl -w net.ipv4.conf.all.send_redirects=0
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
net.ipv4.conf.all.send_redirects = 0

Rationale:

ICMP redirect messages are used by routers to inform hosts that a more direct route exists for a particular destination. These messages contain information from the system's route table possibly revealing portions of the network topology.
The ability to send ICMP redirects is only appropriate for systems acting as routers.

Remediation script:
- name: Ensure sysctl net.ipv4.conf.all.send_redirects is set to 0
  sysctl:
    name: net.ipv4.conf.all.send_redirects
    value: '0'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83089-3
    - CJIS-5.10.1.1
    - DISA-STIG-SLES-12-030420
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-SC-5
    - NIST-800-53-SC-7(a)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_net_ipv4_conf_all_send_redirects

Disable Kernel Parameter for IP Forwarding on IPv4 Interfacesrule

To set the runtime status of the net.ipv4.ip_forward kernel parameter, run the following command:

$ sudo sysctl -w net.ipv4.ip_forward=0
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
net.ipv4.ip_forward = 0

warning  Certain technologies such as virtual machines, containers, etc. rely on IPv4 forwarding to enable and use networking. Disabling IPv4 forwarding would cause those technologies to stop working. Therefore, this rule should not be used in profiles or benchmarks that target usage of IPv4 forwarding.
Rationale:

Routing protocol daemons are typically used on routers to exchange network topology information with other routers. If this capability is used when not required, system network information may be unnecessarily transmitted across the network.

Remediation script:
- name: Ensure sysctl net.ipv4.ip_forward is set to 0
  sysctl:
    name: net.ipv4.ip_forward
    value: '0'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83088-5
    - DISA-STIG-SLES-12-030430
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-SC-5
    - NIST-800-53-SC-7(a)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_net_ipv4_ip_forward

Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces by Defaultrule

To set the runtime status of the net.ipv4.conf.default.send_redirects kernel parameter, run the following command:

$ sudo sysctl -w net.ipv4.conf.default.send_redirects=0
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
net.ipv4.conf.default.send_redirects = 0

Rationale:

ICMP redirect messages are used by routers to inform hosts that a more direct route exists for a particular destination. These messages contain information from the system's route table possibly revealing portions of the network topology.
The ability to send ICMP redirects is only appropriate for systems acting as routers.

Remediation script:
- name: Ensure sysctl net.ipv4.conf.default.send_redirects is set to 0
  sysctl:
    name: net.ipv4.conf.default.send_redirects
    value: '0'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83086-9
    - CJIS-5.10.1.1
    - DISA-STIG-SLES-12-030410
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-SC-5
    - NIST-800-53-SC-7(a)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_net_ipv4_conf_default_send_redirects

SuSEfirewall2group

The SuSEfirewall2 provides a managed firewall.

contains 4 rules

Install SuSEfirewall2 Packagerule

The SuSEfirewall2 package can be installed with the following command:

$ sudo zypper install SuSEfirewall2

Rationale:

The SuSEfirewall2 package should be installed to provide access control methods.

Remediation script:

zypper install -y "SuSEfirewall2"
Remediation script:
- name: Ensure SuSEfirewall2 is installed
  package:
    name: SuSEfirewall2
    state: present
  tags:
    - CCE-83157-8
    - DISA-STIG-SLES-12-030030
    - NIST-800-53-AC-17(1)
    - NIST-800-53-CA-3(5)
    - NIST-800-53-CM-7
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_SuSEfirewall2_installed
Remediation script:
include install_SuSEfirewall2

class install_SuSEfirewall2 {
  package { 'SuSEfirewall2':
    ensure => 'installed',
  }
}
Remediation script:

[[packages]]
name = "SuSEfirewall2"
version = "*"

Enable the SuSEfirewall 2rule

The SuSEfirewall2 service can be enabled with the following command:

$ sudo systemctl enable SuSEfirewall2.service

Rationale:

To prevent unauthorized connection of devices, unauthorized transfer of information, or unauthorized tunneling (i.e., embedding of data types within data types), organizations must disable or restrict unused or unnecessary physical and logical ports/protocols on information systems. SUSE operating systems are capable of providing a wide variety of functions and services. Some of the functions and services provided by default may not be necessary to support essential organizational operations. Additionally, it is sometimes convenient to provide multiple services from a single component (e.g., VPN and IPS); however, doing so increases risk over limiting the services provided by any one component.

Remediation script:

SYSTEMCTL_EXEC='/usr/bin/systemctl'
"$SYSTEMCTL_EXEC" unmask 'SuSEfirewall2.service'
"$SYSTEMCTL_EXEC" start 'SuSEfirewall2.service'
"$SYSTEMCTL_EXEC" enable 'SuSEfirewall2.service'
Remediation script:
- name: Enable service SuSEfirewall2
  block:

    - name: Gather the package facts
      package_facts:
        manager: auto

    - name: Enable service SuSEfirewall2
      service:
        name: SuSEfirewall2
        enabled: 'yes'
        state: started
        masked: 'no'
      when:
        - '"SuSEfirewall2" in ansible_facts.packages'
  tags:
    - CCE-83164-4
    - DISA-STIG-SLES-12-030030
    - NIST-800-53-AC-17(1)
    - NIST-800-53-CA-3(5)
    - NIST-800-53-CM-7
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_SuSEfirewall2_enabled
Remediation script:
include enable_SuSEfirewall2

class enable_SuSEfirewall2 {
  service {'SuSEfirewall2':
    enable => true,
    ensure => 'running',
  }
}

Enable DoS Protections in SuSEfirewall2rule

The SuSEfirewall2 package can be installed with the following command:

$ sudo zypper install SuSEfirewall2
The SuSEfirewall2 service can be enabled with the following command:
$ sudo systemctl enable SuSEfirewall2.service
Verify "SuSEfirewall2" is configured to protect the SUSE operating system against or limit the effects of DoS attacks. Run the following command:
# grep -i fw_services_accept_ext /etc/sysconfig/SuSEfirewall2
FW_SERVICES_ACCEPT_EXT="0/0,tcp,22,,hitcount=3,blockseconds=60,recentname=ssh"
If the "FW_SERVICES_ACCEPT_EXT" rule does not contain both the hitcount and blockseconds parameters, this is a finding.

Rationale:

DoS is a condition when a resource is not available for legitimate users. When this occurs, the organization either cannot accomplish its mission or must operate at degraded capacity. This requirement addresses the configuration of the SUSE operating system to mitigate the impact on system availability of DoS attacks that have occurred or are ongoing. For each system, known and potential DoS attacks must be identified and solutions for each type implemented. A variety of technologies exist to limit or, in some cases, eliminate the effects of DoS attacks (e.g., limiting processes or establishing memory partitions). Employing increased capacity and bandwidth, combined with service redundancy, may reduce the susceptibility to some DoS attacks.

Only Allow Authorized Network Services in SuSEfirewall2rule

The SuSEfirewall2 package can be installed with the following command:

$ sudo zypper install SuSEfirewall2
The SuSEfirewall2 service can be enabled with the following command:
$ sudo systemctl enable SuSEfirewall2.service
Check the firewall configuration for any unnecessary or prohibited functions, ports, protocols, and/or services by running the following command:
# grep ^FW_ /etc/sysconfig/SuSEfirewall2
FW_SERVICES_ACCEPT_EXT="0/0,tcp,22,,hitcount=3,blockseconds=60,recentname=ssh"
Ask the System Administrator for the site or program PPSM Component Local Services Assessment (Component Local Services Assessment (CLSA). Verify the services allowed by the firewall match the PPSM CLSA.

Rationale:

To prevent unauthorized connection of devices, unauthorized transfer of information, or unauthorized tunneling (i.e., embedding of data types within data types), organizations must disable or restrict unused or unnecessary physical and logical ports/protocols on information systems. SUSE operating systems are capable of providing a wide variety of functions and services. Some of the functions and services provided by default may not be necessary to support essential organizational operations. Additionally, it is sometimes convenient to provide multiple services from a single component (e.g., VPN and IPS); however, doing so increases risk over limiting the services provided by any one component. To support the requirements and principles of least functionality, the SUSE operating system must support the organizational requirements, providing only essential capabilities and limiting the use of ports, protocols, and/or services to only those required, authorized, and approved to conduct official business or address authorized quality-of-life issues.

Ensure System is Not Acting as a Network Snifferrule

The system should not be acting as a network sniffer, which can capture all traffic on the network to which it is connected. Run the following to determine if any interface is running in promiscuous mode:

$ ip link | grep PROMISC
Promiscuous mode of an interface can be disabled with the following command:
$ sudo ip link set dev device_name multicast off promisc off

Rationale:

Network interfaces in promiscuous mode allow for the capture of all network traffic visible to the system. If unauthorized individuals can access these applications, it may allow them to collect information such as logon IDs, passwords, and key exchanges between systems.

If the system is being used to perform a network troubleshooting function, the use of these tools must be documented with the Information Systems Security Manager (ISSM) and restricted to only authorized personnel.

File Permissions and Masksgroup

Traditional Unix security relies heavily on file and directory permissions to prevent unauthorized users from reading or modifying files to which they should not have access.

Several of the commands in this section search filesystems for files or directories with certain characteristics, and are intended to be run on every local partition on a given system. When the variable PART appears in one of the commands below, it means that the command is intended to be run repeatedly, with the name of each local partition substituted for PART in turn.

The following command prints a list of all xfs partitions on the local system, which is the default filesystem for SUSE Linux Enterprise 12 installations:

$ mount -t xfs | awk '{print $3}'
For any systems that use a different local filesystem type, modify this command as appropriate.

contains 15 rules

Restrict Partition Mount Optionsgroup

System partitions can be mounted with certain options that limit what files on those partitions can do. These options are set in the /etc/fstab configuration file, and can be used to make certain types of malicious behavior more difficult.

contains 2 rules

Add nosuid Option to Removable Media Partitionsrule

The nosuid mount option prevents set-user-identifier (SUID) and set-group-identifier (SGID) permissions from taking effect. These permissions allow users to execute binaries with the same permissions as the owner and group of the file respectively. Users should not be allowed to introduce SUID and SGID files into the system via partitions mounted from removeable media. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of any removable media partitions.

Rationale:

The presence of SUID and SGID executables should be tightly controlled. Allowing users to introduce SUID or SGID binaries from partitions mounted off of removable media would allow them to introduce their own highly-privileged programs.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then


var_removable_partition="/dev/cdrom"



device_regex="^\s*$var_removable_partition\s\+"
mount_option="nosuid"

if grep -q $device_regex /etc/fstab ; then
    previous_opts=$(grep $device_regex /etc/fstab | awk '{print $4}')
    sed -i "s|\($device_regex.*$previous_opts\)|\1,$mount_option|" /etc/fstab
else
    echo "Not remediating, because there is no record of $var_removable_partition in /etc/fstab" >&2
    return 1
fi

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: XCCDF Value var_removable_partition # promote to variable
  set_fact:
    var_removable_partition: !!str /dev/cdrom
  tags:
    - always

- name: Ensure permission nosuid are set on var_removable_partition
  lineinfile:
    path: /etc/fstab
    regexp: ^\s*({{ var_removable_partition }})\s+([^\s]*)\s+([^\s]*)\s+([^\s]*)(.*)$
    backrefs: true
    line: \1 \2 \3 \4,nosuid \5
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83101-6
    - DISA-STIG-SLES-12-010800
    - NIST-800-53-AC-6
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-MP-7
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_nosuid_removable_partitions
    - no_reboot_needed

Add nosuid Option to /homerule

The nosuid mount option can be used to prevent execution of setuid programs in /home. The SUID and SGID permissions should not be required in these user data directories. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of /home.

Rationale:

The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from user home directory partitions.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

function include_mount_options_functions {
	:
}

# $1: type of filesystem
# $2: new mount point option
# $3: filesystem of new mount point (used when adding new entry in fstab)
# $4: mount type of new mount point (used when adding new entry in fstab)
function ensure_mount_option_for_vfstype {
        local _vfstype="$1" _new_opt="$2" _filesystem=$3 _type=$4 _vfstype_points=()
        readarray -t _vfstype_points < <(grep -E "[[:space:]]${_vfstype}[[:space:]]" /etc/fstab | awk '{print $2}')

        for _vfstype_point in "${_vfstype_points[@]}"
        do
                ensure_mount_option_in_fstab "$_vfstype_point" "$_new_opt" "$_filesystem" "$_type"
        done
}

# $1: mount point
# $2: new mount point option
# $3: device or virtual string (used when adding new entry in fstab)
# $4: mount type of mount point (used when adding new entry in fstab)
function ensure_mount_option_in_fstab {
	local _mount_point="$1" _new_opt="$2" _device=$3 _type=$4
	local _mount_point_match_regexp="" _previous_mount_opts=""
	_mount_point_match_regexp="$(get_mount_point_regexp "$_mount_point")"

	if [ "$(grep -c "$_mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
		# runtime opts without some automatic kernel/userspace-added defaults
		_previous_mount_opts=$(grep "$_mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
					| sed -E "s/(rw|defaults|seclabel|${_new_opt})(,|$)//g;s/,$//")
		[ "$_previous_mount_opts" ] && _previous_mount_opts+=","
		echo "${_device} ${_mount_point} ${_type} defaults,${_previous_mount_opts}${_new_opt} 0 0" >> /etc/fstab
	elif [ "$(grep "$_mount_point_match_regexp" /etc/fstab | grep -c "$_new_opt")" -eq 0 ]; then
		_previous_mount_opts=$(grep "$_mount_point_match_regexp" /etc/fstab | awk '{print $4}')
		sed -i "s|\(${_mount_point_match_regexp}.*${_previous_mount_opts}\)|\1,${_new_opt}|" /etc/fstab
	fi
}

# $1: mount point
function get_mount_point_regexp {
		printf "[[:space:]]%s[[:space:]]" "$1"
}

# $1: mount point
function assert_mount_point_in_fstab {
	local _mount_point_match_regexp
	_mount_point_match_regexp="$(get_mount_point_regexp "$1")"
	grep "$_mount_point_match_regexp" -q /etc/fstab \
		|| { echo "The mount point '$1' is not even in /etc/fstab, so we can't set up mount options" >&2; return 1; }
}

# $1: mount point
function remove_defaults_from_fstab_if_overriden {
	local _mount_point_match_regexp
	_mount_point_match_regexp="$(get_mount_point_regexp "$1")"
	if grep "$_mount_point_match_regexp" /etc/fstab | grep -q "defaults,"
	then
		sed -i "s|\(${_mount_point_match_regexp}.*\)defaults,|\1|" /etc/fstab
	fi
}

# $1: mount point
function ensure_partition_is_mounted {
	local _mount_point="$1"
	mkdir -p "$_mount_point" || return 1
	if mountpoint -q "$_mount_point"; then
		mount -o remount --target "$_mount_point"
	else
		mount --target "$_mount_point"
	fi
}
include_mount_options_functions

function perform_remediation {
	# test "$mount_has_to_exist" = 'yes'
	if test "yes" = 'yes'; then
		assert_mount_point_in_fstab /home || { echo "Not remediating, because there is no record of /home in /etc/fstab" >&2; return 1; }
	fi

	ensure_mount_option_in_fstab "/home" "nosuid" "" ""

	ensure_partition_is_mounted "/home"
}

perform_remediation

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Check information associated to mountpoint
  command: findmnt --fstab '/home'
  register: device_name
  failed_when: device_name.rc > 1
  changed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83100-8
    - DISA-STIG-SLES-12-010790
    - NIST-800-53-AC-6
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-MP-7
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_home_nosuid
    - no_reboot_needed

- name: Create mount_info dictionary variable
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - '{{ device_name.stdout_lines[0].split() | list | lower }}'
    - '{{ device_name.stdout_lines[1].split() | list }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - device_name.stdout is defined and device_name.stdout_lines is defined
    - (device_name.stdout | length > 0)
  tags:
    - CCE-83100-8
    - DISA-STIG-SLES-12-010790
    - NIST-800-53-AC-6
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-MP-7
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_home_nosuid
    - no_reboot_needed

- name: If /home not mounted, craft mount_info manually
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - - target
      - source
      - fstype
      - options
    - - /home
      - ''
      - ''
      - defaults
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ("--fstab" | length == 0)
    - (device_name.stdout | length == 0)
  tags:
    - CCE-83100-8
    - DISA-STIG-SLES-12-010790
    - NIST-800-53-AC-6
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-MP-7
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_home_nosuid
    - no_reboot_needed

- name: Make sure nosuid option is part of the to /home options
  set_fact:
    mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nosuid''
      }) }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - mount_info is defined and "nosuid" not in mount_info.options
  tags:
    - CCE-83100-8
    - DISA-STIG-SLES-12-010790
    - NIST-800-53-AC-6
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-MP-7
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_home_nosuid
    - no_reboot_needed

- name: Ensure /home is mounted with nosuid option
  mount:
    path: /home
    src: '{{ mount_info.source }}'
    opts: '{{ mount_info.options }}'
    state: mounted
    fstype: '{{ mount_info.fstype }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - (device_name.stdout is defined and (device_name.stdout | length > 0)) or ("--fstab"
      | length == 0)
  tags:
    - CCE-83100-8
    - DISA-STIG-SLES-12-010790
    - NIST-800-53-AC-6
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-MP-7
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_home_nosuid
    - no_reboot_needed

Verify Permissions on Important Files and Directoriesgroup

Permissions for many files on a system must be set restrictively to ensure sensitive information is properly protected. This section discusses important permission restrictions which can be verified to ensure that no harmful discrepancies have arisen.

contains 5 rules
contains 1 rule

Verify Permissions and Ownership of Old Passwords Filerule

To properly set the owner of /etc/security/opasswd, run the command:

$ sudo chown root /etc/security/opasswd 
To properly set the group owner of /etc/security/opasswd, run the command:
$ sudo chgrp root /etc/security/opasswd
To properly set the permissions of /etc/security/opasswd, run the command:
$ sudo chmod 0600 /etc/security/opasswd

Rationale:

The /etc/security/opasswd file stores old passwords to prevent password reuse. Protection of this file is critical for system security.

Remediation script:
- name: Ensure /etc/security/opasswd exist and has the correct permissions
  file:
    path: /etc/security/opasswd
    owner: root
    group: root
    mode: 384
    state: touch
  tags:
    - CCE-83172-7
    - DISA-STIG-SLES-12-010300
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(1).1(v)
    - file_etc_security_opasswd
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Ensure All World-Writable Directories Are Group Owned by a System Accountrule

All directories in local partitions which are world-writable should be group owned by root or another system account. If any world-writable directories are not group owned by a system account, this should be investigated. Following this, the files should be deleted or assigned to an appropriate group.

Rationale:

Allowing a user account to group own a world-writable directory is undesirable because it allows the owner of that directory to remove or replace any files that may be placed in the directory by other users.

Verify that All World-Writable Directories Have Sticky Bits Setrule

When the so-called 'sticky bit' is set on a directory, only the owner of a given file may remove that file from the directory. Without the sticky bit, any user with write access to a directory may remove any file in the directory. Setting the sticky bit prevents users from removing each other's files. In cases where there is no reason for a directory to be world-writable, a better solution is to remove that permission rather than to set the sticky bit. However, if a directory is used by a particular application, consult that application's documentation instead of blindly changing modes.
To set the sticky bit on a world-writable directory DIR, run the following command:

$ sudo chmod +t DIR

Rationale:

Failing to set the sticky bit on public directories allows unauthorized users to delete files in the directory structure.

The only authorized public directories are those temporary directories supplied with the system, or those designed to be temporary file repositories. The setting is normally reserved for directories used by the system, by users for temporary file storage (such as /tmp), and for directories requiring global read/write access.

Remediation script:
df --local -P | awk '{if (NR!=1) print $6}' \
| xargs -I '{}' find '{}' -xdev -type d \
\( -perm -0002 -a ! -perm -1000 \) 2>/dev/null \
| xargs chmod a+t
Remediation script:
- name: Get all world-writable directories with no sticky bits set
  shell: |
    set -o pipefail
    df --local -P | awk '{if (NR!=1) print $6}' | xargs -I '{}' find '{}' -xdev -type d \( -perm -0002 -a ! -perm -1000 \) 2>/dev/null
  register: dir_output
  tags:
    - CCE-83047-1
    - DISA-STIG-SLES-12-010460
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - dir_perms_world_writable_sticky_bits
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: ensure sticky bit is set
  file:
    path: '{{ item }}'
    mode: a+t
  with_items:
    - '{{ dir_output.stdout_lines }}'
  tags:
    - CCE-83047-1
    - DISA-STIG-SLES-12-010460
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - dir_perms_world_writable_sticky_bits
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Ensure All Files Are Owned by a Userrule

If any files are not owned by a user, then the cause of their lack of ownership should be investigated. Following this, the files should be deleted or assigned to an appropriate user. The following command will discover and print any files on local partitions which do not belong to a valid user:

$ df --local -P | awk {'if (NR!=1) print $6'} | sudo xargs -I '{}' find '{}' -xdev -nouser
To search all filesystems on a system including network mounted filesystems the following command can be run manually for each partition:
$ sudo find PARTITION -xdev -nouser

warning  For this rule to evaluate centralized user accounts, getent must be working properly so that running the command
getent passwd
returns a list of all users in your organization. If using the System Security Services Daemon (SSSD),
enumerate = true
must be configured in your organization's domain to return a complete list of users
warning  Enabling this rule will result in slower scan times depending on the size of your organization and number of centralized users.
Rationale:

Unowned files do not directly imply a security problem, but they are generally a sign that something is amiss. They may be caused by an intruder, by incorrect software installation or draft software removal, or by failure to remove all files belonging to a deleted account. The files should be repaired so they will not cause problems when accounts are created in the future, and the cause should be discovered and addressed.

Ensure All Files Are Owned by a Grouprule

If any files are not owned by a group, then the cause of their lack of group-ownership should be investigated. Following this, the files should be deleted or assigned to an appropriate group. The following command will discover and print any files on local partitions which do not belong to a valid group:

$ df --local -P | awk '{if (NR!=1) print $6}' | sudo xargs -I '{}' find '{}' -xdev -nogroup
To search all filesystems on a system including network mounted filesystems the following command can be run manually for each partition:
$ sudo find PARTITION -xdev -nogroup

warning  This rule only considers local groups. If you have your groups defined outside /etc/group, the rule won't consider those.
Rationale:

Unowned files do not directly imply a security problem, but they are generally a sign that something is amiss. They may be caused by an intruder, by incorrect software installation or draft software removal, or by failure to remove all files belonging to a deleted account. The files should be repaired so they will not cause problems when accounts are created in the future, and the cause should be discovered and addressed.

Restrict Dynamic Mounting and Unmounting of Filesystemsgroup

Linux includes a number of facilities for the automated addition and removal of filesystems on a running system. These facilities may be necessary in many environments, but this capability also carries some risk -- whether direct risk from allowing users to introduce arbitrary filesystems, or risk that software flaws in the automated mount facility itself could allow an attacker to compromise the system.

This command can be used to list the types of filesystems that are available to the currently executing kernel:

$ find /lib/modules/`uname -r`/kernel/fs -type f -name '*.ko'
If these filesystems are not required then they can be explicitly disabled in a configuratio file in /etc/modprobe.d.

contains 2 rules

Disable the Automounterrule

The autofs daemon mounts and unmounts filesystems, such as user home directories shared via NFS, on demand. In addition, autofs can be used to handle removable media, and the default configuration provides the cdrom device as /misc/cd. However, this method of providing access to removable media is not common, so autofs can almost always be disabled if NFS is not in use. Even if NFS is required, it may be possible to configure filesystem mounts statically by editing /etc/fstab rather than relying on the automounter.

The autofs service can be disabled with the following command:

$ sudo systemctl mask --now autofs.service

Rationale:

Disabling the automounter permits the administrator to statically control filesystem mounting through /etc/fstab.

Additionally, automatically mounting filesystems permits easy introduction of unknown devices, thereby facilitating malicious activity.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

SYSTEMCTL_EXEC='/usr/bin/systemctl'
"$SYSTEMCTL_EXEC" stop 'autofs.service'
"$SYSTEMCTL_EXEC" disable 'autofs.service'
"$SYSTEMCTL_EXEC" mask 'autofs.service'
# Disable socket activation if we have a unit file for it
if "$SYSTEMCTL_EXEC" list-unit-files | grep -q '^autofs.socket'; then
    "$SYSTEMCTL_EXEC" stop 'autofs.socket'
    "$SYSTEMCTL_EXEC" mask 'autofs.socket'
fi
# The service may not be running because it has been started and failed,
# so let's reset the state so OVAL checks pass.
# Service should be 'inactive', not 'failed' after reboot though.
"$SYSTEMCTL_EXEC" reset-failed 'autofs.service' || true

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Disable service autofs
  block:

    - name: Gather the service facts
      service_facts: null

    - name: Disable service autofs
      systemd:
        name: autofs.service
        enabled: 'no'
        state: stopped
        masked: 'yes'
      when: '"autofs.service" in ansible_facts.services'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83070-3
    - DISA-STIG-SLES-12-010590
    - NIST-800-171-3.4.6
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-MP-7
    - disable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_autofs_disabled

- name: Unit Socket Exists - autofs.socket
  command: systemctl list-unit-files autofs.socket
  args:
    warn: false
  register: socket_file_exists
  changed_when: false
  ignore_errors: true
  check_mode: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83070-3
    - DISA-STIG-SLES-12-010590
    - NIST-800-171-3.4.6
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-MP-7
    - disable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_autofs_disabled

- name: Disable socket autofs
  systemd:
    name: autofs.socket
    enabled: 'no'
    state: stopped
    masked: 'yes'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"autofs.socket" in socket_file_exists.stdout_lines[1]'
  tags:
    - CCE-83070-3
    - DISA-STIG-SLES-12-010590
    - NIST-800-171-3.4.6
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-MP-7
    - disable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_autofs_disabled
Remediation script:
include disable_autofs

class disable_autofs {
  service {'autofs':
    enable => false,
    ensure => 'stopped',
  }
}

Disable Modprobe Loading of USB Storage Driverrule

To prevent USB storage devices from being used, configure the kernel module loading system to prevent automatic loading of the USB storage driver. To configure the system to prevent the usb-storage kernel module from being loaded, add the following line to a file in the directory /etc/modprobe.d:

install usb-storage /bin/true
This will prevent the modprobe program from loading the usb-storage module, but will not prevent an administrator (or another program) from using the insmod program to load the module manually.

Rationale:

USB storage devices such as thumb drives can be used to introduce malicious software.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if ! LC_ALL=C grep -q -m 1 "^blacklist usb-storage$" /etc/modprobe.d/50-blacklist.conf ; then
        echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/50-blacklist.conf
        echo "blacklist usb-storage" >> /etc/modprobe.d/50-blacklist.conf
fi

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Ensure kernel module 'usb-storage' is disabled
  lineinfile:
    create: true
    dest: /etc/modprobe.d/50-blacklist.conf
    regexp: ^blacklist usb-storage$
    line: blacklist usb-storage
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83069-5
    - DISA-STIG-SLES-12-010580
    - NIST-800-171-3.1.21
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-MP-7
    - disable_strategy
    - kernel_module_usb-storage_disabled
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required

Verify Permissions on Important Files and Directories Are Configured in /etc/permissions.localgroup

Permissions for many files on a system must be set restrictively to ensure sensitive information is properly protected. This section discusses the /etc/permissions.local file, where expected permissions can be configured to be checked and fixed through usage of the chkstat command.

contains 4 rules

Verify that local /var/log/messages is not world-readablerule

Files containing sensitive informations should be protected by restrictive permissions. Most of the time, there is no need that these files need to be read by any non-root user To properly set the permissions of /var/log/messages, run the command:

$ sudo chmod 0640 /var/log/messages
Check that "permissions.local" file contains the correct permissions rules with the following command:
# grep -i messages /etc/permissions.local

/var/log/messages root:root 640

Rationale:

The /var/log/messages file contains system error messages. Only authorized personnel should be aware of errors and the details of the errors. Error messages are an indicator of an organization's operational state or can identify the SUSE operating system or platform. Additionally, Personally Identifiable Information (PII) and operational information must not be revealed through error messages to unauthorized personnel or their designated representatives.

Remediation script:
- name: Configure permission for /var/log/messages
  lineinfile:
    path: /etc/permissions.local
    create: true
    regexp: ^\/var\/log\/messages\s+root.*
    line: /var/log/messages root:root 640
    state: present
  register: update_permissions_local_result
  tags:
    - CCE-83112-3
    - DISA-STIG-SLES-12-010890
    - NIST-800-53-SI-11(c)
    - configure_strategy
    - file_permissions_local_var_log_messages
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Correct file permissions after update /etc/permissions.local
  shell: |
    set -o pipefail chkstat --set --system
  when: update_permissions_local_result.changed
  tags:
    - CCE-83112-3
    - DISA-STIG-SLES-12-010890
    - NIST-800-53-SI-11(c)
    - configure_strategy
    - file_permissions_local_var_log_messages
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

Verify Permissions of Local Logs of audit Toolsrule

The SUSE operating system audit tools must have the proper permissions configured to protect against unauthorized access. Check that "permissions.local" file contains the correct permissions rules with the following command:

grep "^/usr/sbin/au" /etc/permissions.local

/usr/sbin/audispd root:root 0750
/usr/sbin/auditctl root:root 0750
/usr/sbin/auditd root:root 0750
/usr/sbin/ausearch root:root 0755
/usr/sbin/aureport root:root 0755
/usr/sbin/autrace root:root 0750
/usr/sbin/augenrules root:root 0750
Audit tools include but are not limited to vendor-provided and open-source audit tools needed to successfully view and manipulate audit information system activity and records. Audit tools include custom queries and report generators.

Rationale:

Protecting audit information also includes identifying and protecting the tools used to view and manipulate log data. Therefore, protecting audit tools is necessary to prevent unauthorized operation on audit information. SUSE operating systems providing tools to interface with audit information will leverage user permissions and roles identifying the user accessing the tools and the corresponding rights the user enjoys to make access decisions regarding the access to audit tools.

Verify that Local Logs of the audit Daemon are not World-Readablerule

Files containing sensitive informations should be protected by restrictive permissions. Most of the time, there is no need that these files need to bei read by any non-root user. Check that "permissions.local" file contains the correct permissions rules with the following command:

# grep -i audit /etc/permissions.local

/var/log/audit/ root:root 600
/var/log/audit/audit.log root:root 600
/etc/audit/audit.rules root:root 640
/etc/audit/rules.d/audit.rules root:root 640

Rationale:

Without the capability to restrict which roles and individuals can select which events are audited, unauthorized personnel may be able to prevent the auditing of critical events. Misconfigured audits may degrade the system's performance by overwhelming the audit log. Misconfigured audits may also make it more difficult to establish, correlate, and investigate the events relating to an incident or identify those responsible for one.

OS commands and libraries must have the proper permissions to protect from unauthorized accessrule

Verify that the SUSE operating system prevents unauthorized users from accessing system command and library files. Check that all of the audit information files and folders have the correct permissions with the following command:

# sudo chkstat --warn --system
Set the correct permissions with the following command:
# sudo chkstat --set --system

Rationale:

If the SUSE operating system were to allow any user to make changes to software libraries, those changes might be implemented without undergoing the appropriate testing and approvals that are part of a robust change management process. This requirement applies to SUSE operating systems with software libraries that are accessible and configurable, as in the case of interpreted languages. Software libraries also include privileged programs that execute with escalated privileges. Only qualified and authorized individuals must be allowed to obtain access to information system components to initiate changes, including upgrades and modifications.

identifiers:  CCE-83111-5

references:  CCI-001499, CM-5(6), SRG-OS-000259-GPOS-00100, SLES-12-010880

Restrict Programs from Dangerous Execution Patternsgroup

The recommendations in this section are designed to ensure that the system's features to protect against potentially dangerous program execution are activated. These protections are applied at the system initialization or kernel level, and defend against certain types of badly-configured or compromised programs.

contains 2 rules

Enable ExecShieldgroup

ExecShield describes kernel features that provide protection against exploitation of memory corruption errors such as buffer overflows. These features include random placement of the stack and other memory regions, prevention of execution in memory that should only hold data, and special handling of text buffers. These protections are enabled by default on 32-bit systems and controlled through sysctl variables kernel.exec-shield and kernel.randomize_va_space. On the latest 64-bit systems, kernel.exec-shield cannot be enabled or disabled with sysctl.

contains 2 rules

Restrict Exposed Kernel Pointer Addresses Accessrule

To set the runtime status of the kernel.kptr_restrict kernel parameter, run the following command:

$ sudo sysctl -w kernel.kptr_restrict=1
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
kernel.kptr_restrict = 1

Rationale:

Exposing kernel pointers (through procfs or seq_printf()) exposes kernel writeable structures that can contain functions pointers. If a write vulnereability occurs in the kernel allowing a write access to any of this structure, the kernel can be compromise. This option disallow any program withtout the CAP_SYSLOG capability from getting the kernel pointers addresses, replacing them with 0.

Remediation script:
- name: Ensure sysctl kernel.kptr_restrict is set to 1
  sysctl:
    name: kernel.kptr_restrict
    value: '1'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83125-5
    - DISA-STIG-SLES-12-030320
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SC-30
    - NIST-800-53-SC-30(2)
    - NIST-800-53-SC-30(5)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_kptr_restrict

Enable Randomized Layout of Virtual Address Spacerule

To set the runtime status of the kernel.randomize_va_space kernel parameter, run the following command:

$ sudo sysctl -w kernel.randomize_va_space=2
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
kernel.randomize_va_space = 2

Rationale:

Address space layout randomization (ASLR) makes it more difficult for an attacker to predict the location of attack code they have introduced into a process's address space during an attempt at exploitation. Additionally, ASLR makes it more difficult for an attacker to know the location of existing code in order to re-purpose it using return oriented programming (ROP) techniques.

Remediation script:
- name: Ensure sysctl kernel.randomize_va_space is set to 2
  sysctl:
    name: kernel.randomize_va_space
    value: '2'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83146-1
    - DISA-STIG-SLES-12-030330
    - NIST-800-171-3.1.7
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SC-30
    - NIST-800-53-SC-30(2)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_randomize_va_space

GRUB2 bootloader configurationgroup

During the boot process, the boot loader is responsible for starting the execution of the kernel and passing options to it. The boot loader allows for the selection of different kernels - possibly on different partitions or media. The default SUSE Linux Enterprise 12 boot loader for x86 systems is called GRUB2. Options it can pass to the kernel include single-user mode, which provides root access without any authentication, and the ability to disable SELinux. To prevent local users from modifying the boot parameters and endangering security, protect the boot loader configuration with a password and ensure its configuration file's permissions are set properly.

contains 2 rules

UEFI GRUB2 bootloader configurationgroup

UEFI GRUB2 bootloader configuration

contains 1 rule

Set the UEFI Boot Loader Passwordrule

The grub2 boot loader should have a superuser account and password protection enabled to protect boot-time settings.

Since plaintext passwords are a security risk, generate a hash for the password by running the following command:

$ grub2-mkpasswd-pbkdf2
When prompted, enter the password that was selected.

Using the hash from the output, modify the /etc/grub.d/40_custom file with the following content:
set superusers="boot"
password_pbkdf2 boot grub.pbkdf2.sha512.VeryLongString
NOTE: the bootloader superuser account and password MUST differ from the root account and password. Once the superuser password has been added, update the grub.cfg file by running:
grub2-mkconfig -o /boot/efi/EFI/sles/grub.cfg

warning  To prevent hard-coded passwords, automatic remediation of this control is not available. Remediation must be automated as a component of machine provisioning, or followed manually as outlined above. Also, do NOT manually add the superuser account and password to the grub.cfg file as the grub2-mkconfig command overwrites this file.
Rationale:

Password protection on the boot loader configuration ensures users with physical access cannot trivially alter important bootloader settings. These include which kernel to use, and whether to enter single-user mode.

Non-UEFI GRUB2 bootloader configurationgroup

Non-UEFI GRUB2 bootloader configuration

contains 1 rule

Set Boot Loader Password in grub2rule

The grub2 boot loader should have a superuser account and password protection enabled to protect boot-time settings.

Since plaintext passwords are a security risk, generate a hash for the password by running the following command:

$ grub2-mkpasswd-pbkdf2
When prompted, enter the password that was selected.

Using the hash from the output, modify the /etc/grub.d/40_custom file with the following content:
set superusers="boot"
password_pbkdf2 boot grub.pbkdf2.sha512.VeryLongString
NOTE: the bootloader superuser account and password MUST differ from the root account and password.

Once the superuser password has been added, update the grub.cfg file by running:
grub2-mkconfig -o /boot/grub2/grub.cfg

warning  To prevent hard-coded passwords, automatic remediation of this control is not available. Remediation must be automated as a component of machine provisioning, or followed manually as outlined above. Also, do NOT manually add the superuser account and password to the grub.cfg file as the grub2-mkconfig command overwrites this file.
Rationale:

Password protection on the boot loader configuration ensures users with physical access cannot trivially alter important bootloader settings. These include which kernel to use, and whether to enter single-user mode.

Configure Sysloggroup

The syslog service has been the default Unix logging mechanism for many years. It has a number of downsides, including inconsistent log format, lack of authentication for received messages, and lack of authentication, encryption, or reliable transport for messages sent over a network. However, due to its long history, syslog is a de facto standard which is supported by almost all Unix applications.

In SUSE Linux Enterprise 12, rsyslog has replaced ksyslogd as the syslog daemon of choice, and it includes some additional security features such as reliable, connection-oriented (i.e. TCP) transmission of logs, the option to log to database formats, and the encryption of log data en route to a central logging server. This section discusses how to configure rsyslog for best effect, and how to use tools provided with the system to maintain and monitor logs.

contains 2 rules

Rsyslog Logs Sent To Remote Hostgroup

If system logs are to be useful in detecting malicious activities, it is necessary to send logs to a remote server. An intruder who has compromised the root account on a system may delete the log entries which indicate that the system was attacked before they are seen by an administrator.

However, it is recommended that logs be stored on the local host in addition to being sent to the loghost, especially if rsyslog has been configured to use the UDP protocol to send messages over a network. UDP does not guarantee reliable delivery, and moderately busy sites will lose log messages occasionally, especially in periods of high traffic which may be the result of an attack. In addition, remote rsyslog messages are not authenticated in any way by default, so it is easy for an attacker to introduce spurious messages to the central log server. Also, some problems cause loss of network connectivity, which will prevent the sending of messages to the central server. For all of these reasons, it is better to store log messages both centrally and on each host, so that they can be correlated if necessary.

contains 1 rule

Ensure Logs Sent To Remote Hostrule

To configure rsyslog to send logs to a remote log server, open /etc/rsyslog.conf and read and understand the last section of the file, which describes the multiple directives necessary to activate remote logging. Along with these other directives, the system can be configured to forward its logs to a particular log server by adding or correcting one of the following lines, substituting logcollector appropriately. The choice of protocol depends on the environment of the system; although TCP and RELP provide more reliable message delivery, they may not be supported in all environments.
To use UDP for log message delivery:

*.* @logcollector

To use TCP for log message delivery:
*.* @@logcollector

To use RELP for log message delivery:
*.* :omrelp:logcollector

There must be a resolvable DNS CNAME or Alias record set to "logcollector" for logs to be sent correctly to the centralized logging utility.

Rationale:

A log server (loghost) receives syslog messages from one or more systems. This data can be used as an additional log source in the event a system is compromised and its local logs are suspect. Forwarding log messages to a remote loghost also provides system administrators with a centralized place to view the status of multiple hosts within the enterprise.

Remediation script:
- name: XCCDF Value rsyslog_remote_loghost_address # promote to variable
  set_fact:
    rsyslog_remote_loghost_address: !!str logcollector
  tags:
    - always

- name: Set rsyslog remote loghost
  lineinfile:
    dest: /etc/rsyslog.conf
    regexp: ^\*\.\*
    line: '*.* @@{{ rsyslog_remote_loghost_address }}'
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83180-0
    - DISA-STIG-SLES-12-030340
    - NIST-800-53-AU-4(1)
    - NIST-800-53-AU-9(2)
    - NIST-800-53-CM-6(a)
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - rsyslog_remote_loghost

Ensure real-time clock is set to UTCrule

Ensure that the system real-time clock (RTC) is set to Coordinated Universal Time (UTC).

Rationale:

If time stamps are not consistently applied and there is no common time reference, it is difficult to perform forensic analysis. Time stamps generated by the operating system include date and time. Time is commonly expressed in UTC, a modern continuation of GMT, or local time with an offset from UTC.

Remediation script:
- name: Check 'UTC' timezone is set
  shell: |
    set -o pipefail
    timedatectl status | grep -i 'Time zone'| grep -iv 'UTC\|GMT' || true
  register: check_tz
  failed_when: check_tz.rc not in [ 0 , 1 ]
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83197-4
    - DISA-STIG-SLES-12-030310
    - NIST-800-53-AU-8(b)
    - ensure_rtc_utc_configuration
    - high_severity

- name: Configure OS to use 'UTC' timezone
  command: timedatectl set-timezone UTC
  become: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - check_tz.rc == 0
  tags:
    - CCE-83197-4
    - DISA-STIG-SLES-12-030310
    - NIST-800-53-AU-8(b)
    - ensure_rtc_utc_configuration
    - high_severity

Servicesgroup

The best protection against vulnerable software is running less software. This section describes how to review the software which SUSE Linux Enterprise 12 installs on a system and disable software which is not needed. It then enumerates the software packages installed on a default SUSE Linux Enterprise 12 system and provides guidance about which ones can be safely disabled.

SUSE Linux Enterprise 12 provides a convenient minimal install option that essentially installs the bare necessities for a functional system. When building SUSE Linux Enterprise 12 systems, it is highly recommended to select the minimal packages and then build up the system from there.

contains 29 rules

FTP Servergroup

FTP is a common method for allowing remote access to files. Like telnet, the FTP protocol is unencrypted, which means that passwords and other data transmitted during the session can be captured and that the session is vulnerable to hijacking. Therefore, running the FTP server software is not recommended.

However, there are some FTP server configurations which may be appropriate for some environments, particularly those which allow only read-only anonymous access as a means of downloading data available to the public.

contains 1 rule

Configure vsftpd to Provide FTP Service if Necessarygroup

The primary vsftpd configuration file is /etc/vsftpd.conf, if that file exists, or /etc/vsftpd/vsftpd.conf if it does not.

contains 1 rule

Create Warning Banners for All FTP Usersrule

Edit the vsftpd configuration file, which resides at /etc/vsftpd.conf by default. Add or correct the following configuration options:

banner_file=/etc/issue

Rationale:

This setting will cause the system greeting banner to be used for FTP connections as well.

identifiers:  CCE-83059-6

references:  CCI-000048, SLES-12-030010

Remediation script:
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
  # Otherwise, regular sed command will do.
  sed_command=('sed' '-i')
  if test -L "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="${cce}"
  else
    cce="CCE"
  fi

  # Strip any search characters in the key arg so that the key can be replaced without
  # adding any search characters to the config file.
  stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$value"

  # If the key exists, change it. Otherwise, add it to the config_file.
  # We search for the key string followed by a word boundary (matched by \>),
  # so if we search for 'setting', 'setting2' won't match.
  if LC_ALL=C grep -q -m 1 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}
replace_or_append '/etc/vsftpd.conf' '^banner_file' '/etc/issue' 'CCE-83059-6' '%s=%s'
Remediation script:
- name: Service facts
  service_facts: null
  tags:
    - CCE-83059-6
    - DISA-STIG-SLES-12-030010
    - ftp_present_banner
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Configure banner_file setting
  lineinfile:
    dest: /etc/vsftpd.conf
    line: banner_file=/etc/issue
    regexp: ^\s*banner_file\s*=\s*.*$
    state: present
  register: banner_file_update_result
  when: ansible_facts.services["vsftpd.service"] is defined
  tags:
    - CCE-83059-6
    - DISA-STIG-SLES-12-030010
    - ftp_present_banner
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Restart vsftpd
  systemd:
    name: vsftpd.service
    state: restarted
  when: banner_file_update_result.changed and ansible_facts.services["vsftpd.service"].state
    == "running"
  tags:
    - CCE-83059-6
    - DISA-STIG-SLES-12-030010
    - ftp_present_banner
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

System Security Services Daemongroup

The System Security Services Daemon (SSSD) is a system daemon that provides access to different identity and authentication providers such as Red Hat's IdM, Microsoft's AD, openLDAP, MIT Kerberos, etc. It uses a common framework that can provide caching and offline support to systems utilizing SSSD. SSSD using caching to reduce load on authentication servers permit offline authentication as well as store extended user data.

For more information, see

contains 2 rules

Configure SSSD's Memory Cache to Expirerule

SSSD's memory cache should be configured to set to expire records after 86400 seconds. To configure SSSD to expire memory cache, set memcache_timeout to 86400 under the [nss] section in /etc/sssd/sssd.conf. For example:

[nss]
memcache_timeout = 86400

Rationale:

If cached authentication information is out-of-date, the validity of the authentication information may be questionable.

Remediation script:
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CCE-83040-6
    - DISA-STIG-SLES-12-010670
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(13)
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - sssd_memcache_timeout
    - unknown_strategy
- name: XCCDF Value var_sssd_memcache_timeout # promote to variable
  set_fact:
    var_sssd_memcache_timeout: !!str 86400
  tags:
    - always

- name: Test for domain group
  command: grep '\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf
  register: test_grep_domain
  ignore_errors: true
  changed_when: false
  check_mode: false
  when:
    - '"sssd" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83040-6
    - DISA-STIG-SLES-12-010670
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(13)
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - sssd_memcache_timeout
    - unknown_strategy

- name: Add default domain group (if no domain there)
  ini_file:
    path: /etc/sssd/sssd.conf
    section: '{{ item.section }}'
    option: '{{ item.option }}'
    value: '{{ item.value }}'
    create: true
    mode: 384
  with_items:
    - section: sssd
      option: domains
      value: default
    - section: domain/default
      option: id_provider
      value: files
  when:
    - '"sssd" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - test_grep_domain.stdout is defined
    - test_grep_domain.stdout | length < 1
  tags:
    - CCE-83040-6
    - DISA-STIG-SLES-12-010670
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(13)
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - sssd_memcache_timeout
    - unknown_strategy

- name: Configure SSSD's Memory Cache to Expire
  ini_file:
    dest: /etc/sssd/sssd.conf
    section: nss
    option: memcache_timeout
    value: '{{ var_sssd_memcache_timeout }}'
    create: true
    mode: 384
  when:
    - '"sssd" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83040-6
    - DISA-STIG-SLES-12-010670
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(13)
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - sssd_memcache_timeout
    - unknown_strategy

Configure SSSD to Expire Offline Credentialsrule

SSSD should be configured to expire offline credentials after 1 day. To configure SSSD to expire offline credentials, set offline_credentials_expiration to 1 under the [pam] section in /etc/sssd/sssd.conf. For example:

[pam]
offline_credentials_expiration = 1

Rationale:

If cached authentication information is out-of-date, the validity of the authentication information may be questionable.

Remediation script:
# Remediation is applicable only in certain platforms
if rpm --quiet -q sssd && { [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; }; then

SSSD_CONF="/etc/sssd/sssd.conf"
SSSD_OPT="offline_credentials_expiration"
SSSD_OPT_VAL=1
PAM_REGEX="[[:space:]]*\[pam]"
PAM_OPT_REGEX="${PAM_REGEX}([^\n\[]*\n+)+?[[:space:]]*${SSSD_OPT}"

# Try find [pam] and offline_credentials_expiration in sssd.conf, if it exists
# set it to 1, if it doesn't exist add it, if [pam] section doesn't exist add
# the section and the configuration option.
if grep -qzosP $PAM_OPT_REGEX $SSSD_CONF; then
	sed -i "s/${SSSD_OPT}[^(\n)]*/${SSSD_OPT} = ${SSSD_OPT_VAL}/" $SSSD_CONF
elif grep -qs $PAM_REGEX $SSSD_CONF; then
	sed -i "/$PAM_REGEX/a ${SSSD_OPT} = ${SSSD_OPT_VAL}" $SSSD_CONF
else
	mkdir -p /etc/sssd
	touch $SSSD_CONF
	echo -e "[pam]\n${SSSD_OPT} = ${SSSD_OPT_VAL}" >> $SSSD_CONF
fi

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CCE-83206-3
    - DISA-STIG-SLES-12-010680
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(13)
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - sssd_offline_cred_expiration

- name: Test for domain group
  command: grep '\s*\[domain\/[^]]*]' /etc/sssd/sssd.conf
  register: test_grep_domain
  ignore_errors: true
  changed_when: false
  check_mode: false
  when:
    - '"sssd" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83206-3
    - DISA-STIG-SLES-12-010680
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(13)
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - sssd_offline_cred_expiration

- name: Add default domain group (if no domain there)
  ini_file:
    path: /etc/sssd/sssd.conf
    section: '{{ item.section }}'
    option: '{{ item.option }}'
    value: '{{ item.value }}'
    create: true
    mode: 384
  with_items:
    - section: sssd
      option: domains
      value: default
    - section: domain/default
      option: id_provider
      value: files
  when:
    - '"sssd" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - test_grep_domain.stdout is defined
    - test_grep_domain.stdout | length < 1
  tags:
    - CCE-83206-3
    - DISA-STIG-SLES-12-010680
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(13)
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - sssd_offline_cred_expiration

- name: Configure SSD to Expire Offline Credentials
  ini_file:
    dest: /etc/sssd/sssd.conf
    section: pam
    option: offline_credentials_expiration
    value: 1
    create: true
    mode: 384
  when:
    - '"sssd" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83206-3
    - DISA-STIG-SLES-12-010680
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(13)
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - sssd_offline_cred_expiration

SSH Servergroup

The SSH protocol is recommended for remote login and remote file transfer. SSH provides confidentiality and integrity for data exchanged between two systems, as well as server authentication, through the use of public key cryptography. The implementation included with the system is called OpenSSH, and more detailed documentation is available from its website, https://www.openssh.com. Its server program is called sshd and provided by the RPM package openssh-server.

contains 18 rules

Configure OpenSSH Server if Necessarygroup

If the system needs to act as an SSH server, then certain changes should be made to the OpenSSH daemon configuration file /etc/ssh/sshd_config. The following recommendations can be applied to this file. See the sshd_config(5) man page for more detailed information.

contains 15 rules

Disable Compression Or Set Compression to delayedrule

Compression is useful for slow network connections over long distances but can cause performance issues on local LANs. If use of compression is required, it should be enabled only after a user has authenticated; otherwise, it should be disabled. To disable compression or delay compression until after a user has successfully authenticated, add or correct the following line in the /etc/ssh/sshd_config file:

Compression no

Rationale:

If compression is allowed in an SSH connection prior to authentication, vulnerabilities in the compression software could result in compromise of the system from an unauthenticated connection, potentially with root privileges.

Remediation script:
- name: XCCDF Value var_sshd_disable_compression # promote to variable
  set_fact:
    var_sshd_disable_compression: !!str no
  tags:
    - always

- name: Disable Compression Or Set Compression to delayed
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*Compression\s+
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*Compression\s+
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)^\s*Compression\s+
        line: Compression {{ var_sshd_disable_compression }}
        state: present
        insertbefore: ^[#\s]*Match
        validate: /usr/sbin/sshd -t -f %s
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83062-0
    - DISA-STIG-SLES-12-030250
    - NIST-800-171-3.1.12
    - NIST-800-53-AC-17(a)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - sshd_disable_compression

Set SSH Idle Timeout Intervalrule

SSH allows administrators to set an idle timeout interval. After this interval has passed, the idle user will be automatically logged out.

To set an idle timeout interval, edit the following line in /etc/ssh/sshd_config as follows:

ClientAliveInterval 300


The timeout interval is given in seconds. For example, have a timeout of 10 minutes, set interval to 600.

If a shorter timeout has already been set for the login shell, that value will preempt any SSH setting made in /etc/ssh/sshd_config. Keep in mind that some processes may stop SSH from correctly detecting that the user is idle.

warning  SSH disconnecting idle clients will not have desired effect without also configuring ClientAliveCountMax in the SSH service configuration.
warning  Following conditions may prevent the SSH session to time out:
  • Remote processes on the remote machine generates output. As the output has to be transferred over the network to the client, the timeout is reset every time such transfer happens.
  • Any scp or sftp activity by the same user to the host resets the timeout.
Rationale:

Terminating an idle ssh session within a short time period reduces the window of opportunity for unauthorized personnel to take control of a management session enabled on the console or console port that has been let unattended.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then


sshd_idle_timeout_value="300"



if [ -e "/etc/ssh/sshd_config" ] ; then
    LC_ALL=C sed -i "/^\s*ClientAliveInterval\s\+/Id" "/etc/ssh/sshd_config"
else
    touch "/etc/ssh/sshd_config"
fi
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert before the line matching the regex '^Match'.
line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')"
if [ -z "$line_number" ]; then
    # There was no match of '^Match', insert at
    # the end of the file.
    printf '%s\n' "ClientAliveInterval $sshd_idle_timeout_value" >> "/etc/ssh/sshd_config"
else
    head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config"
    printf '%s\n' "ClientAliveInterval $sshd_idle_timeout_value" >> "/etc/ssh/sshd_config"
    tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
fi
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: XCCDF Value sshd_idle_timeout_value # promote to variable
  set_fact:
    sshd_idle_timeout_value: !!str 300
  tags:
    - always

- name: Set SSH Idle Timeout Interval
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*ClientAliveInterval\s+
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*ClientAliveInterval\s+
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)^\s*ClientAliveInterval\s+
        line: ClientAliveInterval {{ sshd_idle_timeout_value }}
        state: present
        insertbefore: ^[#\s]*Match
        validate: /usr/sbin/sshd -t -f %s
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83027-3
    - CJIS-5.5.6
    - DISA-STIG-SLES-12-030190
    - NIST-800-171-3.1.11
    - NIST-800-53-AC-12
    - NIST-800-53-AC-17(a)
    - NIST-800-53-AC-17(a)
    - NIST-800-53-AC-2(5)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SC-10
    - PCI-DSS-Req-8.1.8
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - sshd_set_idle_timeout

Enable Use of Strict Mode Checkingrule

SSHs StrictModes option checks file and ownership permissions in the user's home directory .ssh folder before accepting login. If world- writable permissions are found, logon is rejected. To enable StrictModes in SSH, add or correct the following line in the /etc/ssh/sshd_config file:

StrictModes yes

Rationale:

If other users have access to modify user-specific SSH configuration files, they may be able to log into the system as another user.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if [ -e "/etc/ssh/sshd_config" ] ; then
    LC_ALL=C sed -i "/^\s*StrictModes\s\+/Id" "/etc/ssh/sshd_config"
else
    touch "/etc/ssh/sshd_config"
fi
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert before the line matching the regex '^Match'.
line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')"
if [ -z "$line_number" ]; then
    # There was no match of '^Match', insert at
    # the end of the file.
    printf '%s\n' "StrictModes yes" >> "/etc/ssh/sshd_config"
else
    head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config"
    printf '%s\n' "StrictModes yes" >> "/etc/ssh/sshd_config"
    tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
fi
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Enable Use of Strict Mode Checking
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*StrictModes\s+
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*StrictModes\s+
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)^\s*StrictModes\s+
        line: StrictModes yes
        state: present
        insertbefore: ^[#\s]*Match
        validate: /usr/sbin/sshd -t -f %s
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83060-4
    - DISA-STIG-SLES-12-030230
    - NIST-800-171-3.1.12
    - NIST-800-53-AC-17(a)
    - NIST-800-53-AC-6
    - NIST-800-53-CM-6(a)
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - sshd_enable_strictmodes

Use Only FIPS 140-2 Validated MACsrule

Limit the MACs to those hash algorithms which are FIPS-approved. The following line in /etc/ssh/sshd_config demonstrates use of FIPS-approved MACs:

MACs hmac-sha2-512,hmac-sha2-256
The man page sshd_config(5) contains a list of supported MACs. The rule is parametrized to use the following MACs: aes128-ctr,aes192-ctr,aes256-ctr.

warning  The system needs to be rebooted for these changes to take effect.
warning  System Crypto Modules must be provided by a vendor that undergoes FIPS-140 certifications. FIPS-140 is applicable to all Federal agencies that use cryptographic-based security systems to protect sensitive information in computer and telecommunication systems (including voice systems) as defined in Section 5131 of the Information Technology Management Reform Act of 1996, Public Law 104-106. This standard shall be used in designing and implementing cryptographic modules that Federal departments and agencies operate or are operated for them under contract. See https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.140-2.pdf To meet this, the system has to have cryptographic software provided by a vendor that has undergone this certification. This means providing documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process.
Rationale:

DoD Information Systems are required to use FIPS-approved cryptographic hash functions. The only SSHv2 hash algorithms meeting this requirement is SHA2.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then


sshd_approved_macs="aes128-ctr,aes192-ctr,aes256-ctr"
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
  # Otherwise, regular sed command will do.
  sed_command=('sed' '-i')
  if test -L "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="${cce}"
  else
    cce="CCE"
  fi

  # Strip any search characters in the key arg so that the key can be replaced without
  # adding any search characters to the config file.
  stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$value"

  # If the key exists, change it. Otherwise, add it to the config_file.
  # We search for the key string followed by a word boundary (matched by \>),
  # so if we search for 'setting', 'setting2' won't match.
  if LC_ALL=C grep -q -m 1 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}
replace_or_append '/etc/ssh/sshd_config' '^MACs' "$sshd_approved_macs" 'CCE-83036-4' '%s %s'

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: XCCDF Value sshd_approved_macs # promote to variable
  set_fact:
    sshd_approved_macs: !!str aes128-ctr,aes192-ctr,aes256-ctr
  tags:
    - always

- name: Use Only FIPS 140-2 Validated MACs
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*MACs\s+
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*MACs\s+
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)^\s*MACs\s+
        line: MACs {{ sshd_approved_macs }}
        state: present
        insertbefore: ^[#\s]*Match
        validate: /usr/sbin/sshd -t -f %s
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83036-4
    - DISA-STIG-SLES-12-030180
    - NIST-800-171-3.1.13
    - NIST-800-171-3.13.11
    - NIST-800-171-3.13.8
    - NIST-800-53-AC-17(2)
    - NIST-800-53-AC-17(a)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-MA-4(6)
    - NIST-800-53-SC-12(2)
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SC-13
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - sshd_use_approved_macs

Do Not Allow SSH Environment Optionsrule

To ensure users are not able to override environment variables of the SSH daemon, add or correct the following line in /etc/ssh/sshd_config:

PermitUserEnvironment no

Rationale:

SSH environment options potentially allow users to bypass access restriction in some configurations.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if [ -e "/etc/ssh/sshd_config" ] ; then
    LC_ALL=C sed -i "/^\s*PermitUserEnvironment\s\+/Id" "/etc/ssh/sshd_config"
else
    touch "/etc/ssh/sshd_config"
fi
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert before the line matching the regex '^Match'.
line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')"
if [ -z "$line_number" ]; then
    # There was no match of '^Match', insert at
    # the end of the file.
    printf '%s\n' "PermitUserEnvironment no" >> "/etc/ssh/sshd_config"
else
    head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config"
    printf '%s\n' "PermitUserEnvironment no" >> "/etc/ssh/sshd_config"
    tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
fi
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Do Not Allow SSH Environment Options
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*PermitUserEnvironment\s+
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*PermitUserEnvironment\s+
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)^\s*PermitUserEnvironment\s+
        line: PermitUserEnvironment no
        state: present
        insertbefore: ^[#\s]*Match
        validate: /usr/sbin/sshd -t -f %s
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83015-8
    - CJIS-5.5.6
    - DISA-STIG-SLES-12-030151
    - NIST-800-171-3.1.12
    - NIST-800-53-AC-17(a)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - sshd_do_not_permit_user_env

Use Only FIPS 140-2 Validated Ciphersrule

Limit the ciphers to those algorithms which are FIPS-approved. Counter (CTR) mode is also preferred over cipher-block chaining (CBC) mode. The following line in /etc/ssh/sshd_config demonstrates use of FIPS-approved ciphers:

Ciphers aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc
The man page sshd_config(5) contains a list of supported ciphers. The rule is parametrized to use the following ciphers: aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se.

warning  The system needs to be rebooted for these changes to take effect.
warning  System Crypto Modules must be provided by a vendor that undergoes FIPS-140 certifications. FIPS-140 is applicable to all Federal agencies that use cryptographic-based security systems to protect sensitive information in computer and telecommunication systems (including voice systems) as defined in Section 5131 of the Information Technology Management Reform Act of 1996, Public Law 104-106. This standard shall be used in designing and implementing cryptographic modules that Federal departments and agencies operate or are operated for them under contract. See https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.140-2.pdf To meet this, the system has to have cryptographic software provided by a vendor that has undergone this certification. This means providing documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process.
Rationale:

Unapproved mechanisms that are used for authentication to the cryptographic module are not verified and therefore cannot be relied upon to provide confidentiality or integrity, and system data may be compromised.
Operating systems utilizing encryption are required to use FIPS-compliant mechanisms for authenticating to cryptographic modules.
FIPS 140-2 is the current standard for validating that mechanisms used to access cryptographic modules utilize authentication that meets industry and government requirements. For government systems, this allows Security Levels 1, 2, 3, or 4 for use on SUSE Linux Enterprise 12.

identifiers:  CCE-83181-8

references:  1, 11, 12, 14, 15, 16, 18, 3, 5, 6, 8, 9, 5.5.6, APO11.04, APO13.01, BAI03.05, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.04, DSS05.02, DSS05.03, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.06, DSS06.10, MEA02.01, 3.1.13, 3.13.11, 3.13.8, CCI-000068, CCI-000366, CCI-000803, CCI-000877, CCI-002890, CCI-003123, 164.308(b)(1), 164.308(b)(2), 164.312(e)(1), 164.312(e)(2)(i), 164.312(e)(2)(ii), 164.314(b)(2)(i), 4.3.3.2.2, 4.3.3.3.9, 4.3.3.5.1, 4.3.3.5.2, 4.3.3.5.3, 4.3.3.5.4, 4.3.3.5.5, 4.3.3.5.6, 4.3.3.5.7, 4.3.3.5.8, 4.3.3.6.1, 4.3.3.6.2, 4.3.3.6.3, 4.3.3.6.4, 4.3.3.6.5, 4.3.3.6.6, 4.3.3.6.7, 4.3.3.6.8, 4.3.3.6.9, 4.3.3.7.1, 4.3.3.7.2, 4.3.3.7.3, 4.3.3.7.4, 4.3.4.3.2, 4.3.4.3.3, 4.3.4.4.7, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 1.1, SR 1.10, SR 1.11, SR 1.12, SR 1.13, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.6, SR 1.7, SR 1.8, SR 1.9, SR 2.1, SR 2.10, SR 2.11, SR 2.12, SR 2.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 2.8, SR 2.9, SR 3.1, SR 3.5, SR 3.8, SR 4.1, SR 4.3, SR 5.1, SR 5.2, SR 5.3, SR 7.1, SR 7.6, A.11.2.6, A.12.1.2, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.5.1, A.12.6.2, A.12.7.1, A.13.1.1, A.13.2.1, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.18.1.4, A.6.1.2, A.6.2.1, A.6.2.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.2, A.9.2.3, A.9.2.4, A.9.2.6, A.9.3.1, A.9.4.1, A.9.4.2, A.9.4.3, A.9.4.4, A.9.4.5, CM-6(a), AC-17(a), AC-17(2), SC-13, MA-4(6), IA-5(1)(c), SC-12(2), SC-12(3), PR.AC-1, PR.AC-3, PR.AC-4, PR.AC-6, PR.AC-7, PR.IP-1, PR.PT-1, PR.PT-3, PR.PT-4, SRG-OS-000033-GPOS-00014, SRG-OS-000120-GPOS-00061, SRG-OS-000125-GPOS-00065, SRG-OS-000250-GPOS-00093, SRG-OS-000393-GPOS-00173, SRG-OS-000394-GPOS-00174, SLES-12-030170, SV-217270r603956_rule, SRG-OS-000033-VMM-000140, SRG-OS-000120-VMM-000600, SRG-OS-000478-VMM-001980, SRG-OS-000396-VMM-001590

Remediation script:
- name: XCCDF Value sshd_approved_ciphers # promote to variable
  set_fact:
    sshd_approved_ciphers: !!str aes128-ctr,aes192-ctr,aes256-ctr,aes128-cbc,3des-cbc,aes192-cbc,aes256-cbc,rijndael-cbc@lysator.liu.se
  tags:
    - always

- name: Use Only FIPS 140-2 Validated Ciphers
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*Ciphers\s+
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*Ciphers\s+
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)^\s*Ciphers\s+
        line: Ciphers {{ sshd_approved_ciphers }}
        state: present
        insertbefore: ^[#\s]*Match
        validate: /usr/sbin/sshd -t -f %s
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83181-8
    - CJIS-5.5.6
    - DISA-STIG-SLES-12-030170
    - NIST-800-171-3.1.13
    - NIST-800-171-3.13.11
    - NIST-800-171-3.13.8
    - NIST-800-53-AC-17(2)
    - NIST-800-53-AC-17(a)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-MA-4(6)
    - NIST-800-53-SC-12(2)
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SC-13
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - sshd_use_approved_ciphers

Disable SSH Access via Empty Passwordsrule

To explicitly disallow SSH login from accounts with empty passwords, add or correct the following line in /etc/ssh/sshd_config:

PermitEmptyPasswords no

Any accounts with empty passwords should be disabled immediately, and PAM configuration should prevent users from being able to assign themselves empty passwords.

Rationale:

Configuring this setting for the SSH daemon provides additional assurance that remote login via SSH will require a password, even in the event of misconfiguration elsewhere.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if [ -e "/etc/ssh/sshd_config" ] ; then
    LC_ALL=C sed -i "/^\s*PermitEmptyPasswords\s\+/Id" "/etc/ssh/sshd_config"
else
    touch "/etc/ssh/sshd_config"
fi
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert before the line matching the regex '^Match'.
line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')"
if [ -z "$line_number" ]; then
    # There was no match of '^Match', insert at
    # the end of the file.
    printf '%s\n' "PermitEmptyPasswords no" >> "/etc/ssh/sshd_config"
else
    head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config"
    printf '%s\n' "PermitEmptyPasswords no" >> "/etc/ssh/sshd_config"
    tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
fi
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Disable SSH Access via Empty Passwords
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*PermitEmptyPasswords\s+
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*PermitEmptyPasswords\s+
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)^\s*PermitEmptyPasswords\s+
        line: PermitEmptyPasswords no
        state: present
        insertbefore: ^[#\s]*Match
        validate: /usr/sbin/sshd -t -f %s
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83014-1
    - CJIS-5.5.6
    - DISA-STIG-SLES-12-030150
    - NIST-800-171-3.1.1
    - NIST-800-171-3.1.5
    - NIST-800-53-AC-17(a)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - high_severity
    - low_complexity
    - low_disruption
    - no_reboot_needed
    - restrict_strategy
    - sshd_disable_empty_passwords

Enable SSH Warning Bannerrule

To enable the warning banner and ensure it is consistent across the system, add or correct the following line in /etc/ssh/sshd_config:

Banner /etc/issue
Another section contains information on how to create an appropriate system-wide warning banner.

Rationale:

The warning message reinforces policy awareness during the logon process and facilitates possible legal action against attackers. Alternatively, systems whose ownership should not be obvious should ensure usage of a banner that does not provide easy attribution.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if [ -e "/etc/ssh/sshd_config" ] ; then
    LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config"
else
    touch "/etc/ssh/sshd_config"
fi
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert before the line matching the regex '^Match'.
line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')"
if [ -z "$line_number" ]; then
    # There was no match of '^Match', insert at
    # the end of the file.
    printf '%s\n' "Banner /etc/issue" >> "/etc/ssh/sshd_config"
else
    head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config"
    printf '%s\n' "Banner /etc/issue" >> "/etc/ssh/sshd_config"
    tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
fi
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Enable SSH Warning Banner
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*Banner\s+
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*Banner\s+
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)^\s*Banner\s+
        line: Banner /etc/issue
        state: present
        insertbefore: ^[#\s]*Match
        validate: /usr/sbin/sshd -t -f %s
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83066-1
    - CJIS-5.5.6
    - DISA-STIG-SLES-12-030050
    - NIST-800-171-3.1.9
    - NIST-800-53-AC-17(a)
    - NIST-800-53-AC-8(a)
    - NIST-800-53-AC-8(c)
    - NIST-800-53-CM-6(a)
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - sshd_enable_warning_banner

Enable Use of Privilege Separationrule

When enabled, SSH will create an unprivileged child process that has the privilege of the authenticated user. To enable privilege separation in SSH, add or correct the following line in the /etc/ssh/sshd_config file:

UsePrivilegeSeparation sandbox

Rationale:

SSH daemon privilege separation causes the SSH process to drop root privileges when not needed which would decrease the impact of software vulnerabilities in the unprivileged section.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then


var_sshd_priv_separation="sandbox"



if [ -e "/etc/ssh/sshd_config" ] ; then
    LC_ALL=C sed -i "/^\s*UsePrivilegeSeparation\s\+/Id" "/etc/ssh/sshd_config"
else
    touch "/etc/ssh/sshd_config"
fi
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert before the line matching the regex '^Match'.
line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')"
if [ -z "$line_number" ]; then
    # There was no match of '^Match', insert at
    # the end of the file.
    printf '%s\n' "UsePrivilegeSeparation $var_sshd_priv_separation" >> "/etc/ssh/sshd_config"
else
    head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config"
    printf '%s\n' "UsePrivilegeSeparation $var_sshd_priv_separation" >> "/etc/ssh/sshd_config"
    tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
fi
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: XCCDF Value var_sshd_priv_separation # promote to variable
  set_fact:
    var_sshd_priv_separation: !!str sandbox
  tags:
    - always

- name: Enable Use of Privilege Separation
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*UsePrivilegeSeparation\s+
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*UsePrivilegeSeparation\s+
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)^\s*UsePrivilegeSeparation\s+
        line: UsePrivilegeSeparation {{ var_sshd_priv_separation }}
        state: present
        insertbefore: ^[#\s]*Match
        validate: /usr/sbin/sshd -t -f %s
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83061-2
    - DISA-STIG-SLES-12-030240
    - NIST-800-171-3.1.12
    - NIST-800-53-AC-17(a)
    - NIST-800-53-AC-6
    - NIST-800-53-CM-6(a)
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - sshd_use_priv_separation

Set SSH Client Alive Count Max to zerorule

The SSH server sends at most ClientAliveCountMax messages during a SSH session and waits for a response from the SSH client. The option ClientAliveInterval configures timeout after each ClientAliveCountMax message. If the SSH server does not receive a response from the client, then the connection is considered idle and terminated. To ensure the SSH idle timeout occurs precisely when the ClientAliveInterval is set, set the ClientAliveCountMax to value of 0.

Rationale:

This ensures a user login will be terminated as soon as the ClientAliveInterval is reached.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if [ -e "/etc/ssh/sshd_config" ] ; then
    LC_ALL=C sed -i "/^\s*ClientAliveCountMax\s\+/Id" "/etc/ssh/sshd_config"
else
    touch "/etc/ssh/sshd_config"
fi
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert before the line matching the regex '^Match'.
line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')"
if [ -z "$line_number" ]; then
    # There was no match of '^Match', insert at
    # the end of the file.
    printf '%s\n' "ClientAliveCountMax 0" >> "/etc/ssh/sshd_config"
else
    head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config"
    printf '%s\n' "ClientAliveCountMax 0" >> "/etc/ssh/sshd_config"
    tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
fi
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Set SSH Client Alive Count Max to zero
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*ClientAliveCountMax\s+
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*ClientAliveCountMax\s+
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)^\s*ClientAliveCountMax\s+
        line: ClientAliveCountMax 0
        state: present
        insertbefore: ^[#\s]*Match
        validate: /usr/sbin/sshd -t -f %s
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83407-7
    - CJIS-5.5.6
    - DISA-STIG-SLES-12-030191
    - NIST-800-171-3.1.11
    - NIST-800-53-AC-12
    - NIST-800-53-AC-17(a)
    - NIST-800-53-AC-2(5)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SC-10
    - PCI-DSS-Req-8.1.8
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - sshd_set_keepalive_0

Enable Encrypted X11 Forwardingrule

By default, remote X11 connections are not encrypted when initiated by users. SSH has the capability to encrypt remote X11 connections when SSH's X11Forwarding option is enabled.

To enable X11 Forwarding, add or correct the following line in /etc/ssh/sshd_config:

X11Forwarding yes

Rationale:

Non-encrypted X displays allow an attacker to capture keystrokes and to execute commands remotely.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if [ -e "/etc/ssh/sshd_config" ] ; then
    LC_ALL=C sed -i "/^\s*X11Forwarding\s\+/Id" "/etc/ssh/sshd_config"
else
    touch "/etc/ssh/sshd_config"
fi
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert before the line matching the regex '^Match'.
line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')"
if [ -z "$line_number" ]; then
    # There was no match of '^Match', insert at
    # the end of the file.
    printf '%s\n' "X11Forwarding yes" >> "/etc/ssh/sshd_config"
else
    head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config"
    printf '%s\n' "X11Forwarding yes" >> "/etc/ssh/sshd_config"
    tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
fi
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Enable Encrypted X11 Forwarding
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*X11Forwarding\s+
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*X11Forwarding\s+
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)^\s*X11Forwarding\s+
        line: X11Forwarding yes
        state: present
        insertbefore: ^[#\s]*Match
        validate: /usr/sbin/sshd -t -f %s
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83017-4
    - DISA-STIG-SLES-12-030260
    - NIST-800-171-3.1.13
    - NIST-800-53-AC-17(2)
    - NIST-800-53-AC-17(a)
    - NIST-800-53-CM-6(a)
    - high_severity
    - low_complexity
    - low_disruption
    - no_reboot_needed
    - restrict_strategy
    - sshd_enable_x11_forwarding

Enable SSH Print Last Logrule

When enabled, SSH will display the date and time of the last successful account logon. To enable LastLog in SSH, add or correct the following line in the /etc/ssh/sshd_config file:

PrintLastLog yes

Rationale:

Providing users feedback on when account accesses last occurred facilitates user recognition and reporting of unauthorized account use.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if [ -e "/etc/ssh/sshd_config" ] ; then
    LC_ALL=C sed -i "/^\s*PrintLastLog\s\+/Id" "/etc/ssh/sshd_config"
else
    touch "/etc/ssh/sshd_config"
fi
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert before the line matching the regex '^Match'.
line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')"
if [ -z "$line_number" ]; then
    # There was no match of '^Match', insert at
    # the end of the file.
    printf '%s\n' "PrintLastLog yes" >> "/etc/ssh/sshd_config"
else
    head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config"
    printf '%s\n' "PrintLastLog yes" >> "/etc/ssh/sshd_config"
    tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
fi
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Enable SSH Print Last Log
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*PrintLastLog\s+
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*PrintLastLog\s+
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)^\s*PrintLastLog\s+
        line: PrintLastLog yes
        state: present
        insertbefore: ^[#\s]*Match
        validate: /usr/sbin/sshd -t -f %s
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83083-6
    - DISA-STIG-SLES-12-030130
    - NIST-800-53-AC-17(a)
    - NIST-800-53-AC-9
    - NIST-800-53-CM-6(a)
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - sshd_print_last_log

Disable SSH Support for User Known Hostsrule

SSH can allow system users to connect to systems if a cache of the remote systems public keys is available. This should be disabled.

To ensure this behavior is disabled, add or correct the following line in /etc/ssh/sshd_config:

IgnoreUserKnownHosts yes

Rationale:

Configuring this setting for the SSH daemon provides additional assurance that remote login via SSH will require a password, even in the event of misconfiguration elsewhere.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if [ -e "/etc/ssh/sshd_config" ] ; then
    LC_ALL=C sed -i "/^\s*IgnoreUserKnownHosts\s\+/Id" "/etc/ssh/sshd_config"
else
    touch "/etc/ssh/sshd_config"
fi
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert before the line matching the regex '^Match'.
line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')"
if [ -z "$line_number" ]; then
    # There was no match of '^Match', insert at
    # the end of the file.
    printf '%s\n' "IgnoreUserKnownHosts yes" >> "/etc/ssh/sshd_config"
else
    head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config"
    printf '%s\n' "IgnoreUserKnownHosts yes" >> "/etc/ssh/sshd_config"
    tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
fi
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Disable SSH Support for User Known Hosts
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*IgnoreUserKnownHosts\s+
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*IgnoreUserKnownHosts\s+
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)^\s*IgnoreUserKnownHosts\s+
        line: IgnoreUserKnownHosts yes
        state: present
        insertbefore: ^[#\s]*Match
        validate: /usr/sbin/sshd -t -f %s
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83056-2
    - DISA-STIG-SLES-12-030200
    - NIST-800-171-3.1.12
    - NIST-800-53-AC-17(a)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - sshd_disable_user_known_hosts

Set SSH Daemon LogLevel to VERBOSErule

The VERBOSE parameter configures the SSH daemon to record login and logout activity. To specify the log level in SSH, add or correct the following line in the /etc/ssh/sshd_config file:

LogLevel VERBOSE

Rationale:

SSH provides several logging levels with varying amounts of verbosity. DEBUG is specifically not recommended other than strictly for debugging SSH communications since it provides so much data that it is difficult to identify important security information. INFO or VERBOSE level is the basic level that only records login activity of SSH users. In many situations, such as Incident Response, it is important to determine when a particular user was active on a system. The logout record can eliminate those users who disconnected, which helps narrow the field.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if [ -e "/etc/ssh/sshd_config" ] ; then
    LC_ALL=C sed -i "/^\s*LogLevel\s\+/Id" "/etc/ssh/sshd_config"
else
    touch "/etc/ssh/sshd_config"
fi
cp "/etc/ssh/sshd_config" "/etc/ssh/sshd_config.bak"
# Insert before the line matching the regex '^Match'.
line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.bak" | LC_ALL=C sed 's/:.*//g')"
if [ -z "$line_number" ]; then
    # There was no match of '^Match', insert at
    # the end of the file.
    printf '%s\n' "LogLevel VERBOSE" >> "/etc/ssh/sshd_config"
else
    head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.bak" > "/etc/ssh/sshd_config"
    printf '%s\n' "LogLevel VERBOSE" >> "/etc/ssh/sshd_config"
    tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.bak" >> "/etc/ssh/sshd_config"
fi
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.bak"

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Set SSH Daemon LogLevel to VERBOSE
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*LogLevel\s+
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: (?i)^\s*LogLevel\s+
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: true
        regexp: (?i)^\s*LogLevel\s+
        line: LogLevel VERBOSE
        state: present
        insertbefore: ^[#\s]*Match
        validate: /usr/sbin/sshd -t -f %s
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83077-8
    - DISA-STIG-SLES-12-030110
    - NIST-800-53-AC-17(1)
    - NIST-800-53-AC-17(a)
    - NIST-800-53-CM-6(a)
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - sshd_set_loglevel_verbose

Enable the OpenSSH Servicerule

The SSH server service, sshd, is commonly needed. The sshd service can be enabled with the following command:

$ sudo systemctl enable sshd.service

Rationale:

Without protection of the transmitted information, confidentiality, and integrity may be compromised because unprotected communications can be intercepted and either read or altered.

This checklist item applies to both internal and external networks and all types of information system components from which information can be transmitted (e.g., servers, mobile devices, notebook computers, printers, copiers, scanners, etc). Communication paths outside the physical protection of a controlled boundary are exposed to the possibility of interception and modification.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

SYSTEMCTL_EXEC='/usr/bin/systemctl'
"$SYSTEMCTL_EXEC" unmask 'sshd.service'
"$SYSTEMCTL_EXEC" start 'sshd.service'
"$SYSTEMCTL_EXEC" enable 'sshd.service'

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Enable service sshd
  block:

    - name: Gather the package facts
      package_facts:
        manager: auto

    - name: Enable service sshd
      service:
        name: sshd
        enabled: 'yes'
        state: started
        masked: 'no'
      when:
        - '"openssh" in ansible_facts.packages'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83201-4
    - DISA-STIG-SLES-12-030100
    - NIST-800-171-3.1.13
    - NIST-800-171-3.13.8
    - NIST-800-171-3.5.4
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SC-8
    - NIST-800-53-SC-8(1)
    - NIST-800-53-SC-8(2)
    - NIST-800-53-SC-8(3)
    - NIST-800-53-SC-8(4)
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_sshd_enabled
Remediation script:
include enable_sshd

class enable_sshd {
  service {'sshd':
    enable => true,
    ensure => 'running',
  }
}

Verify Permissions on SSH Server Public *.pub Key Filesrule

To properly set the permissions of /etc/ssh/*.pub, run the command:

$ sudo chmod 0644 /etc/ssh/*.pub

Rationale:

If a public host key file is modified by an unauthorized user, the SSH service may be compromised.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

readarray -t files < <(find /etc/ssh/)
for file in "${files[@]}"; do
    if basename $file | grep -q '^.*.pub$'; then
        chmod 0644 $file
    fi    
done

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Find /etc/ssh/ file(s)
  find:
    paths: /etc/ssh/
    patterns: ^.*.pub$
    use_regex: true
  register: files_found
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83057-0
    - DISA-STIG-SLES-12-030210
    - NIST-800-171-3.1.13
    - NIST-800-171-3.13.10
    - NIST-800-53-AC-17(a)
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - configure_strategy
    - file_permissions_sshd_pub_key
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Set permissions for /etc/ssh/ file(s)
  file:
    path: '{{ item.path }}'
    mode: '0644'
  with_items:
    - '{{ files_found.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83057-0
    - DISA-STIG-SLES-12-030210
    - NIST-800-171-3.1.13
    - NIST-800-171-3.13.10
    - NIST-800-53-AC-17(a)
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - configure_strategy
    - file_permissions_sshd_pub_key
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
Remediation script:
include ssh_public_key_perms

class ssh_public_key_perms {
  exec { 'sshd_pub_key':
    command => "chmod 0644 /etc/ssh/*.pub",
    path    => '/bin:/usr/bin'
  }
}

Verify Permissions on SSH Server Private *_key Key Filesrule

To properly set the permissions of /etc/ssh/*_key, run the command:

$ sudo chmod 0600 /etc/ssh/*_key

Rationale:

If an unauthorized user obtains the private SSH host key file, the host could be impersonated.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

readarray -t files < <(find /etc/ssh/)
for file in "${files[@]}"; do
    if basename $file | grep -q '^.*_key$'; then
        chmod 0600 $file
    fi    
done

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Find /etc/ssh/ file(s)
  find:
    paths: /etc/ssh/
    patterns: ^.*_key$
    use_regex: true
  register: files_found
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83058-8
    - DISA-STIG-SLES-12-030220
    - NIST-800-171-3.1.13
    - NIST-800-171-3.13.10
    - NIST-800-53-AC-17(a)
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - configure_strategy
    - file_permissions_sshd_private_key
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Set permissions for /etc/ssh/ file(s)
  file:
    path: '{{ item.path }}'
    mode: '0600'
  with_items:
    - '{{ files_found.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83058-8
    - DISA-STIG-SLES-12-030220
    - NIST-800-171-3.1.13
    - NIST-800-171-3.13.10
    - NIST-800-53-AC-17(a)
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - configure_strategy
    - file_permissions_sshd_private_key
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
Remediation script:
include ssh_private_key_perms

class ssh_private_key_perms {
  exec { 'sshd_priv_key':
    command => "chmod 0640 /etc/ssh/*_key",
    path    => '/bin:/usr/bin'
  }
}

Obsolete Servicesgroup

This section discusses a number of network-visible services which have historically caused problems for system security, and for which disabling or severely limiting the service has been the best available guidance for some time. As a result of this, many of these services are not installed as part of SUSE Linux Enterprise 12 by default.

Organizations which are running these services should switch to more secure equivalents as soon as possible. If it remains absolutely necessary to run one of these services for legacy reasons, care should be taken to restrict the service as much as possible, for instance by configuring host firewall software such as iptables to restrict access to the vulnerable service to only those remote hosts which have a known need to use it.

contains 3 rules

Rlogin, Rsh, and Rexecgroup

The Berkeley r-commands are legacy services which allow cleartext remote access and have an insecure trust model.

contains 2 rules

Remove Host-Based Authentication Filesrule

The shosts.equiv file list remote hosts and users that are trusted by the local system. To remove these files, run the following command to delete them from any location:

$ sudo rm /[path]/[to]/[file]/shosts.equiv

Rationale:

The shosts.equiv files are used to configure host-based authentication for the system via SSH. Host-based authentication is not sufficient for preventing unauthorized access to the system, as it does not require interactive identification and authentication of a connection request, or for the use of two-factor authentication.

identifiers:  CCE-83022-4

references:  CCI-000366, SRG-OS-000480-GPOS-00227, SLES-12-010410, SV-217142r603262_rule

Remediation script:

# Identify local mounts
MOUNT_LIST=$(df --local | awk '{ print $6 }')

# Find file on each listed mount point
for cur_mount in ${MOUNT_LIST}
do
	find ${cur_mount} -xdev -type f -name "shosts.equiv" -exec rm -f {} \;
done
Remediation script:
- block:

    - name: Find local mount points
      shell: |
        set -o pipefail
        df --local | awk '{print $6}' | grep -v Mounted | grep -v '^/dev' || true
      register: local_mount_points

    - name: Detect the shosts.equiv files on the system
      find:
        paths: '{{ item }}'
        recurse: true
        patterns:
          - shosts.equiv
        file_type: file
      check_mode: false
      with_items: '{{ local_mount_points.stdout_lines }}'
      register: shosts_equiv_locations

    - name: Remove shosts.equiv Files
      file:
        path: '{{ item.path }}'
        state: absent
      with_items: '{{ shosts_equiv_locations.results | map(attribute=''files'') |
        list }}'
      when: shosts_equiv_locations is success
  tags:
    - CCE-83022-4
    - DISA-STIG-SLES-12-010410
    - high_severity
    - low_complexity
    - low_disruption
    - no_host_based_files
    - no_reboot_needed
    - restrict_strategy

Remove User Host-Based Authentication Filesrule

The ~/.shosts (in each user's home directory) files list remote hosts and users that are trusted by the local system. To remove these files, run the following command to delete them from any location:

$ sudo find / -name '.shosts' -type f -delete

Rationale:

The .shosts files are used to configure host-based authentication for individual users or the system via SSH. Host-based authentication is not sufficient for preventing unauthorized access to the system, as it does not require interactive identification and authentication of a connection request, or for the use of two-factor authentication.

identifiers:  CCE-83021-6

references:  CCI-000366, SRG-OS-000480-GPOS-00227, SLES-12-010400, SV-217141r603262_rule

Remediation script:

# Identify local mounts
MOUNT_LIST=$(df --local | awk '{ print $6 }')

# Find file on each listed mount point
for cur_mount in ${MOUNT_LIST}
do
	find ${cur_mount} -xdev -type f -name ".shosts" -exec rm -f {} \;
done
Remediation script:
- block:

    - name: Find local mount points
      shell: |
        set -o pipefail
        df --local | awk '{print $6}' | grep -v Mounted | grep -v '^/dev' || true
      register: local_mount_points

    - name: Detect the .shosts files on the system
      find:
        paths: '{{ item }}'
        recurse: true
        patterns:
          - .shosts
        hidden: true
        file_type: file
      check_mode: false
      with_items: '{{ local_mount_points.stdout_lines }}'
      register: shosts_locations

    - name: Remove .shosts Files
      file:
        path: '{{ item.path }}'
        state: absent
      with_items: '{{ shosts_locations.results | map(attribute=''files'') | list }}'
      when: shosts_locations is success
  tags:
    - CCE-83021-6
    - DISA-STIG-SLES-12-010400
    - high_severity
    - low_complexity
    - low_disruption
    - no_reboot_needed
    - no_user_host_based_files
    - restrict_strategy

Telnetgroup

The telnet protocol does not provide confidentiality or integrity for information transmitted on the network. This includes authentication information such as passwords. Organizations which use telnet should be actively working to migrate to a more secure protocol.

contains 1 rule

Uninstall telnet-server Packagerule

The telnet-server package can be removed with the following command:

$ sudo zypper remove telnet-server

Rationale:

It is detrimental for operating systems to provide, or install by default, functionality exceeding requirements or mission objectives. These unnecessary capabilities are often overlooked and therefore may remain unsecure. They increase the risk to the platform by providing additional attack vectors.
The telnet service provides an unencrypted remote access service which does not provide for the confidentiality and integrity of user passwords or the remote session. If a privileged user were to login using this service, the privileged user password could be compromised.
Removing the telnet-server package decreases the risk of the telnet service's accidental (or intentional) activation.

Remediation script:

# CAUTION: This remediation script will remove telnet-server
#	   from the system, and may remove any packages
#	   that depend on telnet-server. Execute this
#	   remediation AFTER testing on a non-production
#	   system!

zypper remove -y "telnet-server"
Remediation script:
- name: Ensure telnet-server is removed
  package:
    name: telnet-server
    state: absent
  tags:
    - CCE-83084-4
    - DISA-STIG-SLES-12-030000
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - disable_strategy
    - high_severity
    - low_complexity
    - low_disruption
    - no_reboot_needed
    - package_telnet-server_removed
Remediation script:
include remove_telnet-server

class remove_telnet-server {
  package { 'telnet-server':
    ensure => 'purged',
  }
}

Base Servicesgroup

This section addresses the base services that are installed on a SUSE Linux Enterprise 12 default installation which are not covered in other sections. Some of these services listen on the network and should be treated with particular discretion. Other services are local system utilities that may or may not be extraneous. In general, system services should be disabled if not required.

contains 1 rule

Disable KDump Kernel Crash Analyzer (kdump)rule

The kdump service provides a kernel crash dump analyzer. It uses the kexec system call to boot a secondary kernel ("capture" kernel) following a system crash, which can load information from the crashed kernel for analysis. The kdump service can be disabled with the following command:

$ sudo systemctl mask --now kdump.service

Rationale:

Kernel core dumps may contain the full contents of system memory at the time of the crash. Kernel core dumps consume a considerable amount of disk space and may result in denial of service by exhausting the available space on the target file system partition. Unless the system is used for kernel development or testing, there is little need to run the kdump service.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

SYSTEMCTL_EXEC='/usr/bin/systemctl'
"$SYSTEMCTL_EXEC" stop 'kdump.service'
"$SYSTEMCTL_EXEC" disable 'kdump.service'
"$SYSTEMCTL_EXEC" mask 'kdump.service'
# Disable socket activation if we have a unit file for it
if "$SYSTEMCTL_EXEC" list-unit-files | grep -q '^kdump.socket'; then
    "$SYSTEMCTL_EXEC" stop 'kdump.socket'
    "$SYSTEMCTL_EXEC" mask 'kdump.socket'
fi
# The service may not be running because it has been started and failed,
# so let's reset the state so OVAL checks pass.
# Service should be 'inactive', not 'failed' after reboot though.
"$SYSTEMCTL_EXEC" reset-failed 'kdump.service' || true

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Disable service kdump
  block:

    - name: Gather the service facts
      service_facts: null

    - name: Disable service kdump
      systemd:
        name: kdump.service
        enabled: 'no'
        state: stopped
        masked: 'yes'
      when: '"kdump.service" in ansible_facts.services'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83105-7
    - DISA-STIG-SLES-12-010840
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - disable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_kdump_disabled

- name: Unit Socket Exists - kdump.socket
  command: systemctl list-unit-files kdump.socket
  args:
    warn: false
  register: socket_file_exists
  changed_when: false
  ignore_errors: true
  check_mode: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83105-7
    - DISA-STIG-SLES-12-010840
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - disable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_kdump_disabled

- name: Disable socket kdump
  systemd:
    name: kdump.socket
    enabled: 'no'
    state: stopped
    masked: 'yes'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"kdump.socket" in socket_file_exists.stdout_lines[1]'
  tags:
    - CCE-83105-7
    - DISA-STIG-SLES-12-010840
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - disable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_kdump_disabled
Remediation script:
include disable_kdump

class disable_kdump {
  service {'kdump':
    enable => false,
    ensure => 'stopped',
  }
}

NFS and RPCgroup

The Network File System is a popular distributed filesystem for the Unix environment, and is very widely deployed. This section discusses the circumstances under which it is possible to disable NFS and its dependencies, and then details steps which should be taken to secure NFS's configuration. This section is relevant to systems operating as NFS clients, as well as to those operating as NFS servers.

contains 2 rules

Configure NFS Clientsgroup

The steps in this section are appropriate for systems which operate as NFS clients.

contains 2 rules

Mount Remote Filesystems with Restrictive Optionsgroup

Edit the file /etc/fstab. For each filesystem whose type (column 3) is nfs or nfs4, add the text ,nodev,nosuid to the list of mount options in column 4. If appropriate, also add ,noexec.

See the section titled "Restrict Partition Mount Options" for a description of the effects of these options. In general, execution of files mounted via NFS should be considered risky because of the possibility that an adversary could intercept the request and substitute a malicious file. Allowing setuid files to be executed from remote servers is particularly risky, both for this reason and because it requires the clients to extend root-level trust to the NFS server.

contains 2 rules

Mount Remote Filesystems with noexecrule

Add the noexec option to the fourth column of /etc/fstab for the line which controls mounting of any NFS mounts.

Rationale:

The noexec mount option causes the system not to execute binary files. This option must be used for mounting any file system not containing approved binary files as they may be incompatible. Executing files from untrusted file systems increases the opportunity for unprivileged users to attain unauthorized administrative access.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

function include_mount_options_functions {
	:
}

# $1: type of filesystem
# $2: new mount point option
# $3: filesystem of new mount point (used when adding new entry in fstab)
# $4: mount type of new mount point (used when adding new entry in fstab)
function ensure_mount_option_for_vfstype {
        local _vfstype="$1" _new_opt="$2" _filesystem=$3 _type=$4 _vfstype_points=()
        readarray -t _vfstype_points < <(grep -E "[[:space:]]${_vfstype}[[:space:]]" /etc/fstab | awk '{print $2}')

        for _vfstype_point in "${_vfstype_points[@]}"
        do
                ensure_mount_option_in_fstab "$_vfstype_point" "$_new_opt" "$_filesystem" "$_type"
        done
}

# $1: mount point
# $2: new mount point option
# $3: device or virtual string (used when adding new entry in fstab)
# $4: mount type of mount point (used when adding new entry in fstab)
function ensure_mount_option_in_fstab {
	local _mount_point="$1" _new_opt="$2" _device=$3 _type=$4
	local _mount_point_match_regexp="" _previous_mount_opts=""
	_mount_point_match_regexp="$(get_mount_point_regexp "$_mount_point")"

	if [ "$(grep -c "$_mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
		# runtime opts without some automatic kernel/userspace-added defaults
		_previous_mount_opts=$(grep "$_mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
					| sed -E "s/(rw|defaults|seclabel|${_new_opt})(,|$)//g;s/,$//")
		[ "$_previous_mount_opts" ] && _previous_mount_opts+=","
		echo "${_device} ${_mount_point} ${_type} defaults,${_previous_mount_opts}${_new_opt} 0 0" >> /etc/fstab
	elif [ "$(grep "$_mount_point_match_regexp" /etc/fstab | grep -c "$_new_opt")" -eq 0 ]; then
		_previous_mount_opts=$(grep "$_mount_point_match_regexp" /etc/fstab | awk '{print $4}')
		sed -i "s|\(${_mount_point_match_regexp}.*${_previous_mount_opts}\)|\1,${_new_opt}|" /etc/fstab
	fi
}

# $1: mount point
function get_mount_point_regexp {
		printf "[[:space:]]%s[[:space:]]" "$1"
}

# $1: mount point
function assert_mount_point_in_fstab {
	local _mount_point_match_regexp
	_mount_point_match_regexp="$(get_mount_point_regexp "$1")"
	grep "$_mount_point_match_regexp" -q /etc/fstab \
		|| { echo "The mount point '$1' is not even in /etc/fstab, so we can't set up mount options" >&2; return 1; }
}

# $1: mount point
function remove_defaults_from_fstab_if_overriden {
	local _mount_point_match_regexp
	_mount_point_match_regexp="$(get_mount_point_regexp "$1")"
	if grep "$_mount_point_match_regexp" /etc/fstab | grep -q "defaults,"
	then
		sed -i "s|\(${_mount_point_match_regexp}.*\)defaults,|\1|" /etc/fstab
	fi
}

# $1: mount point
function ensure_partition_is_mounted {
	local _mount_point="$1"
	mkdir -p "$_mount_point" || return 1
	if mountpoint -q "$_mount_point"; then
		mount -o remount --target "$_mount_point"
	else
		mount --target "$_mount_point"
	fi
}
include_mount_options_functions

ensure_mount_option_for_vfstype "nfs[4]?" "noexec" "" "nfs4"

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Get nfs and nfs4 mount points, that don't have noexec
  command: findmnt --fstab --types nfs,nfs4 -O nonoexec -n
  register: points_register
  check_mode: false
  changed_when: false
  failed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83103-2
    - DISA-STIG-SLES-12-010820
    - NIST-800-53-AC-6
    - NIST-800-53-AC-6(10)
    - NIST-800-53-AC-6(8)
    - NIST-800-53-CM-6(a)
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - mount_option_noexec_remote_filesystems
    - no_reboot_needed

- name: Add noexec to nfs and nfs4 mount points
  mount:
    path: '{{ item.split()[0] }}'
    src: '{{ item.split()[1] }}'
    fstype: '{{ item.split()[2] }}'
    state: mounted
    opts: '{{ item.split()[3] }},noexec'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - (points_register.stdout | length > 0)
  with_items: '{{ points_register.stdout_lines }}'
  tags:
    - CCE-83103-2
    - DISA-STIG-SLES-12-010820
    - NIST-800-53-AC-6
    - NIST-800-53-AC-6(10)
    - NIST-800-53-AC-6(8)
    - NIST-800-53-CM-6(a)
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - mount_option_noexec_remote_filesystems
    - no_reboot_needed

Mount Remote Filesystems with nosuidrule

Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of any NFS mounts.

Rationale:

NFS mounts should not present suid binaries to users. Only vendor-supplied suid executables should be installed to their default location on the local filesystem.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

function include_mount_options_functions {
	:
}

# $1: type of filesystem
# $2: new mount point option
# $3: filesystem of new mount point (used when adding new entry in fstab)
# $4: mount type of new mount point (used when adding new entry in fstab)
function ensure_mount_option_for_vfstype {
        local _vfstype="$1" _new_opt="$2" _filesystem=$3 _type=$4 _vfstype_points=()
        readarray -t _vfstype_points < <(grep -E "[[:space:]]${_vfstype}[[:space:]]" /etc/fstab | awk '{print $2}')

        for _vfstype_point in "${_vfstype_points[@]}"
        do
                ensure_mount_option_in_fstab "$_vfstype_point" "$_new_opt" "$_filesystem" "$_type"
        done
}

# $1: mount point
# $2: new mount point option
# $3: device or virtual string (used when adding new entry in fstab)
# $4: mount type of mount point (used when adding new entry in fstab)
function ensure_mount_option_in_fstab {
	local _mount_point="$1" _new_opt="$2" _device=$3 _type=$4
	local _mount_point_match_regexp="" _previous_mount_opts=""
	_mount_point_match_regexp="$(get_mount_point_regexp "$_mount_point")"

	if [ "$(grep -c "$_mount_point_match_regexp" /etc/fstab)" -eq 0 ]; then
		# runtime opts without some automatic kernel/userspace-added defaults
		_previous_mount_opts=$(grep "$_mount_point_match_regexp" /etc/mtab | head -1 |  awk '{print $4}' \
					| sed -E "s/(rw|defaults|seclabel|${_new_opt})(,|$)//g;s/,$//")
		[ "$_previous_mount_opts" ] && _previous_mount_opts+=","
		echo "${_device} ${_mount_point} ${_type} defaults,${_previous_mount_opts}${_new_opt} 0 0" >> /etc/fstab
	elif [ "$(grep "$_mount_point_match_regexp" /etc/fstab | grep -c "$_new_opt")" -eq 0 ]; then
		_previous_mount_opts=$(grep "$_mount_point_match_regexp" /etc/fstab | awk '{print $4}')
		sed -i "s|\(${_mount_point_match_regexp}.*${_previous_mount_opts}\)|\1,${_new_opt}|" /etc/fstab
	fi
}

# $1: mount point
function get_mount_point_regexp {
		printf "[[:space:]]%s[[:space:]]" "$1"
}

# $1: mount point
function assert_mount_point_in_fstab {
	local _mount_point_match_regexp
	_mount_point_match_regexp="$(get_mount_point_regexp "$1")"
	grep "$_mount_point_match_regexp" -q /etc/fstab \
		|| { echo "The mount point '$1' is not even in /etc/fstab, so we can't set up mount options" >&2; return 1; }
}

# $1: mount point
function remove_defaults_from_fstab_if_overriden {
	local _mount_point_match_regexp
	_mount_point_match_regexp="$(get_mount_point_regexp "$1")"
	if grep "$_mount_point_match_regexp" /etc/fstab | grep -q "defaults,"
	then
		sed -i "s|\(${_mount_point_match_regexp}.*\)defaults,|\1|" /etc/fstab
	fi
}

# $1: mount point
function ensure_partition_is_mounted {
	local _mount_point="$1"
	mkdir -p "$_mount_point" || return 1
	if mountpoint -q "$_mount_point"; then
		mount -o remount --target "$_mount_point"
	else
		mount --target "$_mount_point"
	fi
}
include_mount_options_functions

ensure_mount_option_for_vfstype "nfs[4]?" "nosuid" "" "nfs4"

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: Get nfs and nfs4 mount points, that don't have nosuid
  command: findmnt --fstab --types nfs,nfs4 -O nonosuid -n
  register: points_register
  check_mode: false
  changed_when: false
  failed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83102-4
    - DISA-STIG-SLES-12-010810
    - NIST-800-53-AC-6
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM6(a)
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - mount_option_nosuid_remote_filesystems
    - no_reboot_needed

- name: Add nosuid to nfs and nfs4 mount points
  mount:
    path: '{{ item.split()[0] }}'
    src: '{{ item.split()[1] }}'
    fstype: '{{ item.split()[2] }}'
    state: mounted
    opts: '{{ item.split()[3] }},nosuid'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - (points_register.stdout | length > 0)
  with_items: '{{ points_register.stdout_lines }}'
  tags:
    - CCE-83102-4
    - DISA-STIG-SLES-12-010810
    - NIST-800-53-AC-6
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM6(a)
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - mount_option_nosuid_remote_filesystems
    - no_reboot_needed

Network Time Protocolgroup

The Network Time Protocol is used to manage the system clock over a network. Computer clocks are not very accurate, so time will drift unpredictably on unmanaged systems. Central time protocols can be used both to ensure that time is consistent among a network of systems, and that their time is consistent with the outside world.

If every system on a network reliably reports the same time, then it is much easier to correlate log messages in case of an attack. In addition, a number of cryptographic protocols (such as Kerberos) use timestamps to prevent certain types of attacks. If your network does not have synchronized time, these protocols may be unreliable or even unusable.

Depending on the specifics of the network, global time accuracy may be just as important as local synchronization, or not very important at all. If your network is connected to the Internet, using a public timeserver (or one provided by your enterprise) provides globally accurate timestamps which may be essential in investigating or responding to an attack which originated outside of your network.

A typical network setup involves a small number of internal systems operating as NTP servers, and the remainder obtaining time information from those internal servers.

There is a choice between the daemons ntpd and chronyd, which are available from the repositories in the ntp and chrony packages respectively.

The default chronyd daemon can work well when external time references are only intermittently accesible, can perform well even when the network is congested for longer periods of time, can usually synchronize the clock faster and with better time accuracy, and quickly adapts to sudden changes in the rate of the clock, for example, due to changes in the temperature of the crystal oscillator. Chronyd should be considered for all systems which are frequently suspended or otherwise intermittently disconnected and reconnected to a network. Mobile and virtual systems for example.

The ntpd NTP daemon fully supports NTP protocol version 4 (RFC 5905), including broadcast, multicast, manycast clients and servers, and the orphan mode. It also supports extra authentication schemes based on public-key cryptography (RFC 5906). The NTP daemon (ntpd) should be considered for systems which are normally kept permanently on. Systems which are required to use broadcast or multicast IP, or to perform authentication of packets with the Autokey protocol, should consider using ntpd.

Refer to https://docs.fedoraproject.org/en-US/fedora/rawhide/system-administrators-guide/servers/Configuring_NTP_Using_the_chrony_Suite/ for more detailed comparison of features of chronyd and ntpd daemon features respectively, and for further guidance how to choose between the two NTP daemons.

The upstream manual pages at http://chrony.tuxfamily.org/manual.html for chronyd and http://www.ntp.org for ntpd provide additional information on the capabilities and configuration of each of the NTP daemons.

contains 1 rule

Configure Time Service Maxpoll Intervalrule

The maxpoll should be configured to 10 in /etc/ntp.conf or /etc/chrony.conf to continuously poll time servers. To configure maxpoll in /etc/ntp.conf or /etc/chrony.conf add the following:

maxpoll 10

Rationale:

Inaccurate time stamps make it more difficult to correlate events and can lead to an inaccurate analysis. Determining the correct time a particular event occurred on a system is critical when conducting forensic analysis and investigating system events. Sources outside the configured acceptable allowance (drift) may be inaccurate.

Remediation script:
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CCE-83124-8
    - DISA-STIG-SLES-12-030300
    - NIST-800-53-AU-8(1)(a)
    - NIST-800-53-AU-8(1)(b)
    - chronyd_or_ntpd_set_maxpoll
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
- name: XCCDF Value var_time_service_set_maxpoll # promote to variable
  set_fact:
    var_time_service_set_maxpoll: !!str 10
  tags:
    - always

- name: Check that /etc/ntp.conf exist
  stat:
    path: /etc/ntp.conf
  register: ntp_conf_exist_result
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"ntp" in ansible_facts.packages or "chrony" in ansible_facts.packages'
  tags:
    - CCE-83124-8
    - DISA-STIG-SLES-12-030300
    - NIST-800-53-AU-8(1)(a)
    - NIST-800-53-AU-8(1)(b)
    - chronyd_or_ntpd_set_maxpoll
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check that /etc/chrony.conf exist
  stat:
    path: /etc/chrony.conf
  register: chrony_conf_exist_result
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"ntp" in ansible_facts.packages or "chrony" in ansible_facts.packages'
  tags:
    - CCE-83124-8
    - DISA-STIG-SLES-12-030300
    - NIST-800-53-AU-8(1)(a)
    - NIST-800-53-AU-8(1)(b)
    - chronyd_or_ntpd_set_maxpoll
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Update the maxpoll values in /etc/ntp.conf
  lineinfile:
    path: /etc/ntp.conf
    regex: ^(server.*maxpoll) [0-9]+(\s+.*)$
    line: \1 {{ var_time_service_set_maxpoll }}\2
    backrefs: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"ntp" in ansible_facts.packages or "chrony" in ansible_facts.packages'
    - ntp_conf_exist_result.stat.exists
  tags:
    - CCE-83124-8
    - DISA-STIG-SLES-12-030300
    - NIST-800-53-AU-8(1)(a)
    - NIST-800-53-AU-8(1)(b)
    - chronyd_or_ntpd_set_maxpoll
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Update the maxpoll values in /etc/chrony.conf
  lineinfile:
    path: /etc/chrony.conf
    regex: ^(server.*maxpoll) [0-9]+(\s+.*)$
    line: \1 {{ var_time_service_set_maxpoll }}\2
    backrefs: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"ntp" in ansible_facts.packages or "chrony" in ansible_facts.packages'
    - chrony_conf_exist_result.stat.exists
  tags:
    - CCE-83124-8
    - DISA-STIG-SLES-12-030300
    - NIST-800-53-AU-8(1)(a)
    - NIST-800-53-AU-8(1)(b)
    - chronyd_or_ntpd_set_maxpoll
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Set the maxpoll values in /etc/ntp.conf
  lineinfile:
    path: /etc/ntp.conf
    regex: (^server\s+((?!maxpoll).)*)$
    line: \1 maxpoll {{ var_time_service_set_maxpoll }}\n
    backrefs: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"ntp" in ansible_facts.packages or "chrony" in ansible_facts.packages'
    - ntp_conf_exist_result.stat.exists
  tags:
    - CCE-83124-8
    - DISA-STIG-SLES-12-030300
    - NIST-800-53-AU-8(1)(a)
    - NIST-800-53-AU-8(1)(b)
    - chronyd_or_ntpd_set_maxpoll
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Set the maxpoll values in /etc/chrony.conf
  lineinfile:
    path: /etc/chrony.conf
    regex: (^server\s+((?!maxpoll).)*)$
    line: \1 maxpoll {{ var_time_service_set_maxpoll }}\n
    backrefs: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"ntp" in ansible_facts.packages or "chrony" in ansible_facts.packages'
    - chrony_conf_exist_result.stat.exists
  tags:
    - CCE-83124-8
    - DISA-STIG-SLES-12-030300
    - NIST-800-53-AU-8(1)(a)
    - NIST-800-53-AU-8(1)(b)
    - chronyd_or_ntpd_set_maxpoll
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Mail Server Softwaregroup

Mail servers are used to send and receive email over the network. Mail is a very common service, and Mail Transfer Agents (MTAs) are obvious targets of network attack. Ensure that systems are not running MTAs unnecessarily, and configure needed MTAs as defensively as possible.

Very few systems at any site should be configured to directly receive email over the network. Users should instead use mail client programs to retrieve email from a central server that supports protocols such as IMAP or POP3. However, it is normal for most systems to be independently capable of sending email, for instance so that cron jobs can report output to an administrator. Most MTAs, including Postfix, support a submission-only mode in which mail can be sent from the local system to a central site MTA (or directly delivered to a local account), but the system still cannot receive mail directly over a network.

The alternatives program in SUSE Linux Enterprise 12 permits selection of other mail server software (such as Sendmail), but Postfix is the default and is preferred. Postfix was coded with security in mind and can also be more effectively contained by SELinux as its modular design has resulted in separate processes performing specific actions. More information is available on its website, http://www.postfix.org.

contains 1 rule

Configure SMTP For Mail Clientsgroup

This section discusses settings for Postfix in a submission-only e-mail configuration.

contains 1 rule

Configure System to Forward All Mail For The Root Accountrule

Make sure that mails delivered to root user are forwarded to a monitored email address. Make sure that the address system.administrator@mail.mil is a valid email address reachable from the system in question. Use the following command to configure the alias:

$ sudo echo "root: system.administrator@mail.mil" >> /etc/aliases
$ sudo newaliases

Rationale:

A number of system services utilize email messages sent to the root user to notify system administrators of active or impending issues. These messages must be forwarded to at least one monitored email address.

Remediation script:
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then


var_postfix_root_mail_alias="system.administrator@mail.mil"
# Function to replace configuration setting in config file or add the configuration setting if
# it does not exist.
#
# Expects arguments:
#
# config_file:		Configuration file that will be modified
# key:			Configuration option to change
# value:		Value of the configuration option to change
# cce:			The CCE identifier or '@CCENUM@' if no CCE identifier exists
# format:		The printf-like format string that will be given stripped key and value as arguments,
#			so e.g. '%s=%s' will result in key=value subsitution (i.e. without spaces around =)
#
# Optional arugments:
#
# format:		Optional argument to specify the format of how key/value should be
# 			modified/appended in the configuration file. The default is key = value.
#
# Example Call(s):
#
#     With default format of 'key = value':
#     replace_or_append '/etc/sysctl.conf' '^kernel.randomize_va_space' '2' '@CCENUM@'
#
#     With custom key/value format:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' 'disabled' '@CCENUM@' '%s=%s'
#
#     With a variable:
#     replace_or_append '/etc/sysconfig/selinux' '^SELINUX=' $var_selinux_state '@CCENUM@' '%s=%s'
#
function replace_or_append {
  local default_format='%s = %s' case_insensitive_mode=yes sed_case_insensitive_option='' grep_case_insensitive_option=''
  local config_file=$1
  local key=$2
  local value=$3
  local cce=$4
  local format=$5

  if [ "$case_insensitive_mode" = yes ]; then
    sed_case_insensitive_option="i"
    grep_case_insensitive_option="-i"
  fi
  [ -n "$format" ] || format="$default_format"
  # Check sanity of the input
  [ $# -ge "3" ] || { echo "Usage: replace_or_append <config_file_location> <key_to_search> <new_value> [<CCE number or literal '@CCENUM@' if unknown>] [printf-like format, default is '$default_format']" >&2; exit 1; }

  # Test if the config_file is a symbolic link. If so, use --follow-symlinks with sed.
  # Otherwise, regular sed command will do.
  sed_command=('sed' '-i')
  if test -L "$config_file"; then
    sed_command+=('--follow-symlinks')
  fi

  # Test that the cce arg is not empty or does not equal @CCENUM@.
  # If @CCENUM@ exists, it means that there is no CCE assigned.
  if [ -n "$cce" ] && [ "$cce" != '@CCENUM@' ]; then
    cce="${cce}"
  else
    cce="CCE"
  fi

  # Strip any search characters in the key arg so that the key can be replaced without
  # adding any search characters to the config file.
  stripped_key=$(sed 's/[\^=\$,;+]*//g' <<< "$key")

  # shellcheck disable=SC2059
  printf -v formatted_output "$format" "$stripped_key" "$value"

  # If the key exists, change it. Otherwise, add it to the config_file.
  # We search for the key string followed by a word boundary (matched by \>),
  # so if we search for 'setting', 'setting2' won't match.
  if LC_ALL=C grep -q -m 1 $grep_case_insensitive_option -e "${key}\\>" "$config_file"; then
    "${sed_command[@]}" "s/${key}\\>.*/$formatted_output/g$sed_case_insensitive_option" "$config_file"
  else
    # \n is precaution for case where file ends without trailing newline
    printf '\n# Per %s: Set %s in %s\n' "$cce" "$formatted_output" "$config_file" >> "$config_file"
    printf '%s\n' "$formatted_output" >> "$config_file"
  fi
}
replace_or_append '/etc/aliases' '^root' "$var_postfix_root_mail_alias" 'CCE-83031-5' '%s: %s'

newaliases

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Remediation script:
- name: XCCDF Value var_postfix_root_mail_alias # promote to variable
  set_fact:
    var_postfix_root_mail_alias: !!str system.administrator@mail.mil
  tags:
    - always

- name: Make sure that that "/etc/aliases" has a defined value for root
  lineinfile:
    path: /etc/aliases
    line: 'root: {{ var_postfix_root_mail_alias }}'
    regexp: ^(?:[rR][oO][oO][tT]|"[rR][oO][oO][tT]")\s*:\s*(.+)$
    create: true
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-83031-5
    - DISA-STIG-SLES-12-020050
    - NIST-800-53-AU-5(a)
    - NIST-800-53-AU-5.1(ii)
    - configure_strategy
    - low_complexity
    - low_disruption
    - low_severity
    - no_reboot_needed
    - postfix_client_configure_mail_alias
Red Hat and Red Hat Enterprise Linux are either registered trademarks or trademarks of Red Hat, Inc. in the United States and other countries. All other names are registered trademarks or trademarks of their respective companies.