Guide to the Secure Configuration of AlmaLinux 9

with profile [DRAFT] Unclassified Information in Non-federal Information Systems and Organizations (NIST 800-171)
From NIST 800-171, Section 2.2: Security requirements for protecting the confidentiality of CUI in nonfederal information systems and organizations have a well-defined structure that consists of: (i) a basic security requirements section; (ii) a derived security requirements section. The basic security requirements are obtained from FIPS Publication 200, which provides the high-level and fundamental security requirements for federal information and information systems. The derived security requirements, which supplement the basic security requirements, are taken from the security controls in NIST Special Publication 800-53. This profile configures AlmaLinux 9 to the NIST Special Publication 800-53 controls identified for securing Controlled Unclassified Information (CUI)."
This guide presents a catalog of security-relevant configuration settings for AlmaLinux 9. 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 Information

Profile Title[DRAFT] Unclassified Information in Non-federal Information Systems and Organizations (NIST 800-171)
Profile IDxccdf_org.ssgproject.content_profile_cui

CPE Platforms

  • cpe:/o:almalinux:almalinux:9

Revision History

Current version: 0.1.60

  • draft (as of 2022-05-24)

Table of Contents

  1. System Settings
    1. Installing and Maintaining Software
    2. Account and Access Control
    3. System Accounting with auditd
    4. GRUB2 bootloader configuration
    5. zIPL bootloader configuration
    6. Configure Syslog
    7. Network Configuration and Firewalls
    8. File Permissions and Masks
    9. SELinux
  2. Services
    1. Base Services
    2. Application Whitelisting Daemon
    3. Kerberos
    4. Mail Server Software
    5. NFS and RPC
    6. Network Time Protocol
    7. SSH Server
    8. USBGuard daemon

Checklist

Group   Guide to the Secure Configuration of AlmaLinux 9   Group contains 62 groups and 193 rules
Group   System Settings   Group contains 50 groups and 169 rules
[ref]   Contains rules that check correct system settings.
Group   Installing and Maintaining Software   Group contains 9 groups and 31 rules
[ref]   The following sections contain information on security-relevant choices during the initial operating system installation process and the setup of software updates.
Group   System and Software Integrity   Group contains 4 groups and 10 rules
[ref]   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.
Group   Software Integrity Checking   Group contains 1 group and 1 rule
[ref]   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.
Group   Verify Integrity with AIDE   Group contains 1 rule
[ref]   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.

Rule   Install AIDE   [ref]

The aide package can be installed with the following command:
$ sudo dnf install aide
Rationale:
The AIDE package must be installed if it is to be available for integrity checking.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_aide_installed
Identifiers and References

References:  BP28(R51), 1, 11, 12, 13, 14, 15, 16, 2, 3, 5, 7, 8, 9, 5.10.1.3, APO01.06, BAI01.06, BAI02.01, BAI03.05, BAI06.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS03.05, DSS04.07, DSS05.02, DSS05.03, DSS05.05, DSS05.07, DSS06.02, DSS06.06, CCI-002696, CCI-002699, CCI-001744, 4.3.4.3.2, 4.3.4.3.3, 4.3.4.4.4, SR 3.1, SR 3.3, SR 3.4, SR 3.8, SR 4.1, SR 6.2, SR 7.6, 1034, 1288, 1341, 1417, A.11.2.4, A.12.1.2, A.12.2.1, A.12.4.1, A.12.5.1, A.12.6.2, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.14.2.7, A.15.2.1, A.8.2.3, CM-6(a), DE.CM-1, DE.CM-7, PR.DS-1, PR.DS-6, PR.DS-8, PR.IP-1, PR.IP-3, Req-11.5, SRG-OS-000363-GPOS-00150, SRG-OS-000445-GPOS-00199


Complexity:low
Disruption:low
Strategy:enable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if ! rpm -q --quiet "aide" ; then
    dnf install -y "aide"
fi

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

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure aide is installed
  package:
    name: aide
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CJIS-5.10.1.3
    - 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

Complexity:low
Disruption:low
Strategy:enable
include install_aide

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

Complexity:low
Disruption:low
Strategy:enable

package --add=aide


[[packages]]
name = "aide"
version = "*"
Group   Federal Information Processing Standard (FIPS)   Group contains 2 rules
[ref]   The Federal Information Processing Standard (FIPS) is a computer security standard which is developed by the U.S. Government and industry working groups to validate the quality of cryptographic modules. The FIPS standard provides four security levels to ensure adequate coverage of different industries, implementation of cryptographic modules, and organizational sizes and requirements.

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 AlmaLinux 9.

See http://csrc.nist.gov/publications/PubsFIPS.html for more information.

Rule   Enable Dracut FIPS Module   [ref]

To enable FIPS mode, run the following command:
fips-mode-setup --enable
To enable FIPS, the system requires that the fips module is added in dracut configuration. Check if /etc/dracut.conf.d/40-fips.conf contain add_dracutmodules+=" fips "
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:
Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to protect data. The operating system must implement cryptographic modules adhering to the higher standards approved by the federal government since this provides assurance they have been tested and validated.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_enable_dracut_fips_module
Identifiers and References

References:  CCI-000068, CCI-000803, CCI-002450, 1446, CIP-003-8 R4.2, CIP-007-3 R5.1, SC-12(2), SC-12(3), IA-7, SC-13, CM-6(a), SC-12, FCS_RBG_EXT.1, SRG-OS-000478-GPOS-00223, SRG-OS-000120-VMM-000600, SRG-OS-000478-VMM-001980, SRG-OS-000396-VMM-001590

Rule   Enable FIPS Mode   [ref]

To enable FIPS mode, run the following command:
fips-mode-setup --enable

The fips-mode-setup command will configure the system in FIPS mode by automatically configuring the following:
  • Setting the kernel FIPS mode flag (/proc/sys/crypto/fips_enabled) to 1
  • Creating /etc/system-fips
  • Setting the system crypto policy in /etc/crypto-policies/config to FIPS:OSPP
  • Loading the Dracut fips module
Warning:  The system needs to be rebooted for these changes to take effect.
Warning:  This rule DOES NOT CHECK if the components of the operating system are FIPS certified. You can find the list of FIPS certified modules at https://csrc.nist.gov/projects/cryptographic-module-validation-program/validated-modules/search. This rule checks if the system is running in FIPS mode. See the rule description for more information about what it means.
Rationale:
Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to protect data. The operating system must implement cryptographic modules adhering to the higher standards approved by the federal government since this provides assurance they have been tested and validated.
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_enable_fips_mode
Identifiers and References

References:  CCI-000068, CCI-000803, CCI-002450, 1446, CIP-003-8 R4.2, CIP-007-3 R5.1, SC-12(2), SC-12(3), IA-7, SC-13, CM-6(a), SC-12, FCS_COP.1(1), FCS_COP.1(2), FCS_COP.1(3), FCS_COP.1(4), FCS_CKM.1, FCS_CKM.2, FCS_TLSC_EXT.1, FCS_RBG_EXT.1, SRG-OS-000478-GPOS-00223, SRG-OS-000396-GPOS-00176, SRG-OS-000120-VMM-000600, SRG-OS-000478-VMM-001980, SRG-OS-000396-VMM-001590


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

var_system_crypto_policy='FIPS:OSPP'


fips-mode-setup --enable

stderr_of_call=$(update-crypto-policies --set ${var_system_crypto_policy} 2>&1 > /dev/null)
rc=$?

if test "$rc" = 127; then
	echo "$stderr_of_call" >&2
	echo "Make sure that the script is installed on the remediated system." >&2
	echo "See output of the 'dnf provides update-crypto-policies' command" >&2
	echo "to see what package to (re)install" >&2

	false  # end with an error code
elif test "$rc" != 0; then
	echo "Error invoking the update-crypto-policies script: $stderr_of_call" >&2
	false  # end with an error code
fi

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Group   System Cryptographic Policies   Group contains 7 rules
[ref]   Linux has the capability to centrally configure cryptographic polices. The command update-crypto-policies is used to set the policy applicable for the various cryptographic back-ends, such as SSL/TLS libraries. The configured cryptographic policies will be the default policy used by these backends unless the application user configures them otherwise. When the system has been configured to use the centralized cryptographic policies, the administrator is assured that any application that utilizes the supported backends will follow a policy that adheres to the configured profile. Currently the supported backends are:
  • GnuTLS library
  • OpenSSL library
  • NSS library
  • OpenJDK
  • Libkrb5
  • BIND
  • OpenSSH
Applications and languages which rely on any of these backends will follow the system policies as well. Examples are apache httpd, nginx, php, and others.

Rule   Install crypto-policies package   [ref]

The crypto-policies package can be installed with the following command:
$ sudo dnf install crypto-policies
Rationale:
Centralized cryptographic policies simplify applying secure ciphers across an operating system and the applications that run on that operating system. Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to protect data.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_crypto-policies_installed
Identifiers and References

References:  FCS_COP.1(1), FCS_COP.1(2), FCS_COP.1(3), FCS_COP.1(4), FCS_CKM.1, FCS_CKM.2, FCS_TLSC_EXT.1, SRG-OS-000396-GPOS-00176, SRG-OS-000393-GPOS-00173, SRG-OS-000394-GPOS-00174


Complexity:low
Disruption:low
Strategy:enable

if ! rpm -q --quiet "crypto-policies" ; then
    dnf install -y "crypto-policies"
fi

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure crypto-policies is installed
  package:
    name: crypto-policies
    state: present
  tags:
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_crypto-policies_installed

Complexity:low
Disruption:low
Strategy:enable
include install_crypto-policies

class install_crypto-policies {
  package { 'crypto-policies':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=crypto-policies


[[packages]]
name = "crypto-policies"
version = "*"

Rule   Configure BIND to use System Crypto Policy   [ref]

Crypto Policies provide a centralized control over crypto algorithms usage of many packages. BIND is supported by crypto policy, but the BIND configuration may be set up to ignore it. To check that Crypto Policies settings are configured correctly, ensure that the /etc/named.conf includes the appropriate configuration: In the options section of /etc/named.conf, make sure that the following line is not commented out or superseded by later includes: include "/etc/crypto-policies/back-ends/bind.config";
Rationale:
Overriding the system crypto policy makes the behavior of the BIND service violate expectations, and makes system configuration more fragmented.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_configure_bind_crypto_policy
Identifiers and References

References:  CIP-003-8 R4.2, CIP-007-3 R5.1, SC-13, SC-12(2), SC-12(3), SRG-OS-000423-GPOS-00187, SRG-OS-000426-GPOS-00190



function remediate_bind_crypto_policy() {
	CONFIG_FILE="/etc/named.conf"
	if test -f "$CONFIG_FILE"; then
		sed -i 's|options {|&\n\tinclude "/etc/crypto-policies/back-ends/bind.config";|' "$CONFIG_FILE"
		return 0
	else
		echo "Aborting remediation as '$CONFIG_FILE' was not even found." >&2
		return 1
	fi
}

remediate_bind_crypto_policy

Rule   Configure System Cryptography Policy   [ref]

To configure the system cryptography policy to use ciphers only from the FIPS:OSPP policy, run the following command:
$ sudo update-crypto-policies --set FIPS:OSPP
The rule checks if settings for selected crypto policy are configured as expected. Configuration files in the /etc/crypto-policies/back-ends are either symlinks to correct files provided by Crypto-policies package or they are regular files in case crypto policy customizations are applied. Crypto policies may be customized by crypto policy modules, in which case it is delimited from the base policy using a colon.
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:
Centralized cryptographic policies simplify applying secure ciphers across an operating system and the applications that run on that operating system. Use of weak or untested encryption algorithms undermines the purposes of utilizing encryption to protect data.
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_configure_crypto_policy
Identifiers and References

References:  164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.312(e)(1), 164.312(e)(2)(ii), 1446, CIP-003-8 R4.2, CIP-007-3 R5.1, CIP-007-3 R7.1, AC-17(a), AC-17(2), CM-6(a), MA-4(6), SC-13, SC-12(2), SC-12(3), FCS_COP.1(1), FCS_COP.1(2), FCS_COP.1(3), FCS_COP.1(4), FCS_CKM.1, FCS_CKM.2, FCS_TLSC_EXT.1, SRG-OS-000396-GPOS-00176, SRG-OS-000393-GPOS-00173, SRG-OS-000394-GPOS-00174



var_system_crypto_policy='FIPS:OSPP'


stderr_of_call=$(update-crypto-policies --set ${var_system_crypto_policy} 2>&1 > /dev/null)
rc=$?

if test "$rc" = 127; then
	echo "$stderr_of_call" >&2
	echo "Make sure that the script is installed on the remediated system." >&2
	echo "See output of the 'dnf provides update-crypto-policies' command" >&2
	echo "to see what package to (re)install" >&2

	false  # end with an error code
elif test "$rc" != 0; then
	echo "Error invoking the update-crypto-policies script: $stderr_of_call" >&2
	false  # end with an error code
fi

Complexity:low
Disruption:low
Strategy:restrict
- name: XCCDF Value var_system_crypto_policy # promote to variable
  set_fact:
    var_system_crypto_policy: !!str FIPS:OSPP
  tags:
    - always

- name: Configure System Cryptography Policy
  lineinfile:
    path: /etc/crypto-policies/config
    regexp: ^(?!#)(\S+)$
    line: '{{ var_system_crypto_policy }}'
    create: true
  tags:
    - 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
    - configure_crypto_policy
    - high_severity
    - low_complexity
    - low_disruption
    - no_reboot_needed
    - restrict_strategy

- name: Verify that Crypto Policy is Set (runtime)
  command: /usr/bin/update-crypto-policies --set {{ var_system_crypto_policy }}
  tags:
    - 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
    - configure_crypto_policy
    - high_severity
    - low_complexity
    - low_disruption
    - no_reboot_needed
    - restrict_strategy

Rule   Configure Kerberos to use System Crypto Policy   [ref]

Crypto Policies provide a centralized control over crypto algorithms usage of many packages. Kerberos is supported by crypto policy, but it's configuration may be set up to ignore it. To check that Crypto Policies settings for Kerberos are configured correctly, examine that there is a symlink at /etc/krb5.conf.d/crypto-policies targeting /etc/cypto-policies/back-ends/krb5.config. If the symlink exists, kerberos is configured to use the system-wide crypto policy settings.
Rationale:
Overriding the system crypto policy makes the behavior of Kerberos violate expectations, and makes system configuration more fragmented.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_configure_kerberos_crypto_policy
Identifiers and References

References:  0418, 1055, 1402, CIP-003-8 R4.2, CIP-007-3 R5.1, SC-13, SC-12(2), SC-12(3), SRG-OS-000120-GPOS-00061


Complexity:low
Disruption:low
Reboot:true
Strategy:configure

rm -f /etc/krb5.conf.d/crypto-policies
ln -s /etc/crypto-policies/back-ends/krb5.config /etc/krb5.conf.d/crypto-policies

Complexity:low
Disruption:low
Reboot:true
Strategy:configure
- name: Configure Kerberos to use System Crypto Policy
  file:
    src: /etc/crypto-policies/back-ends/krb5.config
    path: /etc/krb5.conf.d/crypto-policies
    state: link
  tags:
    - NIST-800-53-SC-12(2)
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SC-13
    - configure_kerberos_crypto_policy
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required

Rule   Configure Libreswan to use System Crypto Policy   [ref]

Crypto Policies provide a centralized control over crypto algorithms usage of many packages. Libreswan is supported by system crypto policy, but the Libreswan configuration may be set up to ignore it. To check that Crypto Policies settings are configured correctly, ensure that the /etc/ipsec.conf includes the appropriate configuration file. In /etc/ipsec.conf, make sure that the following line is not commented out or superseded by later includes: include /etc/crypto-policies/back-ends/libreswan.config
Rationale:
Overriding the system crypto policy makes the behavior of the Libreswan service violate expectations, and makes system configuration more fragmented.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_configure_libreswan_crypto_policy
Identifiers and References

References:  CIP-003-8 R4.2, CIP-007-3 R5.1, CM-6(a), MA-4(6), SC-13, SC-12(2), SC-12(3), FCS_IPSEC_EXT.1.4, FCS_IPSEC_EXT.1.6, SRG-OS-000033-GPOS-00014



function remediate_libreswan_crypto_policy() {
    CONFIG_FILE="/etc/ipsec.conf"
    if ! grep -qP "^\s*include\s+/etc/crypto-policies/back-ends/libreswan.config\s*(?:#.*)?$" "$CONFIG_FILE" ; then
        echo 'include /etc/crypto-policies/back-ends/libreswan.config' >> "$CONFIG_FILE"
    fi
    return 0
}

remediate_libreswan_crypto_policy

Complexity:low
Disruption:low
Strategy:restrict
- name: Configure Libreswan to use System Crypto Policy
  lineinfile:
    path: /etc/ipsec.conf
    line: include /etc/crypto-policies/back-ends/libreswan.config
    create: true
  tags:
    - 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
    - configure_libreswan_crypto_policy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Configure OpenSSL library to use System Crypto Policy   [ref]

Crypto Policies provide a centralized control over crypto algorithms usage of many packages. OpenSSL is supported by crypto policy, but the OpenSSL configuration may be set up to ignore it. To check that Crypto Policies settings are configured correctly, you have to examine the OpenSSL config file available under /etc/pki/tls/openssl.cnf. This file has the ini format, and it enables crypto policy support if there is a [ crypto_policy ] section that contains the .include /etc/crypto-policies/back-ends/opensslcnf.config directive.
Rationale:
Overriding the system crypto policy makes the behavior of the Java runtime violates expectations, and makes system configuration more fragmented.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_configure_openssl_crypto_policy
Identifiers and References

References:  CCI-001453, CIP-003-8 R4.2, CIP-007-3 R5.1, CIP-007-3 R7.1, AC-17(a), AC-17(2), CM-6(a), MA-4(6), SC-13, SC-12(2), SC-12(3), SRG-OS-000250-GPOS-00093



OPENSSL_CRYPTO_POLICY_SECTION='[ crypto_policy ]'
OPENSSL_CRYPTO_POLICY_SECTION_REGEX='\[\s*crypto_policy\s*\]'
OPENSSL_CRYPTO_POLICY_INCLUSION='.include /etc/crypto-policies/back-ends/opensslcnf.config'
OPENSSL_CRYPTO_POLICY_INCLUSION_REGEX='^\s*\.include\s*/etc/crypto-policies/back-ends/opensslcnf.config$'

function remediate_openssl_crypto_policy() {
	CONFIG_FILE="/etc/pki/tls/openssl.cnf"
	if test -f "$CONFIG_FILE"; then
		if ! grep -q "^\\s*$OPENSSL_CRYPTO_POLICY_SECTION_REGEX" "$CONFIG_FILE"; then
			printf '\n%s\n\n%s' "$OPENSSL_CRYPTO_POLICY_SECTION" "$OPENSSL_CRYPTO_POLICY_INCLUSION" >> "$CONFIG_FILE"
			return 0
		elif ! grep -q "^\\s*$OPENSSL_CRYPTO_POLICY_INCLUSION_REGEX" "$CONFIG_FILE"; then
			sed -i "s|$OPENSSL_CRYPTO_POLICY_SECTION_REGEX|&\\n\\n$OPENSSL_CRYPTO_POLICY_INCLUSION\\n|" "$CONFIG_FILE"
			return 0
		fi
	else
		echo "Aborting remediation as '$CONFIG_FILE' was not even found." >&2
		return 1
	fi
}

remediate_openssl_crypto_policy

Complexity:low
Disruption:medium
- name: Test for crypto_policy group
  command: grep '^\s*\[\s*crypto_policy\s*]' /etc/pki/tls/openssl.cnf
  register: test_crypto_policy_group
  ignore_errors: true
  changed_when: false
  check_mode: false
  tags:
    - 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
    - configure_openssl_crypto_policy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

- name: Add .include for opensslcnf.config to crypto_policy section
  lineinfile:
    create: true
    insertafter: ^\s*\[\s*crypto_policy\s*]\s*
    line: .include /etc/crypto-policies/back-ends/opensslcnf.config
    path: /etc/pki/tls/openssl.cnf
  when:
    - test_crypto_policy_group.stdout is defined
    - test_crypto_policy_group.stdout | length > 0
  tags:
    - 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
    - configure_openssl_crypto_policy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

- name: Add crypto_policy group and set include opensslcnf.config
  lineinfile:
    create: true
    line: |-
      [crypto_policy]
      .include /etc/crypto-policies/back-ends/opensslcnf.config
    path: /etc/pki/tls/openssl.cnf
  when:
    - test_crypto_policy_group.stdout is defined
    - test_crypto_policy_group.stdout | length < 1
  tags:
    - 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
    - configure_openssl_crypto_policy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy

Rule   Configure SSH to use System Crypto Policy   [ref]

Crypto Policies provide a centralized control over crypto algorithms usage of many packages. SSH is supported by crypto policy, but the SSH configuration may be set up to ignore it. To check that Crypto Policies settings are configured correctly, ensure that the CRYPTO_POLICY variable is either commented or not set at all in the /etc/sysconfig/sshd.
Rationale:
Overriding the system crypto policy makes the behavior of the SSH service violate expectations, and makes system configuration more fragmented.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_configure_ssh_crypto_policy
Identifiers and References

References:  164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.312(e)(1), 164.312(e)(2)(ii), CIP-003-8 R4.2, CIP-007-3 R5.1, CIP-007-3 R7.1, AC-17(a), AC-17(2), CM-6(a), MA-4(6), SC-13, SRG-OS-000250-GPOS-00093



SSH_CONF="/etc/sysconfig/sshd"

sed -i "/^\s*CRYPTO_POLICY.*$/d" $SSH_CONF

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: Configure SSH to use System Crypto Policy
  lineinfile:
    dest: /etc/sysconfig/sshd
    state: absent
    regexp: ^\s*CRYPTO_POLICY.*$
  tags:
    - 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-13
    - configure_ssh_crypto_policy
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
Group   Disk Partitioning   Group contains 5 rules
[ref]   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.

Rule   Ensure /home Located On Separate Partition   [ref]

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.
Severity: 
low
Rule ID:xccdf_org.ssgproject.content_rule_partition_for_home
Identifiers and References

References:  BP28(R12), 12, 15, 8, APO13.01, DSS05.02, CCI-000366, CCI-001208, 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.13.1.1, A.13.2.1, A.14.1.3, CM-6(a), SC-5(2), PR.PT-4, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:high
Strategy:enable

part /home


[[customizations.filesystem]]
mountpoint = "/home"
size = 1073741824

Rule   Ensure /var Located On Separate Partition   [ref]

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.
Severity: 
low
Rule ID:xccdf_org.ssgproject.content_rule_partition_for_var
Identifiers and References

References:  BP28(R12), 12, 15, 8, APO13.01, DSS05.02, CCI-000366, 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.13.1.1, A.13.2.1, A.14.1.3, CM-6(a), SC-5(2), PR.PT-4, SRG-OS-000480-GPOS-00227, SRG-OS-000341-VMM-001220


Complexity:low
Disruption:high
Strategy:enable

part /var


[[customizations.filesystem]]
mountpoint = "/var"
size = 3221225472

Rule   Ensure /var/log Located On Separate Partition   [ref]

System logs are stored in the /var/log directory. Ensure that /var/log has its own partition or logical volume at installation time, or migrate it using LVM.
Rationale:
Placing /var/log in its own partition enables better separation between log files and other files in /var/.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_partition_for_var_log
Identifiers and References

References:  BP28(R12), BP28(R47), 1, 12, 14, 15, 16, 3, 5, 6, 8, APO11.04, APO13.01, BAI03.05, DSS05.02, DSS05.04, DSS05.07, MEA02.01, CCI-000366, 4.3.3.3.9, 4.3.3.5.8, 4.3.4.4.7, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 2.10, SR 2.11, SR 2.12, 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.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, CIP-007-3 R6.5, CM-6(a), AU-4, SC-5(2), PR.PT-1, PR.PT-4, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:high
Strategy:enable

part /var/log


[[customizations.filesystem]]
mountpoint = "/var/log"
size = 5368709120

Rule   Ensure /var/log/audit Located On Separate Partition   [ref]

Audit logs are stored in the /var/log/audit directory. Ensure that /var/log/audit has its own partition or logical volume at installation time, or migrate it 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.
Severity: 
low
Rule ID:xccdf_org.ssgproject.content_rule_partition_for_var_log_audit
Identifiers and References

References:  BP28(R43), 1, 12, 13, 14, 15, 16, 2, 3, 5, 6, 8, APO11.04, APO13.01, BAI03.05, BAI04.04, DSS05.02, DSS05.04, DSS05.07, MEA02.01, CCI-000366, CCI-001849, 164.312(a)(2)(ii), 4.3.3.3.9, 4.3.3.5.8, 4.3.4.4.7, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 2.10, SR 2.11, SR 2.12, 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.2, SR 7.6, A.12.1.3, 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.17.2.1, CIP-007-3 R6.5, CM-6(a), AU-4, SC-5(2), PR.DS-4, PR.PT-1, PR.PT-4, SRG-OS-000341-GPOS-00132, SRG-OS-000480-GPOS-00227, SRG-OS-000341-VMM-001220


Complexity:low
Disruption:high
Strategy:enable

part /var/log/audit


[[customizations.filesystem]]
mountpoint = "/var/log/audit"
size = 10737418240

Rule   Ensure /var/tmp Located On Separate Partition   [ref]

The /var/tmp directory is a world-writable directory used for temporary file storage. Ensure it has its own partition or logical volume at installation time, or migrate it using LVM.
Rationale:
The /var/tmp partition is used as temporary storage by many programs. Placing /var/tmp in its own partition enables the setting of more restrictive mount options, which can help protect programs which use it.
Severity: 
low
Rule ID:xccdf_org.ssgproject.content_rule_partition_for_var_tmp
Identifiers and References

References:  BP28(R12), SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:high
Strategy:enable

part /var/tmp


[[customizations.filesystem]]
mountpoint = "/var/tmp"
size = 1073741824
Group   Sudo   Group contains 1 rule
[ref]   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.

Rule   Install sudo Package   [ref]

The sudo package can be installed with the following command:
$ sudo dnf install sudo
Rationale:
sudo is a program designed to allow a system administrator to give limited root privileges to users and log root activity. The basic philosophy is to give as few privileges as possible but still allow system users to get their work done.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_sudo_installed
Identifiers and References

References:  BP28(R19), 1382, 1384, 1386, CM-6(a), SRG-OS-000324-GPOS-00125


Complexity:low
Disruption:low
Strategy:enable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if ! rpm -q --quiet "sudo" ; then
    dnf install -y "sudo"
fi

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

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure sudo is installed
  package:
    name: sudo
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-CM-6(a)
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_sudo_installed

Complexity:low
Disruption:low
Strategy:enable
include install_sudo

class install_sudo {
  package { 'sudo':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=sudo


[[packages]]
name = "sudo"
version = "*"
Group   System Tooling / Utilities   Group contains 7 rules
[ref]   The following checks evaluate the system for recommended base packages -- both for installation and removal.

Rule   Ensure gnutls-utils is installed   [ref]

The gnutls-utils package can be installed with the following command:
$ sudo dnf install gnutls-utils
Rationale:
GnuTLS is a secure communications library implementing the SSL, TLS and DTLS protocols and technologies around them. It provides a simple C language application programming interface (API) to access the secure communications protocols as well as APIs to parse and write X.509, PKCS #12, OpenPGP and other required structures. This package contains command line TLS client and server and certificate manipulation tools.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_gnutls-utils_installed
Identifiers and References

References:  FIA_X509_EXT, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:low
Strategy:enable

if ! rpm -q --quiet "gnutls-utils" ; then
    dnf install -y "gnutls-utils"
fi

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure gnutls-utils is installed
  package:
    name: gnutls-utils
    state: present
  tags:
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_gnutls-utils_installed

Complexity:low
Disruption:low
Strategy:enable
include install_gnutls-utils

class install_gnutls-utils {
  package { 'gnutls-utils':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=gnutls-utils


[[packages]]
name = "gnutls-utils"
version = "*"

Rule   Install openscap-scanner Package   [ref]

The openscap-scanner package can be installed with the following command:
$ sudo dnf install openscap-scanner
Rationale:
openscap-scanner contains the oscap command line tool. This tool is a configuration and vulnerability scanner, capable of performing compliance checking using SCAP content.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_openscap-scanner_installed
Identifiers and References

References:  SRG-OS-000480-GPOS-00227, SRG-OS-000191-GPOS-00080


Complexity:low
Disruption:low
Strategy:enable

if ! rpm -q --quiet "openscap-scanner" ; then
    dnf install -y "openscap-scanner"
fi

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure openscap-scanner is installed
  package:
    name: openscap-scanner
    state: present
  tags:
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_openscap-scanner_installed

Complexity:low
Disruption:low
Strategy:enable
include install_openscap-scanner

class install_openscap-scanner {
  package { 'openscap-scanner':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=openscap-scanner


[[packages]]
name = "openscap-scanner"
version = "*"

Rule   Install scap-security-guide Package   [ref]

The scap-security-guide package can be installed with the following command:
$ sudo dnf install scap-security-guide
Rationale:
The scap-security-guide package provides a guide for configuration of the system from the final system's security point of view. The guidance is specified in the Security Content Automation Protocol (SCAP) format and constitutes a catalog of practical hardening advice, linked to government requirements where applicable. The SCAP Security Guide project bridges the gap between generalized policy requirements and specific implementation guidelines. A system administrator can use the oscap CLI tool from the openscap-scanner package, or the SCAP Workbench GUI tool from the scap-workbench package, to verify that the system conforms to provided guidelines. Refer to the scap-security-guide(8) manual page for futher information.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_scap-security-guide_installed
Identifiers and References

References:  SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:low
Strategy:enable

if ! rpm -q --quiet "scap-security-guide" ; then
    dnf install -y "scap-security-guide"
fi

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure scap-security-guide is installed
  package:
    name: scap-security-guide
    state: present
  tags:
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_scap-security-guide_installed

Complexity:low
Disruption:low
Strategy:enable
include install_scap-security-guide

class install_scap-security-guide {
  package { 'scap-security-guide':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=scap-security-guide


[[packages]]
name = "scap-security-guide"
version = "*"

Rule   Install subscription-manager Package   [ref]

The subscription-manager package can be installed with the following command:
$ sudo dnf install subscription-manager
Rationale:
Red Hat Subscription Manager is a local service which tracks installed products and subscriptions on a local system to help manage subscription assignments. It communicates with the backend subscription service (the Customer Portal or an on-premise server such as Subscription Asset Manager) and works with content management tools such as . The package provides, among other things, plugins to interact with repositories and subscriptions from the Red Hat entitlement platform - the subscription-manager and product-id plugins.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_subscription-manager_installed
Identifiers and References

References:  0940, 1144, 1467, 1472, 1483, 1493, 1494, 1495, FPT_TUD_EXT.1, FPT_TUD_EXT.2, SRG-OS-000366-GPOS-00153


Complexity:low
Disruption:low
Strategy:enable

if ! rpm -q --quiet "subscription-manager" ; then
    dnf install -y "subscription-manager"
fi

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure subscription-manager is installed
  package:
    name: subscription-manager
    state: present
  tags:
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_subscription-manager_installed

Complexity:low
Disruption:low
Strategy:enable
include install_subscription-manager

class install_subscription-manager {
  package { 'subscription-manager':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=subscription-manager


[[packages]]
name = "subscription-manager"
version = "*"

Rule   Uninstall gssproxy Package   [ref]

The gssproxy package can be removed with the following command:
$ sudo dnf erase gssproxy
Rationale:
gssproxy is a proxy for GSS API credential handling.
Severity: 
low
Rule ID:xccdf_org.ssgproject.content_rule_package_gssproxy_removed
Identifiers and References

References:  CCI-000381, CCI-000366, SRG-OS-000095-GPOS-00049, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:low
Strategy:disable

# CAUTION: This remediation script will remove gssproxy
#	   from the system, and may remove any packages
#	   that depend on gssproxy. Execute this
#	   remediation AFTER testing on a non-production
#	   system!

if rpm -q --quiet "gssproxy" ; then

    dnf remove -y "gssproxy"

fi

Complexity:low
Disruption:low
Strategy:disable
- name: Ensure gssproxy is removed
  package:
    name: gssproxy
    state: absent
  tags:
    - disable_strategy
    - low_complexity
    - low_disruption
    - low_severity
    - no_reboot_needed
    - package_gssproxy_removed

Complexity:low
Disruption:low
Strategy:disable
include remove_gssproxy

class remove_gssproxy {
  package { 'gssproxy':
    ensure => 'purged',
  }
}

Rule   Uninstall iprutils Package   [ref]

The iprutils package can be removed with the following command:
$ sudo dnf erase iprutils
Rationale:
iprutils provides a suite of utlilities to manage and configure SCSI devices supported by the ipr SCSI storage device driver.
Severity: 
low
Rule ID:xccdf_org.ssgproject.content_rule_package_iprutils_removed
Identifiers and References

References:  CCI-000366, SRG-OS-000095-GPOS-00049, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:low
Strategy:disable

# CAUTION: This remediation script will remove iprutils
#	   from the system, and may remove any packages
#	   that depend on iprutils. Execute this
#	   remediation AFTER testing on a non-production
#	   system!

if rpm -q --quiet "iprutils" ; then

    dnf remove -y "iprutils"

fi

Complexity:low
Disruption:low
Strategy:disable
- name: Ensure iprutils is removed
  package:
    name: iprutils
    state: absent
  tags:
    - disable_strategy
    - low_complexity
    - low_disruption
    - low_severity
    - no_reboot_needed
    - package_iprutils_removed

Complexity:low
Disruption:low
Strategy:disable
include remove_iprutils

class remove_iprutils {
  package { 'iprutils':
    ensure => 'purged',
  }
}

Complexity:low
Disruption:low
Strategy:disable

package --remove=iprutils

Rule   Uninstall krb5-workstation Package   [ref]

The krb5-workstation package can be removed with the following command:
$ sudo dnf erase krb5-workstation
Rationale:
Kerberos is a network authentication system. The krb5-workstation package contains the basic Kerberos programs (kinit, klist, kdestroy, kpasswd). Currently, Kerberos does not utilize FIPS 140-2 cryptography and is not permitted on Government networks, nor is it permitted in many regulatory environments such as HIPAA.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_krb5-workstation_removed
Identifiers and References

References:  CCI-000803, SRG-OS-000095-GPOS-00049, SRG-OS-000120-GPOS-00061


Complexity:low
Disruption:low
Strategy:disable

# CAUTION: This remediation script will remove krb5-workstation
#	   from the system, and may remove any packages
#	   that depend on krb5-workstation. Execute this
#	   remediation AFTER testing on a non-production
#	   system!

if rpm -q --quiet "krb5-workstation" ; then

    dnf remove -y "krb5-workstation"

fi

Complexity:low
Disruption:low
Strategy:disable
- name: Ensure krb5-workstation is removed
  package:
    name: krb5-workstation
    state: absent
  tags:
    - disable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_krb5-workstation_removed

Complexity:low
Disruption:low
Strategy:disable
include remove_krb5-workstation

class remove_krb5-workstation {
  package { 'krb5-workstation':
    ensure => 'purged',
  }
}

Complexity:low
Disruption:low
Strategy:disable

package --remove=krb5-workstation
Group   Updating Software   Group contains 8 rules
[ref]   The dnf 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.

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

Rule   Install dnf-automatic Package   [ref]

The dnf-automatic package can be installed with the following command:
$ sudo dnf install dnf-automatic
Rationale:
dnf-automatic is an alternative command line interface (CLI) to dnf upgrade suitable for automatic, regular execution.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_dnf-automatic_installed
Identifiers and References

References:  BP28(R8), SRG-OS-000191-GPOS-00080


Complexity:low
Disruption:low
Strategy:enable

if ! rpm -q --quiet "dnf-automatic" ; then
    dnf install -y "dnf-automatic"
fi

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure dnf-automatic is installed
  package:
    name: dnf-automatic
    state: present
  tags:
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_dnf-automatic_installed

Complexity:low
Disruption:low
Strategy:enable
include install_dnf-automatic

class install_dnf-automatic {
  package { 'dnf-automatic':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=dnf-automatic


[[packages]]
name = "dnf-automatic"
version = "*"

Rule   Configure dnf-automatic to Install Available Updates Automatically   [ref]

To ensure that the packages comprising the available updates will be automatically installed by dnf-automatic, set apply_updates to yes under [commands] section in /etc/dnf/automatic.conf.
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. The automated installation of updates ensures that recent security patches are applied in a timely manner.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_dnf-automatic_apply_updates
Identifiers and References

References:  BP28(R8), 0940, 1144, 1467, 1472, 1483, 1493, 1494, 1495, SI-2(5), CM-6(a), SI-2(c), FMT_SMF_EXT.1, SRG-OS-000191-GPOS-00080



CONF="/etc/dnf/automatic.conf"
APPLY_UPDATES_REGEX="[[:space:]]*\[commands]([^\n\[]*\n+)+?[[:space:]]*apply_updates"
COMMANDS_REGEX="[[:space:]]*\[commands]"

# Try find [commands] and apply_updates in automatic.conf, if it exists, set
# to yes, if it isn't here, add it, if [commands] doesn't exist, add it there
if grep -qzosP $APPLY_UPDATES_REGEX $CONF; then
    sed -i "s/apply_updates[^(\n)]*/apply_updates = yes/" $CONF
elif grep -qs $COMMANDS_REGEX $CONF; then
    sed -i "/$COMMANDS_REGEX/a apply_updates = yes" $CONF
else
    mkdir -p /etc/dnf
    echo -e "[commands]\napply_updates = yes" >> $CONF
fi

Rule   Configure dnf-automatic to Install Only Security Updates   [ref]

To configure dnf-automatic to install only security updates automatically, set upgrade_type to security under [commands] section in /etc/dnf/automatic.conf.
Rationale:
By default, dnf-automatic installs all available updates. Reducing the amount of updated packages only to updates that were issued as a part of a security advisory increases the system stability.
Severity: 
low
Rule ID:xccdf_org.ssgproject.content_rule_dnf-automatic_security_updates_only
Identifiers and References

References:  BP28(R8), SI-2(5), CM-6(a), SI-2(c), FMT_SMF_EXT.1, SRG-OS-000191-GPOS-00080



CONF="/etc/dnf/automatic.conf"
APPLY_UPDATES_REGEX="[[:space:]]*\[commands]([^\n\[]*\n+)+?[[:space:]]*upgrade_type"
COMMANDS_REGEX="[[:space:]]*\[commands]"

# Try find [commands] and upgrade_type in automatic.conf, if it exists, set
# it to security, if it isn't here, add it, if [commands] doesn't exist,
# add it there
if grep -qzosP $APPLY_UPDATES_REGEX $CONF; then
    sed -i "s/upgrade_type[^(\n)]*/upgrade_type = security/" $CONF
elif grep -qs $COMMANDS_REGEX $CONF; then
    sed -i "/$COMMANDS_REGEX/a upgrade_type = security" $CONF
else
    mkdir -p /etc/dnf
    echo -e "[commands]\nupgrade_type = security" >> $CONF
fi

Rule   Ensure AlmaLinux GPG Key Installed   [ref]

To ensure the system can cryptographically verify base software packages come from AlmaLinux, the AlmaLinux GPG key must properly be installed. To install the AlmaLinux GPG key, run:
$ sudo rpm --import https://repo.almalinux.org/almalinux/RPM-GPG-KEY-AlmaLinux-9
If the system is not connected to the Internet, then install the AlmaLinux GPG key from trusted media such as the AlmaLinux installation CD-ROM or DVD. Assuming the disc is mounted in /media/cdrom, use the following command as the root user to import it into the keyring:
$ sudo rpm --import /media/cdrom/RPM-GPG-KEY
Rationale:
Changes to 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. The AlmaLinux GPG key is necessary to cryptographically verify packages are from AlmaLinux.
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_ensure_almalinux_gpgkey_installed
Identifiers and References

References:  CCI-001749, CM-5(3), SI-7, SC-12, SC-12(3), CM-6(a), CM-11(a), CM-11(b), PR.DS-6, PR.DS-8, PR.IP-1, Req-6.2, SR 3.1, SR 3.3, SR 3.4, SR 3.8, SR 7.6, 4.3.4.3.2, 4.3.4.3.3, 4.3.4.4.4, APO01.06, BAI03.05, BAI06.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS06.02, A.11.2.4, A.12.1.2, A.12.2.1, A.12.5.1, A.12.6.2, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, 11, 2, 3, 9, 1.2.2


readonly ALMALINUX_FINGERPRINT="BF18AC2876178908D6E71267D36CB86CB86B3716"

# Location of the key we would like to import (once it's integrity verified)
readonly ALMALINUX_RELEASE_KEY="/etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9"

RPM_GPG_DIR_PERMS=$(stat -c %a "$(dirname "$ALMALINUX_RELEASE_KEY")")

# Verify /etc/pki/rpm-gpg directory permissions are safe
if [ "${RPM_GPG_DIR_PERMS}" -le "755" ]
then
  # If they are safe, try to obtain fingerprints from the key file
  # (to ensure there won't be e.g. CRC error)
  readarray -t GPG_OUT < <(gpg --with-fingerprint --with-colons "$ALMALINUX_RELEASE_KEY" | grep "^fpr" | cut -d ":" -f 10)
  GPG_RESULT=$?
  # No CRC error, safe to proceed
  if [ "${GPG_RESULT}" -eq "0" ]
  then
    # Filter just hexadecimal fingerprints from gpg's output from
    # processing of a key file
    echo "${GPG_OUT[*]}" | grep -vE "${ALMALINUX_FINGERPRINT}" || {
      # If $ ALMALINUX_RELEASE_KEY file doesn't contain any keys with unknown fingerprint, import it
      rpm --import "${ALMALINUX_RELEASE_KEY}"
    }
  fi
fi

Complexity:medium
Disruption:medium
Strategy:restrict
- name: Read permission of GPG key directory
  stat:
    path: /etc/pki/rpm-gpg/
  register: gpg_key_directory_permission
  check_mode: false
  tags:
    - 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-SC-12
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SI-7
    - PCI-DSS-Req-6.2
    - ensure_almalinux_gpgkey_installed
    - high_severity
    - medium_complexity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy

- name: Read signatures in GPG key
  command: gpg --show-keys --with-fingerprint --with-colons "/etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9"
  args:
    warn: false
  changed_when: false
  register: gpg_fingerprints
  check_mode: false
  tags:
    - 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-SC-12
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SI-7
    - PCI-DSS-Req-6.2
    - ensure_almalinux_gpgkey_installed
    - high_severity
    - medium_complexity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy

- name: Set Fact - Installed GPG Fingerprints
  set_fact:
    gpg_installed_fingerprints: |-
      {{ gpg_fingerprints.stdout | regex_findall('^pub.*
      (?:^fpr[:]*)([0-9A-Fa-f]*)', '\1') | list }}
  tags:
    - 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-SC-12
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SI-7
    - PCI-DSS-Req-6.2
    - ensure_almalinux_gpgkey_installed
    - high_severity
    - medium_complexity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy

- name: Set Fact - Valid fingerprints
  set_fact:
    gpg_valid_fingerprints: ("" "")
  tags:
    - 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-SC-12
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SI-7
    - PCI-DSS-Req-6.2
    - ensure_almalinux_gpgkey_installed
    - high_severity
    - medium_complexity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy

- name: Import AlmaLinux GPG key
  rpm_key:
    state: present
    key: /etc/pki/rpm-gpg/RPM-GPG-KEY-AlmaLinux-9
  when:
    - gpg_key_directory_permission.stat.mode <= '0755'
    - (gpg_installed_fingerprints | difference(gpg_valid_fingerprints)) | length ==
      0
    - gpg_installed_fingerprints | length > 0
    - ansible_distribution == "AlmaLinux"
  tags:
    - 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-SC-12
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SI-7
    - PCI-DSS-Req-6.2
    - ensure_almalinux_gpgkey_installed
    - high_severity
    - medium_complexity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy

Rule   Ensure gpgcheck Enabled In Main dnf Configuration   [ref]

The gpgcheck option controls whether RPM packages' signatures are always checked prior to installation. To configure dnf to check package signatures before installing them, ensure the following line appears in /etc/dnf/dnf.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).
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_ensure_gpgcheck_globally_activated
Identifiers and References

References:  BP28(R15), 11, 2, 3, 9, 5.10.4.1, APO01.06, BAI03.05, BAI06.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS06.02, 3.4.8, CCI-001749, 164.308(a)(1)(ii)(D), 164.312(b), 164.312(c)(1), 164.312(c)(2), 164.312(e)(2)(i), 4.3.4.3.2, 4.3.4.3.3, 4.3.4.4.4, SR 3.1, SR 3.3, SR 3.4, SR 3.8, SR 7.6, A.11.2.4, A.12.1.2, A.12.2.1, A.12.5.1, A.12.6.2, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, CM-5(3), SI-7, SC-12, SC-12(3), CM-6(a), SA-12, SA-12(10), CM-11(a), CM-11(b), PR.DS-6, PR.DS-8, PR.IP-1, FPT_TUD_EXT.1, FPT_TUD_EXT.2, Req-6.2, SRG-OS-000366-GPOS-00153, SRG-OS-000366-VMM-001430, SRG-OS-000370-VMM-001460, SRG-OS-000404-VMM-001650


# Remediation is applicable only in certain platforms
if rpm --quiet -q yum; then

# 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 "/etc/dnf/dnf.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^gpgcheck")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "1"

# 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 -i -e "^gpgcheck\\>" "/etc/dnf/dnf.conf"; then
    "${sed_command[@]}" "s/^gpgcheck\\>.*/$formatted_output/gi" "/etc/dnf/dnf.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/dnf/dnf.conf"
fi

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

Complexity:low
Disruption:medium
Strategy:configure
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CJIS-5.10.4.1
    - 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
    - configure_strategy
    - ensure_gpgcheck_globally_activated
    - high_severity
    - low_complexity
    - medium_disruption
    - no_reboot_needed

- name: Ensure GPG check is globally activated
  ini_file:
    dest: /etc/dnf/dnf.conf
    section: main
    option: gpgcheck
    value: 1
    no_extra_spaces: true
    create: false
  when: '"yum" in ansible_facts.packages'
  tags:
    - CJIS-5.10.4.1
    - 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
    - configure_strategy
    - ensure_gpgcheck_globally_activated
    - high_severity
    - low_complexity
    - medium_disruption
    - no_reboot_needed

Rule   Ensure gpgcheck Enabled for Local Packages   [ref]

dnf should be configured to verify the signature(s) of local packages prior to installation. To configure dnf to verify signatures of local packages, set the localpkg_gpgcheck to 1 in /etc/dnf/dnf.conf.
Rationale:
Changes to any software components can have significant effects to the overall security of the operating system. This requirement ensures the software has not been tampered and 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.
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_ensure_gpgcheck_local_packages
Identifiers and References

References:  BP28(R15), 11, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, 3.4.8, CCI-001749, 164.308(a)(1)(ii)(D), 164.312(b), 164.312(c)(1), 164.312(c)(2), 164.312(e)(2)(i), 4.3.4.3.2, 4.3.4.3.3, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, CM-11(a), CM-11(b), CM-6(a), CM-5(3), SA-12, SA-12(10), PR.IP-1, FPT_TUD_EXT.1, FPT_TUD_EXT.2, SRG-OS-000366-GPOS-00153, SRG-OS-000366-VMM-001430, SRG-OS-000370-VMM-001460, SRG-OS-000404-VMM-001650


# Remediation is applicable only in certain platforms
if rpm --quiet -q yum; then

# 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 "/etc/dnf/dnf.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^localpkg_gpgcheck")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "1"

# 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 -i -e "^localpkg_gpgcheck\\>" "/etc/dnf/dnf.conf"; then
    "${sed_command[@]}" "s/^localpkg_gpgcheck\\>.*/$formatted_output/gi" "/etc/dnf/dnf.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/dnf/dnf.conf"
fi

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

Complexity:low
Disruption:medium
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - 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)
    - ensure_gpgcheck_local_packages
    - high_severity
    - low_complexity
    - medium_disruption
    - no_reboot_needed
    - unknown_strategy

- name: Ensure GPG check Enabled for Local Packages (Yum)
  ini_file:
    dest: /etc/dnf/dnf.conf
    section: main
    option: localpkg_gpgcheck
    value: 1
    no_extra_spaces: true
    create: true
  when: '"yum" in ansible_facts.packages'
  tags:
    - 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)
    - ensure_gpgcheck_local_packages
    - high_severity
    - low_complexity
    - medium_disruption
    - no_reboot_needed
    - unknown_strategy

Rule   Ensure gpgcheck Enabled for All dnf Package Repositories   [ref]

To ensure signature checking is not disabled for any repos, remove any lines from files in /etc/yum.repos.d of the form:
gpgcheck=0
Rationale:
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)."
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_ensure_gpgcheck_never_disabled
Identifiers and References

References:  BP28(R15), 11, 2, 3, 9, 5.10.4.1, APO01.06, BAI03.05, BAI06.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS06.02, 3.4.8, CCI-001749, 164.308(a)(1)(ii)(D), 164.312(b), 164.312(c)(1), 164.312(c)(2), 164.312(e)(2)(i), 4.3.4.3.2, 4.3.4.3.3, 4.3.4.4.4, SR 3.1, SR 3.3, SR 3.4, SR 3.8, SR 7.6, A.11.2.4, A.12.1.2, A.12.2.1, A.12.5.1, A.12.6.2, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, CM-5(3), SI-7, SC-12, SC-12(3), CM-6(a), SA-12, SA-12(10), CM-11(a), CM-11(b), PR.DS-6, PR.DS-8, PR.IP-1, FPT_TUD_EXT.1, FPT_TUD_EXT.2, Req-6.2, SRG-OS-000366-GPOS-00153, SRG-OS-000366-VMM-001430, SRG-OS-000370-VMM-001460, SRG-OS-000404-VMM-001650


sed -i 's/gpgcheck\s*=.*/gpgcheck=1/g' /etc/yum.repos.d/*

Complexity:low
Disruption:medium
Strategy:enable
- name: Grep for dnf repo section names
  shell: |
    set -o pipefail
    grep -HEr '^\[.+\]' -r /etc/yum.repos.d/
  register: repo_grep_results
  ignore_errors: true
  changed_when: false
  tags:
    - CJIS-5.10.4.1
    - 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
    - enable_strategy
    - ensure_gpgcheck_never_disabled
    - high_severity
    - low_complexity
    - medium_disruption
    - no_reboot_needed

- name: Set gpgcheck=1 for each dnf repo
  ini_file:
    path: '{{ item[0] }}'
    section: '{{ item[1] }}'
    option: gpgcheck
    value: '1'
    no_extra_spaces: true
  loop: '{{ repo_grep_results.stdout | regex_findall( ''(.+\.repo):\[(.+)\]\n?'' )
    }}'
  tags:
    - CJIS-5.10.4.1
    - 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
    - enable_strategy
    - ensure_gpgcheck_never_disabled
    - high_severity
    - low_complexity
    - medium_disruption
    - no_reboot_needed

Rule   Enable dnf-automatic Timer   [ref]

The dnf-automatic timer can be enabled with the following command:
$ sudo systemctl enable dnf-automatic.timer
Rationale:
The dnf-automatic is an alternative command line interface (CLI) to dnf upgrade with specific facilities to make it suitable to be executed automatically and regularly from systemd timers, cron jobs and similar. The tool is controlled by dnf-automatic.timer SystemD timer.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_timer_dnf-automatic_enabled
Identifiers and References

References:  BP28(R8), SI-2(5), CM-6(a), SI-2(c), FMT_SMF_EXT.1, SRG-OS-000191-GPOS-00080


Complexity:low
Disruption:low
Strategy:enable

SYSTEMCTL_EXEC='/usr/bin/systemctl'
"$SYSTEMCTL_EXEC" start 'dnf-automatic.timer'
"$SYSTEMCTL_EXEC" enable 'dnf-automatic.timer'

Complexity:low
Disruption:low
Strategy:enable
- name: Enable timer dnf-automatic
  block:

    - name: Gather the package facts
      package_facts:
        manager: auto

    - name: Enable timer dnf-automatic
      systemd:
        name: dnf-automatic.timer
        enabled: 'yes'
        state: started
      when:
        - '"dnf-automatic" in ansible_facts.packages'
  tags:
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SI-2(5)
    - NIST-800-53-SI-2(c)
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - timer_dnf-automatic_enabled
Group   Account and Access Control   Group contains 13 groups and 30 rules
[ref]   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 AlmaLinux 9.
Group   Protect Accounts by Configuring PAM   Group contains 3 groups and 12 rules
[ref]   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.
Group   Set Lockouts for Failed Password Attempts   Group contains 4 rules
[ref]   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.

Rule   Limit Password Reuse   [ref]

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

In the file /etc/pam.d/system-auth, append remember=5 to the line which refers to the pam_unix.so or pam_pwhistory.somodule, as shown below:
  • for the pam_unix.so case:
    password sufficient pam_unix.so ...existing_options... remember=5
  • for the pam_pwhistory.so case:
    password requisite pam_pwhistory.so ...existing_options... remember=5
The DoD STIG requirement is 5 passwords.
Warning:  If the system relies on authselect tool to manage PAM settings, the remediation will also use authselect tool. However, if any manual modification was made in PAM files, the authselect integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will be shown in the remediation report.
Rationale:
Preventing re-use of previous passwords helps ensure that a compromised password is not re-used by a user.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_password_pam_unix_remember
Identifiers and References

References:  BP28(R18), 1, 12, 15, 16, 5, 5.6.2.1.1, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 3.5.8, CCI-000200, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 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.2, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, A.18.1.4, A.7.1.1, 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.2, A.9.4.3, IA-5(f), IA-5(1)(e), PR.AC-1, PR.AC-6, PR.AC-7, Req-8.2.5, SRG-OS-000077-GPOS-00045, SRG-OS-000077-VMM-000440


# Remediation is applicable only in certain platforms
if rpm --quiet -q pam; then

var_password_pam_unix_remember='5'


if [ -f /usr/bin/authselect ]; then
    if authselect check; then
        CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
        # Standard profiles delivered with authselect should not be modified.
        # If not already in use, a custom profile is created preserving the enabled features.
        if [[ ! $CURRENT_PROFILE == custom/* ]]; then
            ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
            authselect create-profile hardening -b $CURRENT_PROFILE
            CURRENT_PROFILE="custom/hardening"
            # Ensure a backup before changing the profile
            authselect apply-changes -b --backup=before-pwhistory-hardening.backup
            authselect select $CURRENT_PROFILE
            for feature in $ENABLED_FEATURES; do
                authselect enable-feature $feature;
            done
        fi
        # Include the desired configuration in the custom profile
        CUSTOM_SYSTEM_AUTH="/etc/authselect/$CURRENT_PROFILE/system-auth"
        CUSTOM_PASSWORD_AUTH="/etc/authselect/$CURRENT_PROFILE/password-auth"
        for custom_pam_file in $CUSTOM_SYSTEM_AUTH $CUSTOM_PASSWORD_AUTH; do
            if ! $(grep -q "^[^#].*pam_pwhistory.so.*remember=" $custom_pam_file); then
                sed -i --follow-symlinks "/^password.*requisite.*pam_pwquality.so/a password    requisite     pam_pwhistory.so remember=$var_password_pam_unix_remember use_authtok" $custom_pam_file
            else
                sed -i --follow-symlinks "s/\(.*pam_pwhistory.so.*remember=\)[[:digit:]]\+\s\(.*\)/\1$var_password_pam_unix_remember \2/g" $custom_pam_file
            fi
        done
        authselect apply-changes -b --backup=after-pwhistory-hardening.backup
    else
        echo "
authselect integrity check failed. Remediation aborted!
This remediation could not be applied because the authselect profile is not intact.
It is not recommended to manually edit the PAM files when authselect is available
In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
        false
    fi
else
    
    AUTH_FILES[0]="/etc/pam.d/system-auth"
    
    AUTH_FILES[1]="/etc/pam.d/password-auth"

    for pamFile in "${AUTH_FILES[@]}"; do
        if grep -q "pam_unix.so.*" $pamFile; then
            if [ -e "$pamFile" ] ; then
    valueRegex="$var_password_pam_unix_remember" defaultValue="$var_password_pam_unix_remember"
    # 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 the value for 'option' if one exists but does not match 'valueRegex'
    if grep -q -P "^\\s*password\\s+sufficient\\s+pam_unix.so(\\s.+)?\\s+remember(?"'!'"${valueRegex}(\\s|\$))" < "$pamFile" ; then
        sed --follow-symlinks -i -E -e "s/^(\\s*password\\s+sufficient\\s+pam_unix.so(\\s.+)?\\s)remember=[^[:space:]]*/\\1remember${defaultValue}/" "$pamFile"

    # add 'option=default' if option is not set
    elif grep -q -E "^\\s*password\\s+sufficient\\s+pam_unix.so" < "$pamFile" &&
            grep    -E "^\\s*password\\s+sufficient\\s+pam_unix.so" < "$pamFile" | grep -q -E -v "\\sremember(=|\\s|\$)" ; then

        sed --follow-symlinks -i -E -e "s/^(\\s*password\\s+sufficient\\s+pam_unix.so[^\\n]*)/\\1 remember${defaultValue}/" "$pamFile"
    # add a new entry if none exists
    elif ! grep -q -P "^\\s*password\\s+sufficient\\s+pam_unix.so(\\s.+)?\\s+remember${valueRegex}(\\s|\$)" < "$pamFile" ; then
        echo "password sufficient pam_unix.so remember${defaultValue}" >> "$pamFile"
    fi
else
    echo "$pamFile doesn't exist" >&2
fi
        fi
        if grep -q "pam_pwhistory.so.*" $pamFile; then
            if [ -e "$pamFile" ] ; then
    valueRegex="$var_password_pam_unix_remember" defaultValue="$var_password_pam_unix_remember"
    # 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 the value for 'option' if one exists but does not match 'valueRegex'
    if grep -q -P "^\\s*password\\s+required\\s+pam_pwhistory.so(\\s.+)?\\s+remember(?"'!'"${valueRegex}(\\s|\$))" < "$pamFile" ; then
        sed --follow-symlinks -i -E -e "s/^(\\s*password\\s+required\\s+pam_pwhistory.so(\\s.+)?\\s)remember=[^[:space:]]*/\\1remember${defaultValue}/" "$pamFile"

    # add 'option=default' if option is not set
    elif grep -q -E "^\\s*password\\s+required\\s+pam_pwhistory.so" < "$pamFile" &&
            grep    -E "^\\s*password\\s+required\\s+pam_pwhistory.so" < "$pamFile" | grep -q -E -v "\\sremember(=|\\s|\$)" ; then

        sed --follow-symlinks -i -E -e "s/^(\\s*password\\s+required\\s+pam_pwhistory.so[^\\n]*)/\\1 remember${defaultValue}/" "$pamFile"
    # add a new entry if none exists
    elif ! grep -q -P "^\\s*password\\s+required\\s+pam_pwhistory.so(\\s.+)?\\s+remember${valueRegex}(\\s|\$)" < "$pamFile" ; then
        echo "password required pam_pwhistory.so remember${defaultValue}" >> "$pamFile"
    fi
else
    echo "$pamFile doesn't exist" >&2
fi
        fi
    done
fi

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

Complexity:low
Disruption:medium
Strategy:configure
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
- name: XCCDF Value var_password_pam_unix_remember # promote to variable
  set_fact:
    var_password_pam_unix_remember: !!str 5
  tags:
    - always

- name: Check if system relies on authselect
  ansible.builtin.stat:
    path: /usr/bin/authselect
  register: result_authselect_present
  when: '"pam" in ansible_facts.packages'
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

- name: Check the integrity of the current authselect profile
  ansible.builtin.command:
    cmd: authselect check
  register: result_authselect_check_cmd
  changed_when: false
  ignore_errors: true
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_present.stat.exists
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

- name: Informative message based on the authselect integrity check result
  ansible.builtin.assert:
    that:
      - result_authselect_check_cmd is success
    fail_msg:
      - authselect integrity check failed. Remediation aborted!
      - This remediation could not be applied because the authselect profile is not
        intact.
      - It is not recommended to manually edit the PAM files when authselect is available
      - In cases where the default authselect profile does not cover a specific demand,
        a custom authselect profile is recommended.
    success_msg:
      - authselect integrity check passed
  when: '"pam" in ansible_facts.packages'
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

- name: Get authselect current profile
  ansible.builtin.shell:
    cmd: authselect current -r | awk '{ print $1 }'
  register: result_authselect_profile
  changed_when: false
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_present.stat.exists
    - result_authselect_check_cmd is success
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

- name: Define the current authselect profile as a local fact
  ansible.builtin.set_fact:
    authselect_current_profile: '{{ result_authselect_profile.stdout }}'
    authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_profile is not skipped
    - result_authselect_profile.stdout is match("custom/")
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

- name: Define the new authselect custom profile as a local fact
  ansible.builtin.set_fact:
    authselect_current_profile: '{{ result_authselect_profile.stdout }}'
    authselect_custom_profile: custom/hardening
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_profile is not skipped
    - result_authselect_profile.stdout is not match("custom/")
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

- name: Get authselect current features to also enable them in the custom profile
  ansible.builtin.shell:
    cmd: authselect current | tail -n+3 | awk '{ print $2 }'
  register: result_authselect_features
  changed_when: false
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_profile is not skipped
    - authselect_current_profile is not match("custom/")
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

- name: Check if any custom profile with the same name was already created in the
    past
  ansible.builtin.stat:
    path: /etc/authselect/{{ authselect_custom_profile }}
  register: result_authselect_custom_profile_present
  changed_when: false
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_present.stat.exists
    - authselect_current_profile is not match("custom/")
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

- name: Create a custom profile based on the current profile
  ansible.builtin.command:
    cmd: authselect create-profile hardening -b sssd
  register: result_authselect_create_profile
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_present.stat.exists
    - result_authselect_check_cmd is success
    - authselect_current_profile is not match("custom/")
    - not result_authselect_custom_profile_present.stat.exists
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

- name: Ensure the desired configuration is updated in the custom profile
  ansible.builtin.replace:
    dest: '{{ item }}'
    regexp: (.*pam_pwhistory.so.*remember=)(\S+)(.*)$
    replace: \g<1>{{ var_password_pam_unix_remember }}\g<3>
  loop:
    - /etc/authselect/{{ authselect_custom_profile }}/system-auth
    - /etc/authselect/{{ authselect_custom_profile }}/password-auth
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_profile is not skipped
    - authselect_custom_profile is match("custom/")
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

- name: Ensure the desired configuration in present in the custom profile
  ansible.builtin.lineinfile:
    dest: '{{ item }}'
    insertafter: ^password.*requisite.*pam_pwquality.so.*
    line: password    requisite     pam_pwhistory.so remember={{ var_password_pam_unix_remember
      }} use_authtok
  loop:
    - /etc/authselect/{{ authselect_custom_profile }}/system-auth
    - /etc/authselect/{{ authselect_custom_profile }}/password-auth
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_profile is not skipped
    - authselect_custom_profile is match("custom/")
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

- name: Ensure a backup of current authselect profile before select the custom profile
  ansible.builtin.command:
    cmd: authselect apply-changes -b --backup=before-pwhistory-hardening.backup
  register: result_authselect_backup
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_check_cmd is success
    - result_authselect_profile is not skipped
    - authselect_current_profile is not match("custom/")
    - authselect_custom_profile is not match(authselect_current_profile)
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

- name: Ensure the custom profile is selected
  ansible.builtin.command:
    cmd: authselect select {{ authselect_custom_profile }} --force
  register: result_pam_authselect_select_profile
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_check_cmd is success
    - result_authselect_profile is not skipped
    - authselect_current_profile is not match("custom/")
    - authselect_custom_profile is not match(authselect_current_profile)
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

- name: Restore the authselect features in the custom profile
  ansible.builtin.command:
    cmd: authselect enable-feature {{ item }}
  register: result_pam_authselect_select_features
  loop: '{{ result_authselect_features.stdout_lines }}'
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_profile is not skipped
    - result_authselect_features is not skipped
    - result_pam_authselect_select_profile is not skipped
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

- name: Ensure the custom profile changes are applied
  ansible.builtin.command:
    cmd: authselect apply-changes -b --backup=after-pwhistory-hardening.backup
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_check_cmd is success
    - result_authselect_profile is not skipped
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

- name: Do not allow users to reuse recent passwords - system-auth (change)
  replace:
    dest: /etc/pam.d/system-auth
    regexp: ^(password\s+sufficient\s+pam_unix\.so\s.*remember\s*=\s*)(\S+)(.*)$
    replace: \g<1>{{ var_password_pam_unix_remember }}\g<3>
  when:
    - '"pam" in ansible_facts.packages'
    - not result_authselect_present.stat.exists
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

- name: Do not allow users to reuse recent passwords - system-auth (add)
  replace:
    dest: /etc/pam.d/system-auth
    regexp: ^password\s+sufficient\s+pam_unix\.so\s(?!.*remember\s*=\s*).*$
    replace: \g<0> remember={{ var_password_pam_unix_remember }}
  when:
    - '"pam" in ansible_facts.packages'
    - not result_authselect_present.stat.exists
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

- name: Do not allow users to reuse recent passwords - system-auth (change)
  replace:
    dest: /etc/pam.d/system-auth
    regexp: ^(password\s+(?:(?:requisite)|(?:required))\s+pam_pwhistory\.so\s.*remember\s*=\s*)(\S+)(.*)$
    replace: \g<1>{{ var_password_pam_unix_remember }}\g<3>
  when:
    - '"pam" in ansible_facts.packages'
    - not result_authselect_present.stat.exists
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

- name: Do not allow users to reuse recent passwords - system-auth (add)
  replace:
    dest: /etc/pam.d/system-auth
    regexp: ^password\s+(?:(?:requisite)|(?:required))\s+pam_pwhistory\.so\s(?!.*remember\s*=\s*).*$
    replace: \g<0> remember={{ var_password_pam_unix_remember }}
  when:
    - '"pam" in ansible_facts.packages'
    - not result_authselect_present.stat.exists
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-171-3.5.8
    - NIST-800-53-IA-5(1)(e)
    - NIST-800-53-IA-5(f)
    - PCI-DSS-Req-8.2.5
    - accounts_password_pam_unix_remember
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

Rule   Lock Accounts After Failed Password Attempts   [ref]

This rule configures the system to lock out accounts after a number of incorrect login attempts using pam_faillock.so. pam_faillock.so module requires multiple entries in pam files. These entries must be carefully defined to work as expected. In order to avoid any errors when manually editing these files, it is recommended to use the appropriate tools, such as authselect or authconfig, depending on the OS version.
Warning:  If the system relies on authselect tool to manage PAM settings, the remediation will also use authselect tool. However, if any manual modification was made in PAM files, the authselect integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will be shown in the remediation report. If the system supports the /etc/security/faillock.conf file, the pam_faillock parameters should be defined in faillock.conf file.
Rationale:
Locking out user accounts after a number of incorrect attempts prevents direct password guessing attacks. In combination with the silent option, user enumeration attacks are also mitigated.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_deny
Identifiers and References

References:  BP28(R18), 1, 12, 15, 16, 5.5.3, DSS05.04, DSS05.10, DSS06.10, 3.1.8, CCI-000044, CCI-002236, CCI-002237, CCI-002238, 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, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, CM-6(a), AC-7(a), PR.AC-7, FIA_AFL.1, Req-8.1.6, SRG-OS-000329-GPOS-00128, SRG-OS-000021-GPOS-00005, SRG-OS-000021-VMM-000050


# Remediation is applicable only in certain platforms
if rpm --quiet -q pam; then

var_accounts_passwords_pam_faillock_deny='3'


if [ -f /usr/sbin/authconfig ]; then
    authconfig --enablefaillock --update
elif [ -f /usr/bin/authselect ]; then
    if authselect check; then
        authselect enable-feature with-faillock
        authselect apply-changes
    else
        echo "
authselect integrity check failed. Remediation aborted!
This remediation could not be applied because the authselect profile is not intact.
It is not recommended to manually edit the PAM files when authselect is available
In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
        false
    fi
fi

FAILLOCK_CONF="/etc/security/faillock.conf"
if [ -f $FAILLOCK_CONF ]; then
    if $(grep -q '^\s*deny\s*=' $FAILLOCK_CONF); then
        sed -i --follow-symlinks "s/^\s*\(deny\s*\)=.*$/\1 = $var_accounts_passwords_pam_faillock_deny/g" $FAILLOCK_CONF
    else
        echo "deny = $var_accounts_passwords_pam_faillock_deny" >> $FAILLOCK_CONF
    fi
else
    AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth")

for pam_file in "${AUTH_FILES[@]}"
do
    # is auth required pam_faillock.so preauth present?
    if grep -qE '^\s*auth\s+required\s+pam_faillock\.so\s+preauth.*$' "$pam_file" ; then
        # is the option set?
        if grep -qE '^\s*auth\s+required\s+pam_faillock\.so\s+preauth.*'"deny"'=([0-9]*).*$' "$pam_file" ; then
            # just change the value of option to a correct value
            sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock.so.*preauth.*silent.*\)\('"deny"' *= *\).*/\1\2'"$var_accounts_passwords_pam_faillock_deny"'/' "$pam_file"
        # the option is not set.
        else
            # append the option
            sed -i --follow-symlinks '/^auth.*required.*pam_faillock.so.*preauth.*silent.*/ s/$/ '"deny"'='"$var_accounts_passwords_pam_faillock_deny"'/' "$pam_file"
        fi
    # auth required pam_faillock.so preauth is not present, insert the whole line
    else
        sed -i --follow-symlinks '/^auth.*sufficient.*pam_unix.so.*/i auth        required      pam_faillock.so preauth silent '"deny"'='"$var_accounts_passwords_pam_faillock_deny" "$pam_file"
    fi
    # is auth default pam_faillock.so authfail present?
    if grep -qE '^\s*auth\s+(\[default=die\])\s+pam_faillock\.so\s+authfail.*$' "$pam_file" ; then
        # is the option set?
        if grep -qE '^\s*auth\s+(\[default=die\])\s+pam_faillock\.so\s+authfail.*'"deny"'=([0-9]*).*$' "$pam_file" ; then
            # just change the value of option to a correct value
            sed -i --follow-symlinks 's/\(^auth.*[default=die].*pam_faillock.so.*authfail.*\)\('"deny"' *= *\).*/\1\2'"$var_accounts_passwords_pam_faillock_deny"'/' "$pam_file"
        # the option is not set.
        else
            # append the option
            sed -i --follow-symlinks '/^auth.*[default=die].*pam_faillock.so.*authfail.*/ s/$/ '"deny"'='"$var_accounts_passwords_pam_faillock_deny"'/' "$pam_file"
        fi
    # auth default pam_faillock.so authfail is not present, insert the whole line
    else
        sed -i --follow-symlinks '/^auth.*sufficient.*pam_unix.so.*/a auth        [default=die] pam_faillock.so authfail '"deny"'='"$var_accounts_passwords_pam_faillock_deny" "$pam_file"
    fi
    if ! grep -qE '^\s*account\s+required\s+pam_faillock\.so.*$' "$pam_file" ; then
        sed -E -i --follow-symlinks '/^\s*account\s*required\s*pam_unix.so/i account     required      pam_faillock.so' "$pam_file"
    fi
done
fi

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.6
    - accounts_passwords_pam_faillock_deny
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
- name: XCCDF Value var_accounts_passwords_pam_faillock_deny # promote to variable
  set_fact:
    var_accounts_passwords_pam_faillock_deny: !!str 3
  tags:
    - always

- name: Check if system relies on authconfig
  ansible.builtin.stat:
    path: /usr/sbin/authconfig
  register: result_authconfig_check
  when: '"pam" in ansible_facts.packages'
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.6
    - accounts_passwords_pam_faillock_deny
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure pam_faillock.so is properly enabled using authconfig tool
  ansible.builtin.command:
    cmd: authconfig --enablefaillock --update
  when:
    - '"pam" in ansible_facts.packages'
    - result_authconfig_check.stat.exists
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.6
    - accounts_passwords_pam_faillock_deny
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check if system relies on authselect
  ansible.builtin.stat:
    path: /usr/bin/authselect
  register: result_authselect_present
  when:
    - '"pam" in ansible_facts.packages'
    - not result_authconfig_check.stat.exists
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.6
    - accounts_passwords_pam_faillock_deny
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check integrity of authselect current profile
  ansible.builtin.command:
    cmd: authselect check
  register: result_authselect_check_cmd
  changed_when: false
  ignore_errors: true
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_present is not skipped
    - result_authselect_present.stat.exists
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.6
    - accounts_passwords_pam_faillock_deny
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Informative message based on the authselect integrity check result
  ansible.builtin.assert:
    that:
      - result_authselect_check_cmd is success
    fail_msg:
      - authselect integrity check failed. Remediation aborted!
      - This remediation could not be applied because the authselect profile is not
        intact.
      - It is not recommended to manually edit the PAM files when authselect is available
      - In cases where the default authselect profile does not cover a specific demand,
        a custom authselect profile is recommended.
    success_msg:
      - authselect integrity check passed
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_present is not skipped
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.6
    - accounts_passwords_pam_faillock_deny
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Get authselect current features
  ansible.builtin.shell:
    cmd: authselect current | tail -n+3 | awk '{ print $2 }'
  register: result_authselect_features
  changed_when: false
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_present is not skipped
    - result_authselect_present.stat.exists
    - result_authselect_check_cmd is success
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.6
    - accounts_passwords_pam_faillock_deny
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure with-faillock feature is enabled via authselect tool
  ansible.builtin.command:
    cmd: authselect enable-feature with-faillock
  register: result_authselect_cmd
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_present is not skipped
    - result_authselect_present.stat.exists
    - result_authselect_check_cmd is success
    - result_authselect_features.stdout is not search("with-faillock")
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.6
    - accounts_passwords_pam_faillock_deny
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check the presence of /etc/security/faillock.conf file
  ansible.builtin.stat:
    path: /etc/security/faillock.conf
  register: result_faillock_conf_check
  when: '"pam" in ansible_facts.packages'
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.6
    - accounts_passwords_pam_faillock_deny
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure the pam_faillock.so deny parameter in /etc/security/faillock.conf
  ansible.builtin.lineinfile:
    path: /etc/security/faillock.conf
    regexp: ^\s*deny\s*=
    line: deny = {{ var_accounts_passwords_pam_faillock_deny }}
    state: present
  when:
    - '"pam" in ansible_facts.packages'
    - result_faillock_conf_check.stat.exists
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.6
    - accounts_passwords_pam_faillock_deny
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure the pam_faillock.so preauth deny parameter in auth section
  ansible.builtin.lineinfile:
    path: '{{ item }}'
    backrefs: true
    regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so preauth.*)(deny)=[0-5]+(.*)
    line: \1required\3\4={{ var_accounts_passwords_pam_faillock_deny }}\5
    state: present
  loop:
    - /etc/pam.d/system-auth
    - /etc/pam.d/password-auth
  when:
    - '"pam" in ansible_facts.packages'
    - not result_faillock_conf_check.stat.exists
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.6
    - accounts_passwords_pam_faillock_deny
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure the pam_faillock.so authfail deny parameter in auth section
  ansible.builtin.lineinfile:
    path: '{{ item }}'
    backrefs: true
    regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so authfail.*)(deny)=[0-5]+(.*)
    line: \1required\3\4={{ var_accounts_passwords_pam_faillock_deny }}\5
    state: present
  loop:
    - /etc/pam.d/system-auth
    - /etc/pam.d/password-auth
  when:
    - '"pam" in ansible_facts.packages'
    - not result_faillock_conf_check.stat.exists
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.6
    - accounts_passwords_pam_faillock_deny
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Set Interval For Counting Failed Password Attempts   [ref]

Utilizing pam_faillock.so, the fail_interval directive configures the system to lock out an account after a number of incorrect login attempts within a specified time period. First make sure the feature is enabled using the following command:

  • authselect enable-feature with-faillock

Then edit the /etc/security/faillock.conf file as follows:

  • add, uncomment or edit the following line:
    fail_interval = 900
  • add or uncomment the following line:
    silent
Warning:  If the system relies on authselect tool to manage PAM settings, the remediation will also use authselect tool. However, if any manual modification was made in PAM files, the authselect integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will be shown in the remediation report. If the system supports the /etc/security/faillock.conf file, the pam_faillock parameters should be defined in faillock.conf file.
Rationale:
By limiting the number of failed logon attempts the risk of unauthorized system access via user password guessing, otherwise known as brute-forcing, is reduced. Limits are imposed by locking the account.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_interval
Identifiers and References

References:  BP28(R18), 1, 12, 15, 16, DSS05.04, DSS05.10, DSS06.10, CCI-000044, CCI-002236, CCI-002237, CCI-002238, 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, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, CM-6(a), AC-7(a), PR.AC-7, FIA_AFL.1, SRG-OS-000329-GPOS-00128, SRG-OS-000021-GPOS-00005, SRG-OS-000021-VMM-000050


# Remediation is applicable only in certain platforms
if rpm --quiet -q pam; then

var_accounts_passwords_pam_faillock_fail_interval='900'


if [ -f /usr/sbin/authconfig ]; then
    authconfig --enablefaillock --update
elif [ -f /usr/bin/authselect ]; then
    if authselect check; then
        authselect enable-feature with-faillock
        authselect apply-changes
    else
        echo "
authselect integrity check failed. Remediation aborted!
This remediation could not be applied because the authselect profile is not intact.
It is not recommended to manually edit the PAM files when authselect is available
In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
        false
    fi
fi

FAILLOCK_CONF="/etc/security/faillock.conf"
if [ -f $FAILLOCK_CONF ]; then
    if $(grep -q '^\s*fail_interval\s*=' $FAILLOCK_CONF); then
        sed -i --follow-symlinks "s/^\s*\(fail_interval\s*\)=.*$/\1 = $var_accounts_passwords_pam_faillock_fail_interval/g" $FAILLOCK_CONF
    else
        echo "fail_interval = $var_accounts_passwords_pam_faillock_fail_interval" >> $FAILLOCK_CONF
    fi
else
    AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth")

for pam_file in "${AUTH_FILES[@]}"
do
    # is auth required pam_faillock.so preauth present?
    if grep -qE '^\s*auth\s+required\s+pam_faillock\.so\s+preauth.*$' "$pam_file" ; then
        # is the option set?
        if grep -qE '^\s*auth\s+required\s+pam_faillock\.so\s+preauth.*'"fail_interval"'=([0-9]*).*$' "$pam_file" ; then
            # just change the value of option to a correct value
            sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock.so.*preauth.*silent.*\)\('"fail_interval"' *= *\).*/\1\2'"$var_accounts_passwords_pam_faillock_fail_interval"'/' "$pam_file"
        # the option is not set.
        else
            # append the option
            sed -i --follow-symlinks '/^auth.*required.*pam_faillock.so.*preauth.*silent.*/ s/$/ '"fail_interval"'='"$var_accounts_passwords_pam_faillock_fail_interval"'/' "$pam_file"
        fi
    # auth required pam_faillock.so preauth is not present, insert the whole line
    else
        sed -i --follow-symlinks '/^auth.*sufficient.*pam_unix.so.*/i auth        required      pam_faillock.so preauth silent '"fail_interval"'='"$var_accounts_passwords_pam_faillock_fail_interval" "$pam_file"
    fi
    # is auth default pam_faillock.so authfail present?
    if grep -qE '^\s*auth\s+(\[default=die\])\s+pam_faillock\.so\s+authfail.*$' "$pam_file" ; then
        # is the option set?
        if grep -qE '^\s*auth\s+(\[default=die\])\s+pam_faillock\.so\s+authfail.*'"fail_interval"'=([0-9]*).*$' "$pam_file" ; then
            # just change the value of option to a correct value
            sed -i --follow-symlinks 's/\(^auth.*[default=die].*pam_faillock.so.*authfail.*\)\('"fail_interval"' *= *\).*/\1\2'"$var_accounts_passwords_pam_faillock_fail_interval"'/' "$pam_file"
        # the option is not set.
        else
            # append the option
            sed -i --follow-symlinks '/^auth.*[default=die].*pam_faillock.so.*authfail.*/ s/$/ '"fail_interval"'='"$var_accounts_passwords_pam_faillock_fail_interval"'/' "$pam_file"
        fi
    # auth default pam_faillock.so authfail is not present, insert the whole line
    else
        sed -i --follow-symlinks '/^auth.*sufficient.*pam_unix.so.*/a auth        [default=die] pam_faillock.so authfail '"fail_interval"'='"$var_accounts_passwords_pam_faillock_fail_interval" "$pam_file"
    fi
    if ! grep -qE '^\s*account\s+required\s+pam_faillock\.so.*$' "$pam_file" ; then
        sed -E -i --follow-symlinks '/^\s*account\s*required\s*pam_unix.so/i account     required      pam_faillock.so' "$pam_file"
    fi
done
fi

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - accounts_passwords_pam_faillock_interval
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
- name: XCCDF Value var_accounts_passwords_pam_faillock_fail_interval # promote to variable
  set_fact:
    var_accounts_passwords_pam_faillock_fail_interval: !!str 900
  tags:
    - always

- name: Check if system relies on authconfig
  ansible.builtin.stat:
    path: /usr/sbin/authconfig
  register: result_authconfig_check
  when: '"pam" in ansible_facts.packages'
  tags:
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - accounts_passwords_pam_faillock_interval
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure pam_faillock.so is properly enabled using authconfig tool
  ansible.builtin.command:
    cmd: authconfig --enablefaillock --update
  when:
    - '"pam" in ansible_facts.packages'
    - result_authconfig_check.stat.exists
  tags:
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - accounts_passwords_pam_faillock_interval
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check if system relies on authselect
  ansible.builtin.stat:
    path: /usr/bin/authselect
  register: result_authselect_present
  when:
    - '"pam" in ansible_facts.packages'
    - not result_authconfig_check.stat.exists
  tags:
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - accounts_passwords_pam_faillock_interval
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check integrity of authselect current profile
  ansible.builtin.command:
    cmd: authselect check
  register: result_authselect_check_cmd
  changed_when: false
  ignore_errors: true
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_present is not skipped
    - result_authselect_present.stat.exists
  tags:
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - accounts_passwords_pam_faillock_interval
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Informative message based on the authselect integrity check result
  ansible.builtin.assert:
    that:
      - result_authselect_check_cmd is success
    fail_msg:
      - authselect integrity check failed. Remediation aborted!
      - This remediation could not be applied because the authselect profile is not
        intact.
      - It is not recommended to manually edit the PAM files when authselect is available
      - In cases where the default authselect profile does not cover a specific demand,
        a custom authselect profile is recommended.
    success_msg:
      - authselect integrity check passed
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_present is not skipped
  tags:
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - accounts_passwords_pam_faillock_interval
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Get authselect current features
  ansible.builtin.shell:
    cmd: authselect current | tail -n+3 | awk '{ print $2 }'
  register: result_authselect_features
  changed_when: false
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_present is not skipped
    - result_authselect_present.stat.exists
    - result_authselect_check_cmd is success
  tags:
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - accounts_passwords_pam_faillock_interval
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure with-faillock feature is enabled via authselect tool
  ansible.builtin.command:
    cmd: authselect enable-feature with-faillock
  register: result_authselect_cmd
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_present is not skipped
    - result_authselect_present.stat.exists
    - result_authselect_check_cmd is success
    - result_authselect_features.stdout is not search("with-faillock")
  tags:
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - accounts_passwords_pam_faillock_interval
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check the presence of /etc/security/faillock.conf file
  ansible.builtin.stat:
    path: /etc/security/faillock.conf
  register: result_faillock_conf_check
  when: '"pam" in ansible_facts.packages'
  tags:
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - accounts_passwords_pam_faillock_interval
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure the pam_faillock.so fail_interval parameter in /etc/security/faillock.conf
  ansible.builtin.lineinfile:
    path: /etc/security/faillock.conf
    regexp: ^\s*fail_interval\s*=
    line: fail_interval = {{ var_accounts_passwords_pam_faillock_fail_interval }}
    state: present
  when:
    - '"pam" in ansible_facts.packages'
    - result_faillock_conf_check.stat.exists
  tags:
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - accounts_passwords_pam_faillock_interval
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check if pam_faillock.so fail_interval parameter is already enabled in pam
    files
  ansible.builtin.lineinfile:
    path: /etc/pam.d/system-auth
    regexp: .*auth.*pam_faillock.so (preauth|authfail).*fail_interval
    state: absent
  check_mode: true
  changed_when: false
  register: result_pam_faillock_fail_interval
  when:
    - '"pam" in ansible_facts.packages'
    - not result_faillock_conf_check.stat.exists
  tags:
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - accounts_passwords_pam_faillock_interval
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure the inclusion of pam_faillock.so preauth fail_interval parameter in
    auth section
  ansible.builtin.lineinfile:
    path: '{{ item }}'
    backrefs: true
    regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so preauth.*)
    line: \1required\3 fail_interval={{ var_accounts_passwords_pam_faillock_fail_interval
      }}
    state: present
  loop:
    - /etc/pam.d/system-auth
    - /etc/pam.d/password-auth
  when:
    - '"pam" in ansible_facts.packages'
    - not result_faillock_conf_check.stat.exists
    - result_pam_faillock_fail_interval.found == 0
  tags:
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - accounts_passwords_pam_faillock_interval
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure the inclusion of pam_faillock.so authfail fail_interval parameter in
    auth section
  ansible.builtin.lineinfile:
    path: '{{ item }}'
    backrefs: true
    regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so authfail.*)
    line: \1required\3 fail_interval={{ var_accounts_passwords_pam_faillock_fail_interval
      }}
    state: present
  loop:
    - /etc/pam.d/system-auth
    - /etc/pam.d/password-auth
  when:
    - '"pam" in ansible_facts.packages'
    - not result_faillock_conf_check.stat.exists
    - result_pam_faillock_fail_interval.found == 0
  tags:
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - accounts_passwords_pam_faillock_interval
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure the desired value for pam_faillock.so preauth fail_interval parameter
    in auth section
  ansible.builtin.lineinfile:
    path: '{{ item }}'
    backrefs: true
    regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so preauth.*)(fail_interval)=[0-5]+(.*)
    line: \1required\3\4={{ var_accounts_passwords_pam_faillock_fail_interval }}\5
    state: present
  loop:
    - /etc/pam.d/system-auth
    - /etc/pam.d/password-auth
  when:
    - '"pam" in ansible_facts.packages'
    - not result_faillock_conf_check.stat.exists
    - result_pam_faillock_fail_interval.found > 0
  tags:
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - accounts_passwords_pam_faillock_interval
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure the desired value for pam_faillock.so authfail fail_interval parameter
    in auth section
  ansible.builtin.lineinfile:
    path: '{{ item }}'
    backrefs: true
    regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so authfail.*)(fail_interval)=[0-5]+(.*)
    line: \1required\3\4={{ var_accounts_passwords_pam_faillock_fail_interval }}\5
    state: present
  loop:
    - /etc/pam.d/system-auth
    - /etc/pam.d/password-auth
  when:
    - '"pam" in ansible_facts.packages'
    - not result_faillock_conf_check.stat.exists
    - result_pam_faillock_fail_interval.found > 0
  tags:
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - accounts_passwords_pam_faillock_interval
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Set Lockout Time for Failed Password Attempts   [ref]

This rule configures the system to lock out accounts during a specified time period after a number of incorrect login attempts using pam_faillock.so. pam_faillock.so module requires multiple entries in pam files. These entries must be carefully defined to work as expected. In order to avoid any errors when manually editing these files, it is recommended to use the appropriate tools, such as authselect or authconfig, depending on the OS version.
Warning:  If the system relies on authselect tool to manage PAM settings, the remediation will also use authselect tool. However, if any manual modification was made in PAM files, the authselect integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will be shown in the remediation report. If the system supports the /etc/security/faillock.conf file, the pam_faillock parameters should be defined in faillock.conf file.
Rationale:
Locking out user accounts after a number of incorrect attempts prevents direct password guessing attacks. Ensuring that an administrator is involved in unlocking locked accounts draws appropriate attention to such situations.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_unlock_time
Identifiers and References

References:  BP28(R18), 1, 12, 15, 16, 5.5.3, DSS05.04, DSS05.10, DSS06.10, 3.1.8, CCI-000044, CCI-002236, CCI-002237, CCI-002238, 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, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, CM-6(a), AC-7(b), PR.AC-7, FIA_AFL.1, Req-8.1.7, SRG-OS-000329-GPOS-00128, SRG-OS-000021-GPOS-00005, SRG-OS-000329-VMM-001180


# Remediation is applicable only in certain platforms
if rpm --quiet -q pam; then

var_accounts_passwords_pam_faillock_unlock_time='0'


if [ -f /usr/sbin/authconfig ]; then
    authconfig --enablefaillock --update
elif [ -f /usr/bin/authselect ]; then
    if authselect check; then
        authselect enable-feature with-faillock
        authselect apply-changes
    else
        echo "
authselect integrity check failed. Remediation aborted!
This remediation could not be applied because the authselect profile is not intact.
It is not recommended to manually edit the PAM files when authselect is available
In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
        false
    fi
fi

FAILLOCK_CONF="/etc/security/faillock.conf"
if [ -f $FAILLOCK_CONF ]; then
    if $(grep -q '^\s*unlock_time\s*=' $FAILLOCK_CONF); then
        sed -i --follow-symlinks "s/^\s*\(unlock_time\s*\)=.*$/\1 = $var_accounts_passwords_pam_faillock_unlock_time/g" $FAILLOCK_CONF
    else
        echo "unlock_time = $var_accounts_passwords_pam_faillock_unlock_time" >> $FAILLOCK_CONF
    fi
else
    AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth")

for pam_file in "${AUTH_FILES[@]}"
do
    # is auth required pam_faillock.so preauth present?
    if grep -qE '^\s*auth\s+required\s+pam_faillock\.so\s+preauth.*$' "$pam_file" ; then
        # is the option set?
        if grep -qE '^\s*auth\s+required\s+pam_faillock\.so\s+preauth.*'"unlock_time"'=([0-9]*).*$' "$pam_file" ; then
            # just change the value of option to a correct value
            sed -i --follow-symlinks 's/\(^auth.*required.*pam_faillock.so.*preauth.*silent.*\)\('"unlock_time"' *= *\).*/\1\2'"$var_accounts_passwords_pam_faillock_unlock_time"'/' "$pam_file"
        # the option is not set.
        else
            # append the option
            sed -i --follow-symlinks '/^auth.*required.*pam_faillock.so.*preauth.*silent.*/ s/$/ '"unlock_time"'='"$var_accounts_passwords_pam_faillock_unlock_time"'/' "$pam_file"
        fi
    # auth required pam_faillock.so preauth is not present, insert the whole line
    else
        sed -i --follow-symlinks '/^auth.*sufficient.*pam_unix.so.*/i auth        required      pam_faillock.so preauth silent '"unlock_time"'='"$var_accounts_passwords_pam_faillock_unlock_time" "$pam_file"
    fi
    # is auth default pam_faillock.so authfail present?
    if grep -qE '^\s*auth\s+(\[default=die\])\s+pam_faillock\.so\s+authfail.*$' "$pam_file" ; then
        # is the option set?
        if grep -qE '^\s*auth\s+(\[default=die\])\s+pam_faillock\.so\s+authfail.*'"unlock_time"'=([0-9]*).*$' "$pam_file" ; then
            # just change the value of option to a correct value
            sed -i --follow-symlinks 's/\(^auth.*[default=die].*pam_faillock.so.*authfail.*\)\('"unlock_time"' *= *\).*/\1\2'"$var_accounts_passwords_pam_faillock_unlock_time"'/' "$pam_file"
        # the option is not set.
        else
            # append the option
            sed -i --follow-symlinks '/^auth.*[default=die].*pam_faillock.so.*authfail.*/ s/$/ '"unlock_time"'='"$var_accounts_passwords_pam_faillock_unlock_time"'/' "$pam_file"
        fi
    # auth default pam_faillock.so authfail is not present, insert the whole line
    else
        sed -i --follow-symlinks '/^auth.*sufficient.*pam_unix.so.*/a auth        [default=die] pam_faillock.so authfail '"unlock_time"'='"$var_accounts_passwords_pam_faillock_unlock_time" "$pam_file"
    fi
    if ! grep -qE '^\s*account\s+required\s+pam_faillock\.so.*$' "$pam_file" ; then
        sed -E -i --follow-symlinks '/^\s*account\s*required\s*pam_unix.so/i account     required      pam_faillock.so' "$pam_file"
    fi
done
fi

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.7
    - accounts_passwords_pam_faillock_unlock_time
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
- name: XCCDF Value var_accounts_passwords_pam_faillock_unlock_time # promote to variable
  set_fact:
    var_accounts_passwords_pam_faillock_unlock_time: !!str 0
  tags:
    - always

- name: Check if system relies on authconfig
  ansible.builtin.stat:
    path: /usr/sbin/authconfig
  register: result_authconfig_check
  when: '"pam" in ansible_facts.packages'
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.7
    - accounts_passwords_pam_faillock_unlock_time
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure pam_faillock.so is properly enabled using authconfig tool
  ansible.builtin.command:
    cmd: authconfig --enablefaillock --update
  when:
    - '"pam" in ansible_facts.packages'
    - result_authconfig_check.stat.exists
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.7
    - accounts_passwords_pam_faillock_unlock_time
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check if system relies on authselect
  ansible.builtin.stat:
    path: /usr/bin/authselect
  register: result_authselect_present
  when:
    - '"pam" in ansible_facts.packages'
    - not result_authconfig_check.stat.exists
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.7
    - accounts_passwords_pam_faillock_unlock_time
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check integrity of authselect current profile
  ansible.builtin.command:
    cmd: authselect check
  register: result_authselect_check_cmd
  changed_when: false
  ignore_errors: true
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_present is not skipped
    - result_authselect_present.stat.exists
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.7
    - accounts_passwords_pam_faillock_unlock_time
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Informative message based on the authselect integrity check result
  ansible.builtin.assert:
    that:
      - result_authselect_check_cmd is success
    fail_msg:
      - authselect integrity check failed. Remediation aborted!
      - This remediation could not be applied because the authselect profile is not
        intact.
      - It is not recommended to manually edit the PAM files when authselect is available
      - In cases where the default authselect profile does not cover a specific demand,
        a custom authselect profile is recommended.
    success_msg:
      - authselect integrity check passed
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_present is not skipped
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.7
    - accounts_passwords_pam_faillock_unlock_time
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Get authselect current features
  ansible.builtin.shell:
    cmd: authselect current | tail -n+3 | awk '{ print $2 }'
  register: result_authselect_features
  changed_when: false
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_present is not skipped
    - result_authselect_present.stat.exists
    - result_authselect_check_cmd is success
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.7
    - accounts_passwords_pam_faillock_unlock_time
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure with-faillock feature is enabled via authselect tool
  ansible.builtin.command:
    cmd: authselect enable-feature with-faillock
  register: result_authselect_cmd
  when:
    - '"pam" in ansible_facts.packages'
    - result_authselect_present is not skipped
    - result_authselect_present.stat.exists
    - result_authselect_check_cmd is success
    - result_authselect_features.stdout is not search("with-faillock")
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.7
    - accounts_passwords_pam_faillock_unlock_time
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check the presence of /etc/security/faillock.conf file
  ansible.builtin.stat:
    path: /etc/security/faillock.conf
  register: result_faillock_conf_check
  when: '"pam" in ansible_facts.packages'
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.7
    - accounts_passwords_pam_faillock_unlock_time
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure the pam_faillock.so unlock_time parameter in /etc/security/faillock.conf
  ansible.builtin.lineinfile:
    path: /etc/security/faillock.conf
    regexp: ^\s*unlock_time\s*=
    line: unlock_time = {{ var_accounts_passwords_pam_faillock_unlock_time }}
    state: present
  when:
    - '"pam" in ansible_facts.packages'
    - result_faillock_conf_check.stat.exists
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.7
    - accounts_passwords_pam_faillock_unlock_time
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure the pam_faillock.so preauth unlock_time parameter in auth section
  ansible.builtin.lineinfile:
    path: '{{ item }}'
    backrefs: true
    regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so preauth.*)(unlock_time)=[0-5]+(.*)
    line: \1required\3\4={{ var_accounts_passwords_pam_faillock_unlock_time }}\5
    state: present
  loop:
    - /etc/pam.d/system-auth
    - /etc/pam.d/password-auth
  when:
    - '"pam" in ansible_facts.packages'
    - not result_faillock_conf_check.stat.exists
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.7
    - accounts_passwords_pam_faillock_unlock_time
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure the pam_faillock.so authfail unlock_time parameter in auth section
  ansible.builtin.lineinfile:
    path: '{{ item }}'
    backrefs: true
    regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so authfail.*)(unlock_time)=[0-5]+(.*)
    line: \1required\3\4={{ var_accounts_passwords_pam_faillock_unlock_time }}\5
    state: present
  loop:
    - /etc/pam.d/system-auth
    - /etc/pam.d/password-auth
  when:
    - '"pam" in ansible_facts.packages'
    - not result_faillock_conf_check.stat.exists
  tags:
    - CJIS-5.5.3
    - NIST-800-171-3.1.8
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-8.1.7
    - accounts_passwords_pam_faillock_unlock_time
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
Group   Set Password Quality Requirements   Group contains 1 group and 8 rules
[ref]   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.
Group   Set Password Quality Requirements with pam_pwquality   Group contains 8 rules
[ref]   The pam_pwquality PAM module can be configured to meet requirements for a variety of policies.

For example, to configure pam_pwquality to require at least one uppercase character, lowercase character, digit, and other (special) character, make sure that pam_pwquality exists in /etc/pam.d/system-auth:
password    requisite     pam_pwquality.so try_first_pass local_users_only retry=3 authtok_type=
If no such line exists, add one as the first line of the password section in /etc/pam.d/system-auth. Next, modify the settings in /etc/security/pwquality.conf to match the following:
difok = 4
minlen = 14
dcredit = -1
ucredit = -1
lcredit = -1
ocredit = -1
maxrepeat = 3
The arguments can be modified to ensure compliance with your organization's security policy. Discussion of each parameter follows.

Rule   Ensure PAM Enforces Password Requirements - Minimum Digit Characters   [ref]

The pam_pwquality 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_pwquality will grant +1 additional length credit for each digit. Modify the dcredit setting in /etc/security/pwquality.conf to require the use of a digit in passwords.
Rationale:
Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks.

Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before the password is compromised. Requiring digits makes password guessing attacks more difficult by ensuring a larger search space.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_password_pam_dcredit
Identifiers and References

References:  BP28(R18), 1, 12, 15, 16, 5, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, CCI-000194, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 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.2, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, A.18.1.4, A.7.1.1, 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.2, A.9.4.3, IA-5(c), IA-5(1)(a), CM-6(a), IA-5(4), PR.AC-1, PR.AC-6, PR.AC-7, FMT_MOF_EXT.1, Req-8.2.3, SRG-OS-000071-GPOS-00039, SRG-OS-000071-VMM-000380


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if rpm --quiet -q pam; then

var_password_pam_dcredit='-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 "/etc/security/pwquality.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^dcredit")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$var_password_pam_dcredit"

# 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 -i -e "^dcredit\\>" "/etc/security/pwquality.conf"; then
    "${sed_command[@]}" "s/^dcredit\\>.*/$formatted_output/gi" "/etc/security/pwquality.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/security/pwquality.conf"
fi

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(a)
    - NIST-800-53-IA-5(4)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.3
    - accounts_password_pam_dcredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
- name: XCCDF Value var_password_pam_dcredit # promote to variable
  set_fact:
    var_password_pam_dcredit: !!str -1
  tags:
    - always

- name: Ensure PAM variable dcredit is set accordingly
  lineinfile:
    create: true
    dest: /etc/security/pwquality.conf
    regexp: ^#?\s*dcredit
    line: dcredit = {{ var_password_pam_dcredit }}
  when: '"pam" in ansible_facts.packages'
  tags:
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(a)
    - NIST-800-53-IA-5(4)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.3
    - accounts_password_pam_dcredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Ensure PAM Enforces Password Requirements - Minimum Different Characters   [ref]

The pam_pwquality module's difok parameter sets the number of characters in a password that must not be present in and old password during a password change.

Modify the difok setting in /etc/security/pwquality.conf to equal 4 to require differing characters when changing passwords.
Rationale:
Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute–force attacks.

Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before the password is compromised.

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.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_password_pam_difok
Identifiers and References

References:  1, 12, 15, 16, 5, 5.6.2.1.1, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, CCI-000195, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 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.2, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, A.18.1.4, A.7.1.1, 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.2, A.9.4.3, IA-5(c), IA-5(1)(b), CM-6(a), IA-5(4), PR.AC-1, PR.AC-6, PR.AC-7, SRG-OS-000072-GPOS-00040, SRG-OS-000072-VMM-000390


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if rpm --quiet -q pam; then

var_password_pam_difok='4'


# 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 "/etc/security/pwquality.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^difok")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$var_password_pam_difok"

# 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 -i -e "^difok\\>" "/etc/security/pwquality.conf"; then
    "${sed_command[@]}" "s/^difok\\>.*/$formatted_output/gi" "/etc/security/pwquality.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/security/pwquality.conf"
fi

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(b)
    - NIST-800-53-IA-5(4)
    - NIST-800-53-IA-5(c)
    - accounts_password_pam_difok
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
- name: XCCDF Value var_password_pam_difok # promote to variable
  set_fact:
    var_password_pam_difok: !!str 4
  tags:
    - always

- name: Ensure PAM variable difok is set accordingly
  lineinfile:
    create: true
    dest: /etc/security/pwquality.conf
    regexp: ^#?\s*difok
    line: difok = {{ var_password_pam_difok }}
  when: '"pam" in ansible_facts.packages'
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(b)
    - NIST-800-53-IA-5(4)
    - NIST-800-53-IA-5(c)
    - accounts_password_pam_difok
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters   [ref]

The pam_pwquality 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_pwquality will grant +1 additional length credit for each lowercase character. Modify the lcredit setting in /etc/security/pwquality.conf to require the use of a lowercase character in passwords.
Rationale:
Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks.

Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possble combinations that need to be tested before the password is compromised. Requiring a minimum number of lowercase characters makes password guessing attacks more difficult by ensuring a larger search space.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_password_pam_lcredit
Identifiers and References

References:  BP28(R18), 1, 12, 15, 16, 5, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, CCI-000193, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 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.2, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, A.18.1.4, A.7.1.1, 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.2, A.9.4.3, IA-5(c), IA-5(1)(a), CM-6(a), IA-5(4), PR.AC-1, PR.AC-6, PR.AC-7, FMT_MOF_EXT.1, Req-8.2.3, SRG-OS-000070-GPOS-00038, SRG-OS-000070-VMM-000370


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if rpm --quiet -q pam; then

var_password_pam_lcredit='-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 "/etc/security/pwquality.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^lcredit")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$var_password_pam_lcredit"

# 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 -i -e "^lcredit\\>" "/etc/security/pwquality.conf"; then
    "${sed_command[@]}" "s/^lcredit\\>.*/$formatted_output/gi" "/etc/security/pwquality.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/security/pwquality.conf"
fi

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(a)
    - NIST-800-53-IA-5(4)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.3
    - accounts_password_pam_lcredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
- name: XCCDF Value var_password_pam_lcredit # promote to variable
  set_fact:
    var_password_pam_lcredit: !!str -1
  tags:
    - always

- name: Ensure PAM variable lcredit is set accordingly
  lineinfile:
    create: true
    dest: /etc/security/pwquality.conf
    regexp: ^#?\s*lcredit
    line: lcredit = {{ var_password_pam_lcredit }}
  when: '"pam" in ansible_facts.packages'
  tags:
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(a)
    - NIST-800-53-IA-5(4)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.3
    - accounts_password_pam_lcredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Ensure PAM Enforces Password Requirements - Maximum Consecutive Repeating Characters from Same Character Class   [ref]

The pam_pwquality module's maxclassrepeat parameter controls requirements for consecutive repeating characters from the same character class. When set to a positive number, it will reject passwords which contain more than that number of consecutive characters from the same character class. Modify the maxclassrepeat setting in /etc/security/pwquality.conf to equal 4 to prevent a run of (4 + 1) or more identical characters.
Rationale:
Use of a complex password helps to increase the time and resources required to comrpomise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks.
Password complexity is one factor of several that determines how long it takes to crack a password. The more complex a password, the greater the number of possible combinations that need to be tested before the password is compromised.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_password_pam_maxclassrepeat
Identifiers and References

References:  1, 12, 15, 16, 5, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, CCI-000195, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 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.2, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, A.18.1.4, A.7.1.1, 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.2, A.9.4.3, IA-5(c), IA-5(1)(a), CM-6(a), IA-5(4), PR.AC-1, PR.AC-6, PR.AC-7, SRG-OS-000072-GPOS-00040


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if rpm --quiet -q pam; then

var_password_pam_maxclassrepeat='4'


# 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 "/etc/security/pwquality.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^maxclassrepeat")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$var_password_pam_maxclassrepeat"

# 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 -i -e "^maxclassrepeat\\>" "/etc/security/pwquality.conf"; then
    "${sed_command[@]}" "s/^maxclassrepeat\\>.*/$formatted_output/gi" "/etc/security/pwquality.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/security/pwquality.conf"
fi

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(a)
    - NIST-800-53-IA-5(4)
    - NIST-800-53-IA-5(c)
    - accounts_password_pam_maxclassrepeat
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
- name: XCCDF Value var_password_pam_maxclassrepeat # promote to variable
  set_fact:
    var_password_pam_maxclassrepeat: !!str 4
  tags:
    - always

- name: Ensure PAM variable maxclassrepeat is set accordingly
  lineinfile:
    create: true
    dest: /etc/security/pwquality.conf
    regexp: ^#?\s*maxclassrepeat
    line: maxclassrepeat = {{ var_password_pam_maxclassrepeat }}
  when: '"pam" in ansible_facts.packages'
  tags:
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(a)
    - NIST-800-53-IA-5(4)
    - NIST-800-53-IA-5(c)
    - accounts_password_pam_maxclassrepeat
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Set Password Maximum Consecutive Repeating Characters   [ref]

The pam_pwquality module's maxrepeat parameter controls requirements for consecutive repeating characters. When set to a positive number, it will reject passwords which contain more than that number of consecutive characters. Modify the maxrepeat setting in /etc/security/pwquality.conf to equal 3 to prevent a run of (3 + 1) or more identical characters.
Rationale:
Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks.

Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before the password is compromised.

Passwords with excessive repeating characters may be more vulnerable to password-guessing attacks.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_password_pam_maxrepeat
Identifiers and References

References:  1, 12, 15, 16, 5, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, CCI-000195, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 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.2, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, A.18.1.4, A.7.1.1, 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.2, A.9.4.3, IA-5(c), CM-6(a), IA-5(4), PR.AC-1, PR.AC-6, PR.AC-7, SRG-OS-000072-GPOS-00040


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if rpm --quiet -q pam; then

var_password_pam_maxrepeat='3'


# 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 "/etc/security/pwquality.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^maxrepeat")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$var_password_pam_maxrepeat"

# 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 -i -e "^maxrepeat\\>" "/etc/security/pwquality.conf"; then
    "${sed_command[@]}" "s/^maxrepeat\\>.*/$formatted_output/gi" "/etc/security/pwquality.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/security/pwquality.conf"
fi

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(4)
    - NIST-800-53-IA-5(c)
    - accounts_password_pam_maxrepeat
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
- name: XCCDF Value var_password_pam_maxrepeat # promote to variable
  set_fact:
    var_password_pam_maxrepeat: !!str 3
  tags:
    - always

- name: Ensure PAM variable maxrepeat is set accordingly
  lineinfile:
    create: true
    dest: /etc/security/pwquality.conf
    regexp: ^#?\s*maxrepeat
    line: maxrepeat = {{ var_password_pam_maxrepeat }}
  when: '"pam" in ansible_facts.packages'
  tags:
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(4)
    - NIST-800-53-IA-5(c)
    - accounts_password_pam_maxrepeat
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Ensure PAM Enforces Password Requirements - Minimum Length   [ref]

The pam_pwquality module's minlen parameter controls requirements for minimum characters required in a password. Add minlen=12 after pam_pwquality to set minimum password length requirements.
Rationale:
The shorter the password, the lower the number of possible combinations that need to be tested before the password is compromised.
Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks. 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 compromose the password.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_password_pam_minlen
Identifiers and References

References:  BP28(R18), 1, 12, 15, 16, 5, 5.6.2.1.1, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, CCI-000205, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 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.2, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, A.18.1.4, A.7.1.1, 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.2, A.9.4.3, IA-5(c), IA-5(1)(a), CM-6(a), IA-5(4), PR.AC-1, PR.AC-6, PR.AC-7, FMT_MOF_EXT.1, Req-8.2.3, SRG-OS-000078-GPOS-00046, SRG-OS-000072-VMM-000390, SRG-OS-000078-VMM-000450


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if rpm --quiet -q pam; then

var_password_pam_minlen='12'


# 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 "/etc/security/pwquality.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^minlen")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$var_password_pam_minlen"

# 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 -i -e "^minlen\\>" "/etc/security/pwquality.conf"; then
    "${sed_command[@]}" "s/^minlen\\>.*/$formatted_output/gi" "/etc/security/pwquality.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/security/pwquality.conf"
fi

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(a)
    - NIST-800-53-IA-5(4)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.3
    - accounts_password_pam_minlen
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
- name: XCCDF Value var_password_pam_minlen # promote to variable
  set_fact:
    var_password_pam_minlen: !!str 12
  tags:
    - always

- name: Ensure PAM variable minlen is set accordingly
  lineinfile:
    create: true
    dest: /etc/security/pwquality.conf
    regexp: ^#?\s*minlen
    line: minlen = {{ var_password_pam_minlen }}
  when: '"pam" in ansible_facts.packages'
  tags:
    - CJIS-5.6.2.1.1
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(a)
    - NIST-800-53-IA-5(4)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.3
    - accounts_password_pam_minlen
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Ensure PAM Enforces Password Requirements - Minimum Special Characters   [ref]

The pam_pwquality 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_pwquality will grant +1 additional length credit for each special character. Modify the ocredit setting in /etc/security/pwquality.conf to equal -1 to require use of a special character in passwords.
Rationale:
Use of a complex password helps to increase the time and resources required to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks.

Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possble combinations that need to be tested before the password is compromised. Requiring a minimum number of special characters makes password guessing attacks more difficult by ensuring a larger search space.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_password_pam_ocredit
Identifiers and References

References:  BP28(R18), 1, 12, 15, 16, 5, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, CCI-001619, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 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.2, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, A.18.1.4, A.7.1.1, 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.2, A.9.4.3, IA-5(c), IA-5(1)(a), CM-6(a), IA-5(4), PR.AC-1, PR.AC-6, PR.AC-7, FMT_MOF_EXT.1, SRG-OS-000266-GPOS-00101, SRG-OS-000266-VMM-000940


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if rpm --quiet -q pam; then

var_password_pam_ocredit='-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 "/etc/security/pwquality.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^ocredit")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$var_password_pam_ocredit"

# 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 -i -e "^ocredit\\>" "/etc/security/pwquality.conf"; then
    "${sed_command[@]}" "s/^ocredit\\>.*/$formatted_output/gi" "/etc/security/pwquality.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/security/pwquality.conf"
fi

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(a)
    - NIST-800-53-IA-5(4)
    - NIST-800-53-IA-5(c)
    - accounts_password_pam_ocredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
- name: XCCDF Value var_password_pam_ocredit # promote to variable
  set_fact:
    var_password_pam_ocredit: !!str -1
  tags:
    - always

- name: Ensure PAM variable ocredit is set accordingly
  lineinfile:
    create: true
    dest: /etc/security/pwquality.conf
    regexp: ^#?\s*ocredit
    line: ocredit = {{ var_password_pam_ocredit }}
  when: '"pam" in ansible_facts.packages'
  tags:
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(a)
    - NIST-800-53-IA-5(4)
    - NIST-800-53-IA-5(c)
    - accounts_password_pam_ocredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters   [ref]

The pam_pwquality 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_pwquality will grant +1 additional length credit for each uppercase character. Modify the ucredit setting in /etc/security/pwquality.conf to require the use of an uppercase character in passwords.
Rationale:
Use of a complex password helps to increase the time and resources reuiqred to compromise the password. Password complexity, or strength, is a measure of the effectiveness of a password in resisting attempts at guessing and brute-force attacks.

Password complexity is one factor of several that determines how long it takes to crack a password. The more complex the password, the greater the number of possible combinations that need to be tested before the password is compromised.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_password_pam_ucredit
Identifiers and References

References:  BP28(R18), 1, 12, 15, 16, 5, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, CCI-000192, 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 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.2, 4.3.3.7.4, SR 1.1, SR 1.10, SR 1.2, SR 1.3, SR 1.4, SR 1.5, SR 1.7, SR 1.8, SR 1.9, SR 2.1, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, A.18.1.4, A.7.1.1, 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.2, A.9.4.3, IA-5(c), IA-5(1)(a), CM-6(a), IA-5(4), PR.AC-1, PR.AC-6, PR.AC-7, FMT_MOF_EXT.1, Req-8.2.3, SRG-OS-000069-GPOS-00037, SRG-OS-000069-VMM-000360


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if rpm --quiet -q pam; then

var_password_pam_ucredit='-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 "/etc/security/pwquality.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^ucredit")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$var_password_pam_ucredit"

# 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 -i -e "^ucredit\\>" "/etc/security/pwquality.conf"; then
    "${sed_command[@]}" "s/^ucredit\\>.*/$formatted_output/gi" "/etc/security/pwquality.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/security/pwquality.conf"
fi

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(a)
    - NIST-800-53-IA-5(4)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.3
    - accounts_password_pam_ucredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
- name: XCCDF Value var_password_pam_ucredit # promote to variable
  set_fact:
    var_password_pam_ucredit: !!str -1
  tags:
    - always

- name: Ensure PAM variable ucredit is set accordingly
  lineinfile:
    create: true
    dest: /etc/security/pwquality.conf
    regexp: ^#?\s*ucredit
    line: ucredit = {{ var_password_pam_ucredit }}
  when: '"pam" in ansible_facts.packages'
  tags:
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(a)
    - NIST-800-53-IA-5(4)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.3
    - accounts_password_pam_ucredit
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
Group   Protect Physical Console Access   Group contains 2 groups and 10 rules
[ref]   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.
Group   Configure Screen Locking   Group contains 1 group and 5 rules
[ref]   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.
Group   Configure Console Screen Locking   Group contains 5 rules
[ref]   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.

Rule   Install the tmux Package   [ref]

To enable console screen locking, install the tmux package. 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. Rather than be forced to wait for a period of time to expire before the user session can be locked, AlmaLinux 9 needs to provide users with the ability to manually invoke a session lock so users can secure their session if it is necessary to temporarily vacate the immediate physical vicinity. Instruct users to begin new terminal sessions with the following command:
$ tmux
The console can now be locked with the following key combination:
ctrl+b :lock-session
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 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.

The tmux package allows for a session lock to be implemented and configured.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_tmux_installed
Identifiers and References

References:  1, 12, 15, 16, DSS05.04, DSS05.10, DSS06.10, 3.1.10, CCI-000058, CCI-000056, 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, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, CM-6(a), PR.AC-7, FMT_MOF_EXT.1, SRG-OS-000030-GPOS-00011, SRG-OS-000028-GPOS-00009, SRG-OS-000030-VMM-000110


Complexity:low
Disruption:low
Strategy:enable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if ! rpm -q --quiet "tmux" ; then
    dnf install -y "tmux"
fi

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

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure tmux is installed
  package:
    name: tmux
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.10
    - NIST-800-53-CM-6(a)
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_tmux_installed

Complexity:low
Disruption:low
Strategy:enable
include install_tmux

class install_tmux {
  package { 'tmux':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=tmux


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

Rule   Support session locking with tmux   [ref]

The tmux terminal multiplexer is used to implement automatic session locking. It should be started from /etc/bashrc or drop-in files within /etc/profile.d/.
Rationale:
Unlike bash itself, the tmux terminal multiplexer provides a mechanism to lock sessions after period of inactivity.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_configure_bashrc_exec_tmux
Identifiers and References

References:  CCI-000056, FMT_SMF_EXT.1, SRG-OS-000031-GPOS-00012, SRG-OS-000028-GPOS-00009


Complexity:low
Disruption:low
Reboot:true
Strategy:enable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if ! grep -x '  case "$name" in sshd|login) exec tmux ;; esac' /etc/bashrc; then
    cat >> /etc/profile.d/tmux.sh <<'EOF'
if [ "$PS1" ]; then
  parent=$(ps -o ppid= -p $$)
  name=$(ps -o comm= -p $parent)
  case "$name" in sshd|login) exec tmux ;; esac
fi
EOF
fi

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

Rule   Configure tmux to lock session after inactivity   [ref]

To enable console screen locking in tmux terminal multiplexer after a period of inactivity, the lock-after-time option has to be set to nonzero value in /etc/tmux.conf.
Rationale:
Locking the session after a period of inactivity limits the potential exposure if the session is left unattended.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_configure_tmux_lock_after_time
Identifiers and References

References:  CCI-000057, FMT_SMF_EXT.1, SRG-OS-000029-GPOS-00010


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

tmux_conf="/etc/tmux.conf"

if grep -qP '^\s*set\s+-g\s+lock-after-time' "$tmux_conf" ; then
    sed -i 's/^\s*set\s\+-g\s\+lock-after-time.*$/set -g lock-after-time 900/' "$tmux_conf"
else
    echo "set -g lock-after-time 900" >> "$tmux_conf"
fi

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Configure tmux to lock session after inactivity
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/tmux.conf
        create: false
        regexp: ^\s*set -g lock-after-time\s+
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/tmux.conf
      lineinfile:
        path: /etc/tmux.conf
        create: false
        regexp: ^\s*set -g lock-after-time\s+
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/tmux.conf
      lineinfile:
        path: /etc/tmux.conf
        create: true
        regexp: ^\s*set -g lock-after-time\s+
        line: set -g lock-after-time 900
        state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - configure_tmux_lock_after_time
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Configure the tmux Lock Command   [ref]

To enable console screen locking in tmux terminal multiplexer, the vlock command must be configured to be used as a locking mechanism. Add the following line to /etc/tmux.conf:
set -g lock-command vlock
. The console can now be locked with the following key combination:
ctrl+b :lock-session
Rationale:
The tmux package allows for a session lock to be implemented and configured. However, the session lock is implemented by an external command. The tmux default configuration does not contain an effective session lock.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_configure_tmux_lock_command
Identifiers and References

References:  CCI-000056, CCI-000058, AC-11(a), AC-11(b), CM-6(a), SRG-OS-000028-GPOS-00009, SRG-OS-000028-VMM-000090, SRG-OS-000030-VMM-000110


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

tmux_conf="/etc/tmux.conf"

if grep -qP '^\s*set\s+-g\s+lock-command' "$tmux_conf" ; then
    sed -i 's/^\s*set\s\+-g\s\+lock-command.*$/set -g lock-command vlock/' "$tmux_conf"
else
    echo "set -g lock-command vlock" >> "$tmux_conf"
fi

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Configure the tmux Lock Command
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/tmux.conf
        create: false
        regexp: ^\s*set -g lock-command\s+
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/tmux.conf
      lineinfile:
        path: /etc/tmux.conf
        create: false
        regexp: ^\s*set -g lock-command\s+
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/tmux.conf
      lineinfile:
        path: /etc/tmux.conf
        create: true
        regexp: ^\s*set -g lock-command\s+
        line: set -g lock-command vlock
        state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AC-11(a)
    - NIST-800-53-AC-11(b)
    - NIST-800-53-CM-6(a)
    - configure_tmux_lock_command
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Prevent user from disabling the screen lock   [ref]

The tmux terminal multiplexer is used to implement automatic session locking. It should not be listed in /etc/shells.
Rationale:
Not listing tmux among permitted shells prevents malicious program running as user from lowering security by disabling the screen lock.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_no_tmux_in_shells
Identifiers and References

References:  CCI-000056, CM-6, FMT_SMF_EXT.1, SRG-OS-000324-GPOS-00125, SRG-OS-000028-GPOS-00009


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

if grep -q 'tmux$' /etc/shells ; then
	sed -i '/tmux$/d' /etc/shells
fi

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

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,/bin/sh%0A/bin/bash%0A/usr/bin/sh%0A/usr/bin/bash%0A
        mode: 0644
        path: /etc/shells
        overwrite: true

Rule   Disable debug-shell SystemD Service   [ref]

SystemD's debug-shell service is intended to diagnose SystemD related boot issues with various systemctl commands. Once enabled and following a system reboot, the root shell will be available on tty9 which is access by pressing CTRL-ALT-F9. The debug-shell service should only be used for SystemD related issues and should otherwise be disabled.

By default, the debug-shell SystemD service is already disabled. The debug-shell service can be disabled with the following command:
$ sudo systemctl mask --now debug-shell.service
Rationale:
This prevents attackers with physical access from trivially bypassing security on the machine through valid troubleshooting configurations and gaining root access when the system is rebooted.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_service_debug-shell_disabled
Identifiers and References

References:  3.4.5, CCI-000366, 164.308(a)(1)(ii)(B), 164.308(a)(7)(i), 164.308(a)(7)(ii)(A), 164.310(a)(1), 164.310(a)(2)(i), 164.310(a)(2)(ii), 164.310(a)(2)(iii), 164.310(b), 164.310(c), 164.310(d)(1), 164.310(d)(2)(iii), CM-6, FIA_UAU.1, SRG-OS-000324-GPOS-00125, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:low
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

SYSTEMCTL_EXEC='/usr/bin/systemctl'
"$SYSTEMCTL_EXEC" stop 'debug-shell.service'
"$SYSTEMCTL_EXEC" disable 'debug-shell.service'
"$SYSTEMCTL_EXEC" mask 'debug-shell.service'
# Disable socket activation if we have a unit file for it
if "$SYSTEMCTL_EXEC" list-unit-files | grep -q '^debug-shell.socket'; then
    "$SYSTEMCTL_EXEC" stop 'debug-shell.socket'
    "$SYSTEMCTL_EXEC" mask 'debug-shell.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 'debug-shell.service' || true

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

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service debug-shell
  block:

    - name: Disable service debug-shell
      systemd:
        name: debug-shell.service
        enabled: 'no'
        state: stopped
        masked: 'yes'
      ignore_errors: 'yes'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.4.5
    - NIST-800-53-CM-6
    - disable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_debug-shell_disabled

- name: Unit Socket Exists - debug-shell.socket
  command: systemctl list-unit-files debug-shell.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:
    - NIST-800-171-3.4.5
    - NIST-800-53-CM-6
    - disable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_debug-shell_disabled

- name: Disable socket debug-shell
  systemd:
    name: debug-shell.socket
    enabled: 'no'
    state: stopped
    masked: 'yes'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"debug-shell.socket" in socket_file_exists.stdout_lines[1]'
  tags:
    - NIST-800-171-3.4.5
    - NIST-800-53-CM-6
    - disable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_debug-shell_disabled

Complexity:low
Disruption:low
Strategy:enable
include disable_debug-shell

class disable_debug-shell {
  service {'debug-shell':
    enable => false,
    ensure => 'stopped',
  }
}

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    systemd:
      units:
      - enabled: false
        name: debug-shell.service


[customizations.services]
disabled = ["debug-shell"]

Rule   Disable Ctrl-Alt-Del Burst Action   [ref]

By default, SystemD will reboot the system if the Ctrl-Alt-Del key sequence is pressed Ctrl-Alt-Delete more than 7 times in 2 seconds.

To configure the system to ignore the CtrlAltDelBurstAction setting, add or modify the following to /etc/systemd/system.conf:
CtrlAltDelBurstAction=none
Warning:  Disabling the Ctrl-Alt-Del key sequence in /etc/init/control-alt-delete.conf DOES NOT disable the Ctrl-Alt-Del key sequence if running in runlevel 6 (e.g. in GNOME, KDE, etc.)! The Ctrl-Alt-Del key sequence will only be disabled if running in the non-graphical runlevel 3.
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.
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_disable_ctrlaltdel_burstaction
Identifiers and References

References:  12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 3.4.5, CCI-000366, 164.308(a)(1)(ii)(B), 164.308(a)(7)(i), 164.308(a)(7)(ii)(A), 164.310(a)(1), 164.310(a)(2)(i), 164.310(a)(2)(ii), 164.310(a)(2)(iii), 164.310(b), 164.310(c), 164.310(d)(1), 164.310(d)(2)(iii), 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), CM-6(a), PR.AC-4, PR.DS-5, SRG-OS-000324-GPOS-00125, SRG-OS-000480-GPOS-00227


# Remediation is applicable only in certain platforms
if rpm --quiet -q systemd; then

# 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 "/etc/systemd/system.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^CtrlAltDelBurstAction=")

# shellcheck disable=SC2059
printf -v formatted_output "%s=%s" "$stripped_key" "none"

# 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 -i -e "^CtrlAltDelBurstAction=\\>" "/etc/systemd/system.conf"; then
    "${sed_command[@]}" "s/^CtrlAltDelBurstAction=\\>.*/$formatted_output/gi" "/etc/systemd/system.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/systemd/system.conf"
fi

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

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,CtrlAltDelBurstAction%3Dnone
        mode: 0644
        path: /etc/systemd/system.conf.d/disable_ctrlaltdelete_burstaction.conf
        overwrite: true

Rule   Disable Ctrl-Alt-Del Reboot Activation   [ref]

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.
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_disable_ctrlaltdel_reboot
Identifiers and References

References:  12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 3.4.5, CCI-000366, 164.308(a)(1)(ii)(B), 164.308(a)(7)(i), 164.308(a)(7)(ii)(A), 164.310(a)(1), 164.310(a)(2)(i), 164.310(a)(2)(ii), 164.310(a)(2)(iii), 164.310(b), 164.310(c), 164.310(d)(1), 164.310(d)(2)(iii), 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-6(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000324-GPOS-00125, SRG-OS-000480-GPOS-00227


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

systemctl disable --now ctrl-alt-del.target
systemctl mask --now ctrl-alt-del.target

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

Complexity:low
Disruption:low
Reboot:true
Strategy:restrict
---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    systemd:
      units:
      - name: ctrl-alt-del.target
        mask: true

Rule   Verify that Interactive Boot is Disabled   [ref]

AlmaLinux 9 systems support an "interactive boot" option that can be used to prevent services from being started. On a AlmaLinux 9 system, interactive boot can be enabled by providing a 1, yes, true, or on value to the systemd.confirm_spawn kernel argument in /etc/default/grub. Remove any instance of
systemd.confirm_spawn=(1|yes|true|on)
from the kernel arguments in that file to disable interactive boot. It is also required to change the runtime configuration, run:
/sbin/grubby --update-kernel=ALL --remove-args="systemd.confirm_spawn"
Rationale:
Using interactive boot, the console user could disable auditing, firewalls, or other services, weakening system security.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_grub2_disable_interactive_boot
Identifiers and References

References:  11, 12, 14, 15, 16, 18, 3, 5, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.03, DSS06.06, 3.1.2, 3.4.5, CCI-000213, 164.308(a)(1)(ii)(B), 164.308(a)(7)(i), 164.308(a)(7)(ii)(A), 164.310(a)(1), 164.310(a)(2)(i), 164.310(a)(2)(ii), 164.310(a)(2)(iii), 164.310(b), 164.310(c), 164.310(d)(1), 164.310(d)(2)(iii), 4.3.3.2.2, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, A.6.1.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, SC-2(1), CM-6(a), PR.AC-4, PR.AC-6, PR.PT-3, FIA_UAU.1, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:low
Reboot:true
Strategy:restrict
# Remediation is applicable only in certain platforms
if rpm --quiet -q grub2-common; then

CONFIRM_SPAWN_YES="systemd.confirm_spawn=\(1\|yes\|true\|on\)"
CONFIRM_SPAWN_NO="systemd.confirm_spawn=no"

if grep -q "\(GRUB_CMDLINE_LINUX\|GRUB_CMDLINE_LINUX_DEFAULT\)" /etc/default/grub
then
	sed -i "s/${CONFIRM_SPAWN_YES}/${CONFIRM_SPAWN_NO}/" /etc/default/grub
fi
# Remove 'systemd.confirm_spawn' kernel argument also from runtime settings
/sbin/grubby --update-kernel=ALL --remove-args="systemd.confirm_spawn"

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

Rule   Require Authentication for Single User Mode   [ref]

Single-user mode is intended as a system recovery method, providing a single user root access to the system by providing a boot option at startup. By default, no authentication is performed if single-user mode is selected.

By default, single-user mode is protected by requiring a password and is set in /usr/lib/systemd/system/rescue.service.
Rationale:
This prevents attackers with physical access from trivially bypassing security on the machine and gaining root access. Such accesses are further prevented by configuring the bootloader password.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_require_singleuser_auth
Identifiers and References

References:  1, 11, 12, 14, 15, 16, 18, 3, 5, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.06, DSS06.10, 3.1.1, 3.4.5, CCI-000213, 164.308(a)(1)(ii)(B), 164.308(a)(7)(i), 164.308(a)(7)(ii)(A), 164.310(a)(1), 164.310(a)(2)(i), 164.310(a)(2)(ii), 164.310(a)(2)(iii), 164.310(b), 164.310(c), 164.310(d)(1), 164.310(d)(2)(iii), 4.3.3.2.2, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, A.18.1.4, A.6.1.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, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.2.3, CIP-004-6 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.2, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, IA-2, AC-3, CM-6(a), PR.AC-1, PR.AC-4, PR.AC-6, PR.AC-7, PR.PT-3, FIA_UAU.1, SRG-OS-000080-GPOS-00048


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

service_file="/usr/lib/systemd/system/rescue.service"

sulogin="/usr/lib/systemd/systemd-sulogin-shell rescue"

if grep "^ExecStart=.*" "$service_file" ; then
    sed -i "s%^ExecStart=.*%ExecStart=-$sulogin%" "$service_file"
else
    echo "ExecStart=-$sulogin" >> "$service_file"
fi

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

Complexity:low
Disruption:low
Strategy:restrict
- name: require single user mode password
  lineinfile:
    create: true
    dest: /usr/lib/systemd/system/rescue.service
    regexp: ^#?ExecStart=
    line: ExecStart=-/usr/lib/systemd/systemd-sulogin-shell rescue
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.1
    - NIST-800-171-3.4.5
    - NIST-800-53-AC-3
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-2
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - require_singleuser_auth
    - restrict_strategy
Group   Protect Accounts by Restricting Password-Based Login   Group contains 3 groups and 4 rules
[ref]   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.
Group   Set Password Expiration Parameters   Group contains 1 rule
[ref]   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
Group   Verify Proper Storage and Existence of Password Hashes   Group contains 1 rule
[ref]   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.

Rule   Prevent Login to Accounts With Empty Password   [ref]

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 /etc/pam.d/system-auth to prevent logins with empty passwords. Note that this rule is not applicable for systems running within a container. Having user with empty password within a container is not considered a risk, because it should not be possible to directly login into a container anyway.
Warning:  If the system relies on authselect tool to manage PAM settings, the remediation will also use authselect tool. However, if any manual modification was made in PAM files, the authselect integrity check will fail and the remediation will be aborted in order to preserve intentional changes. In this case, an informative message will be shown in the remediation report.
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.
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_no_empty_passwords
Identifiers and References

References:  1, 12, 13, 14, 15, 16, 18, 3, 5, 5.5.2, APO01.06, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.02, DSS06.03, DSS06.10, 3.1.1, 3.1.5, CCI-000366, 164.308(a)(1)(ii)(B), 164.308(a)(7)(i), 164.308(a)(7)(ii)(A), 164.310(a)(1), 164.310(a)(2)(i), 164.310(a)(2)(ii), 164.310(a)(2)(iii), 164.310(b), 164.310(c), 164.310(d)(1), 164.310(d)(2)(iii), 4.3.3.2.2, 4.3.3.5.1, 4.3.3.5.2, 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.2, 4.3.3.7.3, 4.3.3.7.4, SR 1.1, SR 1.10, 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 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.18.1.4, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.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, IA-5(1)(a), IA-5(c), CM-6(a), PR.AC-1, PR.AC-4, PR.AC-6, PR.AC-7, PR.DS-5, FIA_UAU.1, Req-8.2.3, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Strategy:configure
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

SYSTEM_AUTH="/etc/pam.d/system-auth"
PASSWORD_AUTH="/etc/pam.d/password-auth"

if [ -f /usr/bin/authselect ]; then
    if authselect check; then
        authselect enable-feature without-nullok
        authselect apply-changes
    else
        echo "
authselect integrity check failed. Remediation aborted!
This remediation could not be applied because the authselect profile is not intact.
It is not recommended to manually edit the PAM files when authselect is available
In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
        false
    fi
else
    sed --follow-symlinks -i 's/\<nullok\>//g' $SYSTEM_AUTH
    sed --follow-symlinks -i 's/\<nullok\>//g' $PASSWORD_AUTH
fi

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

Complexity:low
Disruption:medium
Strategy:configure
- name: Check if system relies on authselect
  ansible.builtin.stat:
    path: /usr/bin/authselect
  register: result_authselect_present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CJIS-5.5.2
    - 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: Check integrity of authselect current profile
  ansible.builtin.command:
    cmd: authselect check
  register: result_authselect_check_cmd
  changed_when: false
  ignore_errors: true
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - result_authselect_present.stat.exists
  tags:
    - CJIS-5.5.2
    - 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: Get authselect current features
  ansible.builtin.shell:
    cmd: authselect current | tail -n+3 | awk '{ print $2 }'
  register: result_authselect_features
  changed_when: false
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - result_authselect_present.stat.exists
    - result_authselect_check_cmd is success
  tags:
    - CJIS-5.5.2
    - 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: Ensure nullok property is absent via authselect tool
  ansible.builtin.command:
    cmd: authselect enable-feature without-nullok
  register: result_authselect_cmd
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - result_authselect_present.stat.exists
    - result_authselect_check_cmd is success
    - result_authselect_features.stdout is not search("without-nullok")
  tags:
    - CJIS-5.5.2
    - 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: Informative message based on the authselect integrity check result
  ansible.builtin.assert:
    that:
      - result_authselect_check_cmd is success
    fail_msg:
      - authselect integrity check failed. Remediation aborted!
      - This remediation could not be applied because the authselect profile is not
        intact.
      - It is not recommended to manually edit the PAM files when authselect is available
      - In cases where the default authselect profile does not cover a specific demand,
        a custom authselect profile is recommended.
    success_msg:
      - authselect integrity check passed
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CJIS-5.5.2
    - 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: Ensure nullok property is absent by directly editing pam files
  replace:
    dest: '{{ item }}'
    regexp: nullok
  loop:
    - /etc/pam.d/system-auth
    - /etc/pam.d/password-auth
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - not result_authselect_present.stat.exists
  tags:
    - CJIS-5.5.2
    - 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

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,%23%20Generated%20by%20authselect%20on%20Sat%20Oct%2027%2014%3A59%3A36%202018%0A%23%20Do%20not%20modify%20this%20file%20manually.%0A%0Aauth%20%20%20%20%20%20%20%20required%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_env.so%0Aauth%20%20%20%20%20%20%20%20required%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_faildelay.so%20delay%3D2000000%0Aauth%20%20%20%20%20%20%20%20sufficient%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_fprintd.so%0Aauth%20%20%20%20%20%20%20%20%5Bdefault%3D1%20ignore%3Dignore%20success%3Dok%5D%20%20%20%20%20%20%20%20%20pam_succeed_if.so%20uid%20%3E%3D%201000%20quiet%0Aauth%20%20%20%20%20%20%20%20%5Bdefault%3D1%20ignore%3Dignore%20success%3Dok%5D%20%20%20%20%20%20%20%20%20pam_localuser.so%0Aauth%20%20%20%20%20%20%20%20sufficient%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_unix.so%20try_first_pass%0Aauth%20%20%20%20%20%20%20%20requisite%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_succeed_if.so%20uid%20%3E%3D%201000%20quiet_success%0Aauth%20%20%20%20%20%20%20%20sufficient%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_sss.so%20forward_pass%0Aauth%20%20%20%20%20%20%20%20required%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_deny.so%0A%0Aaccount%20%20%20%20%20required%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_unix.so%0Aaccount%20%20%20%20%20sufficient%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_localuser.so%0Aaccount%20%20%20%20%20sufficient%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_succeed_if.so%20uid%20%3C%201000%20quiet%0Aaccount%20%20%20%20%20%5Bdefault%3Dbad%20success%3Dok%20user_unknown%3Dignore%5D%20pam_sss.so%0Aaccount%20%20%20%20%20required%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_permit.so%0A%0Apassword%20%20%20%20requisite%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_pwquality.so%20try_first_pass%20local_users_only%0Apassword%20%20%20%20sufficient%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_unix.so%20sha512%20shadow%20try_first_pass%20use_authtok%0Apassword%20%20%20%20sufficient%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_sss.so%20use_authtok%0Apassword%20%20%20%20required%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_deny.so%0A%0Asession%20%20%20%20%20optional%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_keyinit.so%20revoke%0Asession%20%20%20%20%20required%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_limits.so%0A-session%20%20%20%20optional%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_systemd.so%0Asession%20%20%20%20%20%5Bsuccess%3D1%20default%3Dignore%5D%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_succeed_if.so%20service%20in%20crond%20quiet%20use_uid%0Asession%20%20%20%20%20required%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_unix.so%0Asession%20%20%20%20%20optional%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_sss.so%0A
        mode: 0644
        path: /etc/pam.d/password-auth
        overwrite: true
      - contents:
          source: data:,%23%20Generated%20by%20authselect%20on%20Sat%20Oct%2027%2014%3A59%3A36%202018%0A%23%20Do%20not%20modify%20this%20file%20manually.%0A%0Aauth%20%20%20%20%20%20%20%20required%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_env.so%0Aauth%20%20%20%20%20%20%20%20required%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_faildelay.so%20delay%3D2000000%0Aauth%20%20%20%20%20%20%20%20sufficient%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_fprintd.so%0Aauth%20%20%20%20%20%20%20%20%5Bdefault%3D1%20ignore%3Dignore%20success%3Dok%5D%20%20%20%20%20%20%20%20%20pam_succeed_if.so%20uid%20%3E%3D%201000%20quiet%0Aauth%20%20%20%20%20%20%20%20%5Bdefault%3D1%20ignore%3Dignore%20success%3Dok%5D%20%20%20%20%20%20%20%20%20pam_localuser.so%0Aauth%20%20%20%20%20%20%20%20sufficient%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_unix.so%20try_first_pass%0Aauth%20%20%20%20%20%20%20%20requisite%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_succeed_if.so%20uid%20%3E%3D%201000%20quiet_success%0Aauth%20%20%20%20%20%20%20%20sufficient%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_sss.so%20forward_pass%0Aauth%20%20%20%20%20%20%20%20required%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_deny.so%0A%0Aaccount%20%20%20%20%20required%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_unix.so%0Aaccount%20%20%20%20%20sufficient%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_localuser.so%0Aaccount%20%20%20%20%20sufficient%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_succeed_if.so%20uid%20%3C%201000%20quiet%0Aaccount%20%20%20%20%20%5Bdefault%3Dbad%20success%3Dok%20user_unknown%3Dignore%5D%20pam_sss.so%0Aaccount%20%20%20%20%20required%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_permit.so%0A%0Apassword%20%20%20%20requisite%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_pwquality.so%20try_first_pass%20local_users_only%0Apassword%20%20%20%20sufficient%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_unix.so%20sha512%20shadow%20try_first_pass%20use_authtok%0Apassword%20%20%20%20sufficient%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_sss.so%20use_authtok%0Apassword%20%20%20%20required%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_deny.so%0A%0Asession%20%20%20%20%20optional%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_keyinit.so%20revoke%0Asession%20%20%20%20%20required%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_limits.so%0A-session%20%20%20%20optional%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_systemd.so%0Asession%20%20%20%20%20%5Bsuccess%3D1%20default%3Dignore%5D%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_succeed_if.so%20service%20in%20crond%20quiet%20use_uid%0Asession%20%20%20%20%20required%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_unix.so%0Asession%20%20%20%20%20optional%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20pam_sss.so%0A
        mode: 0644
        path: /etc/pam.d/system-auth
        overwrite: true
Group   Restrict Root Logins   Group contains 2 rules
[ref]   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.

Rule   Enforce usage of pam_wheel for su authentication   [ref]

To ensure that only users who are members of the wheel group can run commands with altered privileges through the su command, make sure that the following line exists in the file /etc/pam.d/su:
auth             required        pam_wheel.so use_uid
Rationale:
The su program allows to run commands with a substitute user and group ID. It is commonly used to run commands as the root user. Limiting access to such command is considered a good security practice.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_use_pam_wheel_for_su
Identifiers and References

References:  FMT_SMF_EXT.1.1, SRG-OS-000373-GPOS-00156, SRG-OS-000312-GPOS-00123



# uncomment the option if commented
  sed '/^[[:space:]]*#[[:space:]]*auth[[:space:]]\+required[[:space:]]\+pam_wheel\.so[[:space:]]\+use_uid$/s/^[[:space:]]*#//' -i /etc/pam.d/su

Complexity:low
Disruption:low
Strategy:restrict
- name: restrict usage of su command only to members of wheel group
  replace:
    path: /etc/pam.d/su
    regexp: ^[\s]*#[\s]*auth[\s]+required[\s]+pam_wheel\.so[\s]+use_uid$
    replace: auth             required        pam_wheel.so use_uid
  tags:
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - use_pam_wheel_for_su
Group   Secure Session Configuration Files for Login Accounts   Group contains 1 group and 4 rules
[ref]   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.
Group   Ensure that Users Have Sensible Umask Values   Group contains 3 rules
[ref]   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.

Rule   Ensure the Default Bash Umask is Set Correctly   [ref]

To ensure the default umask for users of the Bash shell is set properly, add or correct the umask setting in /etc/bashrc to read as follows:
umask 027
Rationale:
The umask value influences the permissions assigned to files when they are created. A misconfigured umask value could result in files with excessive permissions that can be read or written to by unauthorized users.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_umask_etc_bashrc
Identifiers and References

References:  BP28(R35), 18, APO13.01, BAI03.01, BAI03.02, BAI03.03, CCI-000366, 4.3.4.3.3, A.14.1.1, A.14.2.1, A.14.2.5, A.6.1.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, AC-6(1), CM-6(a), PR.IP-2, SRG-OS-000480-GPOS-00228, SRG-OS-000480-GPOS-00227



var_accounts_user_umask='027'


grep -q umask /etc/bashrc && \
  sed -i "s/umask.*/umask $var_accounts_user_umask/g" /etc/bashrc
if ! [ $? -eq 0 ]; then
    echo "umask $var_accounts_user_umask" >> /etc/bashrc
fi

Complexity:low
Disruption:low
Strategy:restrict
- name: XCCDF Value var_accounts_user_umask # promote to variable
  set_fact:
    var_accounts_user_umask: !!str 027
  tags:
    - always

- name: Replace user umask in /etc/bashrc
  replace:
    path: /etc/bashrc
    regexp: umask.*
    replace: umask {{ var_accounts_user_umask }}
  register: umask_replace
  tags:
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - accounts_umask_etc_bashrc
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Append user umask in /etc/bashrc
  lineinfile:
    create: true
    path: /etc/bashrc
    line: umask {{ var_accounts_user_umask }}
  when: umask_replace is not changed
  tags:
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - accounts_umask_etc_bashrc
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Ensure the Default C Shell Umask is Set Correctly   [ref]

To ensure the default umask for users of the C shell is set properly, add or correct the umask setting in /etc/csh.cshrc to read as follows:
umask 027
Rationale:
The umask value influences the permissions assigned to files when they are created. A misconfigured umask value could result in files with excessive permissions that can be read or written to by unauthorized users.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_umask_etc_csh_cshrc
Identifiers and References

References:  18, APO13.01, BAI03.01, BAI03.02, BAI03.03, CCI-000366, 4.3.4.3.3, A.14.1.1, A.14.2.1, A.14.2.5, A.6.1.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, AC-6(1), CM-6(a), PR.IP-2, SRG-OS-000480-GPOS-00228, SRG-OS-000480-GPOS-00227



var_accounts_user_umask='027'


grep -q umask /etc/csh.cshrc && \
  sed -i "s/umask.*/umask $var_accounts_user_umask/g" /etc/csh.cshrc
if ! [ $? -eq 0 ]; then
    echo "umask $var_accounts_user_umask" >> /etc/csh.cshrc
fi

Complexity:low
Disruption:low
Strategy:restrict
- name: XCCDF Value var_accounts_user_umask # promote to variable
  set_fact:
    var_accounts_user_umask: !!str 027
  tags:
    - always

- name: Replace user umask in /etc/csh.cshrc
  replace:
    path: /etc/csh.cshrc
    regexp: umask.*
    replace: umask {{ var_accounts_user_umask }}
  register: umask_replace
  tags:
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - accounts_umask_etc_csh_cshrc
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Append user umask in /etc/csh.cshrc
  lineinfile:
    create: true
    path: /etc/csh.cshrc
    line: umask {{ var_accounts_user_umask }}
  when: umask_replace is not changed
  tags:
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - accounts_umask_etc_csh_cshrc
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Ensure the Default Umask is Set Correctly in /etc/profile   [ref]

To ensure the default umask controlled by /etc/profile is set properly, add or correct the umask setting in /etc/profile to read as follows:
umask 027
Rationale:
The umask value influences the permissions assigned to files when they are created. A misconfigured umask value could result in files with excessive permissions that can be read or written to by unauthorized users.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_umask_etc_profile
Identifiers and References

References:  BP28(R35), 18, APO13.01, BAI03.01, BAI03.02, BAI03.03, CCI-000366, 4.3.4.3.3, A.14.1.1, A.14.2.1, A.14.2.5, A.6.1.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, AC-6(1), CM-6(a), PR.IP-2, SRG-OS-000480-GPOS-00228, SRG-OS-000480-GPOS-00227



var_accounts_user_umask='027'


grep -q umask /etc/profile && \
  sed -i "s/umask.*/umask $var_accounts_user_umask/g" /etc/profile
if ! [ $? -eq 0 ]; then
    echo "umask $var_accounts_user_umask" >> /etc/profile
fi

Complexity:low
Disruption:low
Strategy:restrict
- name: XCCDF Value var_accounts_user_umask # promote to variable
  set_fact:
    var_accounts_user_umask: !!str 027
  tags:
    - always

- name: Replace user umask in /etc/profile
  replace:
    path: /etc/profile
    regexp: umask.*
    replace: umask {{ var_accounts_user_umask }}
  register: umask_replace
  tags:
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - accounts_umask_etc_profile
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Append user umask in /etc/profile
  lineinfile:
    create: true
    path: /etc/profile
    line: umask {{ var_accounts_user_umask }}
  when: umask_replace is not changed
  tags:
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - accounts_umask_etc_profile
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
Group   System Accounting with auditd   Group contains 2 groups and 25 rules
[ref]   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-single/selinux_users_and_administrators_guide/index#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".
Group   Configure auditd Data Retention   Group contains 4 rules
[ref]   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.

Rule   Configure auditd flush priority   [ref]

The auditd service can be configured to synchronously write audit event data to disk. Add or correct the following line in /etc/audit/auditd.conf to ensure that audit event data is fully synchronized with the log files on the disk:
flush = incremental_async
Rationale:
Audit data should be synchronously written to disk to ensure log integrity. These parameters assure that all audit event data is fully synchronized with the log files on the disk.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_auditd_data_retention_flush
Identifiers and References

References:  1, 12, 13, 14, 15, 16, 2, 3, 5, 6, 7, 8, 9, APO10.01, APO10.03, APO10.04, APO10.05, APO11.04, BAI03.05, DSS01.03, DSS03.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, MEA01.01, MEA01.02, MEA01.03, MEA01.04, MEA01.05, MEA02.01, 3.3.1, CCI-001576, 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.3.2.6.7, 4.3.3.3.9, 4.3.3.5.8, 4.3.4.4.7, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 2.10, SR 2.11, SR 2.12, SR 2.8, SR 2.9, SR 6.1, SR 6.2, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, A.14.2.7, A.15.2.1, A.15.2.2, CIP-004-6 R2.2.3, CIP-004-6 R3.3, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, CIP-007-3 R6.5, AU-11, CM-6(a), DE.CM-1, DE.CM-3, DE.CM-7, ID.SC-4, PR.PT-1, SRG-OS-000480-GPOS-00227


# Remediation is applicable only in certain platforms
if rpm --quiet -q audit; then

var_auditd_flush='incremental_async'


AUDITCONFIG=/etc/audit/auditd.conf

# if flush is present, flush param edited to var_auditd_flush
# else flush param is defined by var_auditd_flush
#
# the freq param is only used for values 'incremental' and 'incremental_async' and will be
# commented out if flush != incremental or flush != incremental_async
#
# if flush == incremental or flush == incremental_async && freq param is not defined, it 
# will be defined as the package-default value of 20

grep -q ^flush $AUDITCONFIG && \
  sed -i 's/^flush.*/flush = '"$var_auditd_flush"'/g' $AUDITCONFIG
if ! [ $? -eq 0 ]; then
  echo "flush = $var_auditd_flush" >> $AUDITCONFIG
fi

if ! [ "$var_auditd_flush" == "incremental" ] && ! [ "$var_auditd_flush" == "incremental_async" ]; then
  sed -i 's/^freq/##freq/g' $AUDITCONFIG
elif [ "$var_auditd_flush" == "incremental" ] || [ "$var_auditd_flush" == "incremental_async" ]; then
  grep -q freq $AUDITCONFIG && \
    sed -i 's/^#\+freq/freq/g' $AUDITCONFIG
  if ! [ $? -eq 0 ]; then
    echo "freq = 20" >> $AUDITCONFIG
  fi
fi

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - NIST-800-171-3.3.1
    - NIST-800-53-AU-11
    - NIST-800-53-CM-6(a)
    - auditd_data_retention_flush
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
- name: XCCDF Value var_auditd_flush # promote to variable
  set_fact:
    var_auditd_flush: !!str incremental_async
  tags:
    - always

- name: Configure auditd Flush Priority
  lineinfile:
    dest: /etc/audit/auditd.conf
    regexp: ^\s*flush\s*=\s*.*$
    line: flush = {{ var_auditd_flush }}
    state: present
    create: true
  when: '"audit" in ansible_facts.packages'
  tags:
    - NIST-800-171-3.3.1
    - NIST-800-53-AU-11
    - NIST-800-53-CM-6(a)
    - auditd_data_retention_flush
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Complexity:low
Disruption:low
Reboot:true
Strategy:restrict
---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,{{ %23%0A%23%20This%20file%20controls%20the%20configuration%20of%20the%20audit%20daemon%0A%23%0A%0Alocal_events%20%3D%20yes%0Awrite_logs%20%3D%20yes%0Alog_file%20%3D%20/var/log/audit/audit.log%0Alog_group%20%3D%20root%0Alog_format%20%3D%20ENRICHED%0Aflush%20%3D%20%7B%7B.var_auditd_flush%7D%7D%0Afreq%20%3D%2050%0Amax_log_file%20%3D%20%7B%7B.var_auditd_max_log_file%7D%7D%0Anum_logs%20%3D%20%7B%7B.var_auditd_num_logs%7D%7D%0Apriority_boost%20%3D%204%0Aname_format%20%3D%20hostname%0A%23%23name%20%3D%20mydomain%0Amax_log_file_action%20%3D%20%7B%7B.var_auditd_max_log_file_action%7D%7D%0Aspace_left%20%3D%20%7B%7B.var_auditd_space_left%7D%7D%0Aspace_left_action%20%3D%20%7B%7B.var_auditd_space_left_action%7D%7D%0Averify_email%20%3D%20yes%0Aaction_mail_acct%20%3D%20%7B%7B.var_auditd_action_mail_acct%7D%7D%0Aadmin_space_left%20%3D%2050%0Aadmin_space_left_action%20%3D%20syslog%0Adisk_full_action%20%3D%20%7B%7B.var_auditd_disk_full_action%7D%7D%0Adisk_error_action%20%3D%20%7B%7B.var_auditd_disk_error_action%7D%7D%0Ause_libwrap%20%3D%20yes%0A%23%23tcp_listen_port%20%3D%2060%0Atcp_listen_queue%20%3D%205%0Atcp_max_per_addr%20%3D%201%0A%23%23tcp_client_ports%20%3D%201024-65535%0Atcp_client_max_idle%20%3D%200%0Atransport%20%3D%20TCP%0Akrb5_principal%20%3D%20auditd%0A%23%23krb5_key_file%20%3D%20/etc/audit/audit.key%0Adistribute_network%20%3D%20no%0Aq_depth%20%3D%20400%0Aoverflow_action%20%3D%20syslog%0Amax_restarts%20%3D%2010%0Aplugin_dir%20%3D%20/etc/audit/plugins.d }}
        mode: 0640
        path: /etc/audit/auditd.conf
        overwrite: true

Rule   Set number of records to cause an explicit flush to audit logs   [ref]

To configure Audit daemon to issue an explicit flush to disk command after writing 50 records, set freq to 50 in /etc/audit/auditd.conf.
Rationale:
If option freq isn't set to 50, the flush to disk may happen after higher number of records, increasing the danger of audit loss.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_auditd_freq
Identifiers and References

References:  CM-6, FAU_GEN.1, SRG-OS-000051-GPOS-00024


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if rpm --quiet -q audit; then

if [ -e "/etc/audit/auditd.conf" ] ; then
    
    LC_ALL=C sed -i "/^\s*freq\s*=\s*/Id" "/etc/audit/auditd.conf"
else
    touch "/etc/audit/auditd.conf"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/audit/auditd.conf"

cp "/etc/audit/auditd.conf" "/etc/audit/auditd.conf.bak"
# Insert at the end of the file
printf '%s\n' "freq = 50" >> "/etc/audit/auditd.conf"
# Clean up after ourselves.
rm "/etc/audit/auditd.conf.bak"

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - NIST-800-53-CM-6
    - auditd_freq
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Set number of records to cause an explicit flush to audit logs
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/audit/auditd.conf
        create: false
        regexp: (?i)^\s*freq\s*=\s*
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/audit/auditd.conf
      lineinfile:
        path: /etc/audit/auditd.conf
        create: false
        regexp: (?i)^\s*freq\s*=\s*
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/audit/auditd.conf
      lineinfile:
        path: /etc/audit/auditd.conf
        create: true
        regexp: (?i)^\s*freq\s*=\s*
        line: freq = 50
        state: present
  when: '"audit" in ansible_facts.packages'
  tags:
    - NIST-800-53-CM-6
    - auditd_freq
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Complexity:low
Disruption:low
Reboot:true
Strategy:restrict
---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,{{ %23%0A%23%20This%20file%20controls%20the%20configuration%20of%20the%20audit%20daemon%0A%23%0A%0Alocal_events%20%3D%20yes%0Awrite_logs%20%3D%20yes%0Alog_file%20%3D%20/var/log/audit/audit.log%0Alog_group%20%3D%20root%0Alog_format%20%3D%20ENRICHED%0Aflush%20%3D%20%7B%7B.var_auditd_flush%7D%7D%0Afreq%20%3D%2050%0Amax_log_file%20%3D%20%7B%7B.var_auditd_max_log_file%7D%7D%0Anum_logs%20%3D%20%7B%7B.var_auditd_num_logs%7D%7D%0Apriority_boost%20%3D%204%0Aname_format%20%3D%20hostname%0A%23%23name%20%3D%20mydomain%0Amax_log_file_action%20%3D%20%7B%7B.var_auditd_max_log_file_action%7D%7D%0Aspace_left%20%3D%20%7B%7B.var_auditd_space_left%7D%7D%0Aspace_left_action%20%3D%20%7B%7B.var_auditd_space_left_action%7D%7D%0Averify_email%20%3D%20yes%0Aaction_mail_acct%20%3D%20%7B%7B.var_auditd_action_mail_acct%7D%7D%0Aadmin_space_left%20%3D%2050%0Aadmin_space_left_action%20%3D%20syslog%0Adisk_full_action%20%3D%20%7B%7B.var_auditd_disk_full_action%7D%7D%0Adisk_error_action%20%3D%20%7B%7B.var_auditd_disk_error_action%7D%7D%0Ause_libwrap%20%3D%20yes%0A%23%23tcp_listen_port%20%3D%2060%0Atcp_listen_queue%20%3D%205%0Atcp_max_per_addr%20%3D%201%0A%23%23tcp_client_ports%20%3D%201024-65535%0Atcp_client_max_idle%20%3D%200%0Atransport%20%3D%20TCP%0Akrb5_principal%20%3D%20auditd%0A%23%23krb5_key_file%20%3D%20/etc/audit/audit.key%0Adistribute_network%20%3D%20no%0Aq_depth%20%3D%20400%0Aoverflow_action%20%3D%20syslog%0Amax_restarts%20%3D%2010%0Aplugin_dir%20%3D%20/etc/audit/plugins.d }}
        mode: 0640
        path: /etc/audit/auditd.conf
        overwrite: true

Rule   Resolve information before writing to audit logs   [ref]

To configure Audit daemon to resolve all uid, gid, syscall, architecture, and socket address information before writing the events to disk, set log_format to ENRICHED in /etc/audit/auditd.conf.
Rationale:
If option log_format isn't set to ENRICHED, the audit records will be stored in a format exactly as the kernel sends them.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_auditd_log_format
Identifiers and References

References:  CCI-000366, CM-6, AU-3, FAU_GEN.1.2, SRG-OS-000255-GPOS-00096, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if rpm --quiet -q audit; then

if [ -e "/etc/audit/auditd.conf" ] ; then
    
    LC_ALL=C sed -i "/^\s*log_format\s*=\s*/Id" "/etc/audit/auditd.conf"
else
    touch "/etc/audit/auditd.conf"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/audit/auditd.conf"

cp "/etc/audit/auditd.conf" "/etc/audit/auditd.conf.bak"
# Insert at the end of the file
printf '%s\n' "log_format = ENRICHED" >> "/etc/audit/auditd.conf"
# Clean up after ourselves.
rm "/etc/audit/auditd.conf.bak"

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - NIST-800-53-AU-3
    - NIST-800-53-CM-6
    - auditd_log_format
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Resolve information before writing to audit logs
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/audit/auditd.conf
        create: false
        regexp: (?i)^\s*log_format\s*=\s*
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/audit/auditd.conf
      lineinfile:
        path: /etc/audit/auditd.conf
        create: false
        regexp: (?i)^\s*log_format\s*=\s*
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/audit/auditd.conf
      lineinfile:
        path: /etc/audit/auditd.conf
        create: true
        regexp: (?i)^\s*log_format\s*=\s*
        line: log_format = ENRICHED
        state: present
  when: '"audit" in ansible_facts.packages'
  tags:
    - NIST-800-53-AU-3
    - NIST-800-53-CM-6
    - auditd_log_format
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Complexity:low
Disruption:low
Reboot:true
Strategy:restrict
---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,{{ %23%0A%23%20This%20file%20controls%20the%20configuration%20of%20the%20audit%20daemon%0A%23%0A%0Alocal_events%20%3D%20yes%0Awrite_logs%20%3D%20yes%0Alog_file%20%3D%20/var/log/audit/audit.log%0Alog_group%20%3D%20root%0Alog_format%20%3D%20ENRICHED%0Aflush%20%3D%20%7B%7B.var_auditd_flush%7D%7D%0Afreq%20%3D%2050%0Amax_log_file%20%3D%20%7B%7B.var_auditd_max_log_file%7D%7D%0Anum_logs%20%3D%20%7B%7B.var_auditd_num_logs%7D%7D%0Apriority_boost%20%3D%204%0Aname_format%20%3D%20hostname%0A%23%23name%20%3D%20mydomain%0Amax_log_file_action%20%3D%20%7B%7B.var_auditd_max_log_file_action%7D%7D%0Aspace_left%20%3D%20%7B%7B.var_auditd_space_left%7D%7D%0Aspace_left_action%20%3D%20%7B%7B.var_auditd_space_left_action%7D%7D%0Averify_email%20%3D%20yes%0Aaction_mail_acct%20%3D%20%7B%7B.var_auditd_action_mail_acct%7D%7D%0Aadmin_space_left%20%3D%2050%0Aadmin_space_left_action%20%3D%20syslog%0Adisk_full_action%20%3D%20%7B%7B.var_auditd_disk_full_action%7D%7D%0Adisk_error_action%20%3D%20%7B%7B.var_auditd_disk_error_action%7D%7D%0Ause_libwrap%20%3D%20yes%0A%23%23tcp_listen_port%20%3D%2060%0Atcp_listen_queue%20%3D%205%0Atcp_max_per_addr%20%3D%201%0A%23%23tcp_client_ports%20%3D%201024-65535%0Atcp_client_max_idle%20%3D%200%0Atransport%20%3D%20TCP%0Akrb5_principal%20%3D%20auditd%0A%23%23krb5_key_file%20%3D%20/etc/audit/audit.key%0Adistribute_network%20%3D%20no%0Aq_depth%20%3D%20400%0Aoverflow_action%20%3D%20syslog%0Amax_restarts%20%3D%2010%0Aplugin_dir%20%3D%20/etc/audit/plugins.d }}
        mode: 0640
        path: /etc/audit/auditd.conf
        overwrite: true

Rule   Set hostname as computer node name in audit logs   [ref]

To configure Audit daemon to use value returned by gethostname syscall as computer node name in the audit events, set name_format to hostname in /etc/audit/auditd.conf.
Rationale:
If option name_format is left at its default value of none, audit events from different computers may be hard to distinguish.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_auditd_name_format
Identifiers and References

References:  CCI-001851, CM-6, AU-3, FAU_GEN.1.2, SRG-OS-000039-GPOS-00017, SRG-OS-000342-GPOS-00133, SRG-OS-000479-GPOS-00224


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if rpm --quiet -q audit; then

if [ -e "/etc/audit/auditd.conf" ] ; then
    
    LC_ALL=C sed -i "/^\s*name_format\s*=\s*/Id" "/etc/audit/auditd.conf"
else
    touch "/etc/audit/auditd.conf"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/audit/auditd.conf"

cp "/etc/audit/auditd.conf" "/etc/audit/auditd.conf.bak"
# Insert at the end of the file
printf '%s\n' "name_format = hostname" >> "/etc/audit/auditd.conf"
# Clean up after ourselves.
rm "/etc/audit/auditd.conf.bak"

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - NIST-800-53-AU-3
    - NIST-800-53-CM-6
    - auditd_name_format
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Set hostname as computer node name in audit logs
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/audit/auditd.conf
        create: false
        regexp: (?i)^\s*name_format\s*=\s*
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/audit/auditd.conf
      lineinfile:
        path: /etc/audit/auditd.conf
        create: false
        regexp: (?i)^\s*name_format\s*=\s*
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/audit/auditd.conf
      lineinfile:
        path: /etc/audit/auditd.conf
        create: true
        regexp: (?i)^\s*name_format\s*=\s*
        line: name_format = hostname
        state: present
  when: '"audit" in ansible_facts.packages'
  tags:
    - NIST-800-53-AU-3
    - NIST-800-53-CM-6
    - auditd_name_format
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Complexity:low
Disruption:low
Reboot:true
Strategy:restrict
---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,{{ %23%0A%23%20This%20file%20controls%20the%20configuration%20of%20the%20audit%20daemon%0A%23%0A%0Alocal_events%20%3D%20yes%0Awrite_logs%20%3D%20yes%0Alog_file%20%3D%20/var/log/audit/audit.log%0Alog_group%20%3D%20root%0Alog_format%20%3D%20ENRICHED%0Aflush%20%3D%20%7B%7B.var_auditd_flush%7D%7D%0Afreq%20%3D%2050%0Amax_log_file%20%3D%20%7B%7B.var_auditd_max_log_file%7D%7D%0Anum_logs%20%3D%20%7B%7B.var_auditd_num_logs%7D%7D%0Apriority_boost%20%3D%204%0Aname_format%20%3D%20hostname%0A%23%23name%20%3D%20mydomain%0Amax_log_file_action%20%3D%20%7B%7B.var_auditd_max_log_file_action%7D%7D%0Aspace_left%20%3D%20%7B%7B.var_auditd_space_left%7D%7D%0Aspace_left_action%20%3D%20%7B%7B.var_auditd_space_left_action%7D%7D%0Averify_email%20%3D%20yes%0Aaction_mail_acct%20%3D%20%7B%7B.var_auditd_action_mail_acct%7D%7D%0Aadmin_space_left%20%3D%2050%0Aadmin_space_left_action%20%3D%20syslog%0Adisk_full_action%20%3D%20%7B%7B.var_auditd_disk_full_action%7D%7D%0Adisk_error_action%20%3D%20%7B%7B.var_auditd_disk_error_action%7D%7D%0Ause_libwrap%20%3D%20yes%0A%23%23tcp_listen_port%20%3D%2060%0Atcp_listen_queue%20%3D%205%0Atcp_max_per_addr%20%3D%201%0A%23%23tcp_client_ports%20%3D%201024-65535%0Atcp_client_max_idle%20%3D%200%0Atransport%20%3D%20TCP%0Akrb5_principal%20%3D%20auditd%0A%23%23krb5_key_file%20%3D%20/etc/audit/audit.key%0Adistribute_network%20%3D%20no%0Aq_depth%20%3D%20400%0Aoverflow_action%20%3D%20syslog%0Amax_restarts%20%3D%2010%0Aplugin_dir%20%3D%20/etc/audit/plugins.d }}
        mode: 0640
        path: /etc/audit/auditd.conf
        overwrite: true
Group   System Accounting with auditd   Group contains 16 rules
[ref]   The auditd program can perform comprehensive monitoring of system activity. This section makes use of recommended configuration settings for specific policies or use cases. The rules in this section make use of rules defined in /usr/share/doc/audit-VERSION/rules.

Rule   Configure auditing of unsuccessful file accesses   [ref]

Ensure that unsuccessful attempts to access a file are audited. The following rules configure audit as described above:
## Unsuccessful file access (any other opens) This has to go last.
-a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-access
-a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-access
-a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-access
-a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-access    
Load new Audit rules into kernel by running:
augenrules --load
Note: This rule utilizes a file provided by Audit package to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs.
Rationale:
Unsuccessful attempts to access a file might be signs of malicious activity happening within the system. Auditing of such activities helps in their monitoring and investigation.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_audit_access_failed
Identifiers and References

References:  0582, 0584, 05885, 0586, 0846, 0957, AU-2(a), FAU_GEN.1.1.c, SRG-OS-000458-GPOS-00203, SRG-OS-000474-GPOS-00219, SRG-OS-000475-GPOS-00220, SRG-OS-000463-GPOS-00207, SRG-OS-000465-GPOS-00209, SRG-OS-000461-GPOS-00205


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules
## Unsuccessful file access (any other opens) This has to go last.
-a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-access
-a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-access
-a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-access
-a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-access
EOF

chmod o-rwx /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules

augenrules --load

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Put contents into /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules according
    to policy
  copy:
    dest: /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules
    content: |
      ## Unsuccessful file access (any other opens) This has to go last.
      -a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-access
      -a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-access
      -a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-access
      -a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-access
    force: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_access_failed
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Remove any permissions from other group
  file:
    path: /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules
    mode: o-rwx
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_access_failed
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,%23%23%20Unsuccessful%20file%20access%20%28any%20other%20opens%29%20This%20has%20to%20go%20last.%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20open%2Copenat%2Copen_by_handle_at%20-F%20exit%3D-EACCES%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-access%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20open%2Copenat%2Copen_by_handle_at%20-F%20exit%3D-EACCES%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-access%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20open%2Copenat%2Copen_by_handle_at%20-F%20exit%3D-EPERM%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-access%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20open%2Copenat%2Copen_by_handle_at%20-F%20exit%3D-EPERM%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-access
        mode: 0600
        path: /etc/audit/rules.d/30-ospp-v42-3-access-failed.rules
        overwrite: true

Rule   Configure auditing of successful file accesses   [ref]

Ensure that successful attempts to access a file are audited. The following rules configure audit as described above:
## Successful file access (any other opens) This has to go last.
## These next two are likely to result in a whole lot of events
-a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access
-a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access    
The Audit package provides pre-configured rules in /usr/share/audit/sample-rules. The above content can be found in /usr/share/audit/sample-rules/30-ospp-v42-3-access-success.rules. To deploy this configuration, it is recommended to copy it over to the /etc/audit/rules.d/ directory:
cp /usr/share/audit/sample-rules/30-ospp-v42-3-access-success.rules /etc/audit/rules.d/
Load new Audit rules into kernel by running:
augenrules --load
Note: This rule utilizes a file provided by Audit package to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs.
Rationale:
Auditing of successful attempts to access a file helps in investigation of activities performed on the system.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_audit_access_success
Identifiers and References

References:  0582, 0584, 05885, 0586, 0846, 0957, AU-2(a), FAU_GEN.1.1.c, SRG-OS-000458-GPOS-00203, SRG-OS-000474-GPOS-00219, SRG-OS-000475-GPOS-00220, SRG-OS-000463-GPOS-00207, SRG-OS-000465-GPOS-00209, SRG-OS-000461-GPOS-00205


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-3-access-success.rules
## Successful file access (any other opens) This has to go last.
## These next two are likely to result in a whole lot of events
-a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access
-a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access
EOF

chmod o-rwx /etc/audit/rules.d/30-ospp-v42-3-access-success.rules

augenrules --load

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Put contents into /etc/audit/rules.d/30-ospp-v42-3-access-success.rules according
    to policy
  copy:
    dest: /etc/audit/rules.d/30-ospp-v42-3-access-success.rules
    content: |
      ## Successful file access (any other opens) This has to go last.
      ## These next two are likely to result in a whole lot of events
      -a always,exit -F arch=b32 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access
      -a always,exit -F arch=b64 -S open,openat,openat2,open_by_handle_at -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-access
    force: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_access_success
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Remove any permissions from other group
  file:
    path: /etc/audit/rules.d/30-ospp-v42-3-access-success.rules
    mode: o-rwx
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_access_success
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,%23%23%20Successful%20file%20access%20%28any%20other%20opens%29%20This%20has%20to%20go%20last.%0A%23%23%20These%20next%20two%20are%20likely%20to%20result%20in%20a%20whole%20lot%20of%20events%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20open%2Copenat%2Copen_by_handle_at%20-F%20success%3D1%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dsuccessful-access%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20open%2Copenat%2Copen_by_handle_at%20-F%20success%3D1%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dsuccessful-access
        mode: 0600
        path: /etc/audit/rules.d/30-ospp-v42-3-access-success.rules
        overwrite: true

Rule   Configure basic parameters of Audit system   [ref]

Perform basic configuration of Audit system. Make sure that any previously defined rules are cleared, the auditing system is configured to handle sudden bursts of events, and in cases of failure, messages are configured to be directed to system log. The following rules configure audit as described above:
## First rule - delete all
-D

## Increase the buffers to survive stress events.
## Make this bigger for busy systems
-b 8192

## This determine how long to wait in burst of events
--backlog_wait_time 60000

## Set failure mode to syslog
-f 1
The Audit package provides pre-configured rules in /usr/share/audit/sample-rules. The above content can be found in /usr/share/audit/sample-rules/10-base-config.rules. To deploy this configuration, it is recommended to copy it over to the /etc/audit/rules.d/ directory:
cp /usr/share/audit/sample-rules/10-base-config.rules /etc/audit/rules.d/
Load new Audit rules into kernel by running:
augenrules --load
Warning:  It might happen that Audit buffer configured by this rule is not large enough for certain use cases. If that is the case, the buffer size can be overridden by placing
-b larger_buffer_size
into a file within /etc/audit/rules.d directory, replacing larger_file_size with the desired value. The file name should start with a number higher than 10 and lower than 99.
Rationale:
Without basic configurations, audit may not perform as expected. It may not be able to correctly handle events under stressful conditions, or log events in case of failure.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_audit_basic_configuration
Identifiers and References

References:  AU-2(a), FAU_GEN.1, SRG-OS-000365-GPOS-00152, SRG-OS-000475-GPOS-00220


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

cat << 'EOF' > /etc/audit/rules.d/10-base-config.rules
## First rule - delete all
-D

## Increase the buffers to survive stress events.
## Make this bigger for busy systems
-b 8192

## This determine how long to wait in burst of events
--backlog_wait_time 60000

## Set failure mode to syslog
-f 1

EOF

chmod o-rwx /etc/audit/rules.d/10-base-config.rules

augenrules --load

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Put contents into /etc/audit/rules.d/10-base-config.rules according to policy
  copy:
    dest: /etc/audit/rules.d/10-base-config.rules
    content: |+
      ## First rule - delete all
      -D

      ## Increase the buffers to survive stress events.
      ## Make this bigger for busy systems
      -b 8192

      ## This determine how long to wait in burst of events
      --backlog_wait_time 60000

      ## Set failure mode to syslog
      -f 1

    force: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_basic_configuration
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Remove any permissions from other group
  file:
    path: /etc/audit/rules.d/10-base-config.rules
    mode: o-rwx
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_basic_configuration
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,%23%23%20First%20rule%20-%20delete%20all%0A-D%0A%0A%23%23%20Increase%20the%20buffers%20to%20survive%20stress%20events.%0A%23%23%20Make%20this%20bigger%20for%20busy%20systems%0A-b%208192%0A%0A%23%23%20This%20determine%20how%20long%20to%20wait%20in%20burst%20of%20events%0A--backlog_wait_time%2060000%0A%0A%23%23%20Set%20failure%20mode%20to%20syslog%0A-f%201%0A
        mode: 0600
        path: /etc/audit/rules.d/10-base-config.rules
        overwrite: true

Rule   Configure auditing of unsuccessful file creations   [ref]

Ensure that unsuccessful attempts to create a file are audited. The following rules configure audit as described above:
## Unsuccessful file creation (open with O_CREAT)
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create    
The Audit package provides pre-configured rules in /usr/share/audit/sample-rules. The above content can be found in /usr/share/audit/sample-rules/30-ospp-v42-1-create-failed.rules. To deploy this configuration, it is recommended to copy it over to the /etc/audit/rules.d/ directory:
cp /usr/share/audit/sample-rules/30-ospp-v42-1-create-failed.rules /etc/audit/rules.d/
Load new Audit rules into kernel by running:
augenrules --load
Note: This rule utilizes a file provided by Audit package to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs.
Rationale:
Unsuccessful file creations might be a sign of a malicious action being performed on the system. Keeping log of such events helps in monitoring and investigation of such actions.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_audit_create_failed
Identifiers and References

References:  AU-2(a), FAU_GEN.1.1.c, SRG-OS-000458-GPOS-00203, SRG-OS-000474-GPOS-00219, SRG-OS-000475-GPOS-00220, SRG-OS-000463-GPOS-00207, SRG-OS-000465-GPOS-00209, SRG-OS-000461-GPOS-00205


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules
## Unsuccessful file creation (open with O_CREAT)
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
-a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
EOF

chmod o-rwx /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules

augenrules --load

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Put contents into /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules according
    to policy
  copy:
    dest: /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules
    content: |
      ## Unsuccessful file creation (open with O_CREAT)
      -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
      -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
      -a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
      -a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
      -a always,exit -F arch=b32 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
      -a always,exit -F arch=b64 -S creat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
      -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
      -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
      -a always,exit -F arch=b32 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
      -a always,exit -F arch=b64 -S open -F a1&0100 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
      -a always,exit -F arch=b32 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
      -a always,exit -F arch=b64 -S creat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-create
    force: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_create_failed
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Remove any permissions from other group
  file:
    path: /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules
    mode: o-rwx
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_create_failed
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,%23%23%20Unsuccessful%20file%20creation%20%28open%20with%20O_CREAT%29%0A%23%23%20/etc/audit/rules.d/30-ospp-v42-1-create-failed.rules%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20openat%2Copen_by_handle_at%20-F%20a2%26amp%3B0100%20-F%20exit%3D-EACCES%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-create%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20openat%2Copen_by_handle_at%20-F%20a2%26amp%3B0100%20-F%20exit%3D-EACCES%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-create%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20open%20-F%20a1%26amp%3B0100%20-F%20exit%3D-EACCES%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-create%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20open%20-F%20a1%26amp%3B0100%20-F%20exit%3D-EACCES%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-create%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20creat%20-F%20exit%3D-EACCES%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-create%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20creat%20-F%20exit%3D-EACCES%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-create%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20openat%2Copen_by_handle_at%20-F%20a2%26amp%3B0100%20-F%20exit%3D-EPERM%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-create%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20openat%2Copen_by_handle_at%20-F%20a2%26amp%3B0100%20-F%20exit%3D-EPERM%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-create%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20open%20-F%20a1%26amp%3B0100%20-F%20exit%3D-EPERM%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-create%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20open%20-F%20a1%26amp%3B0100%20-F%20exit%3D-EPERM%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-create%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20creat%20-F%20exit%3D-EPERM%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-create%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20creat%20-F%20exit%3D-EPERM%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-create%0A
        mode: 0600
        path: /etc/audit/rules.d/30-ospp-v42-1-create-failed.rules 
        overwrite: true

Rule   Configure auditing of successful file creations   [ref]

Ensure that successful attempts to create a file are audited. The following rules configure audit as described above:
## Successful file creation (open with O_CREAT)
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create
-a always,exit -F arch=b32 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create
-a always,exit -F arch=b64 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create
-a always,exit -F arch=b32 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create
-a always,exit -F arch=b64 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create    
The Audit package provides pre-configured rules in /usr/share/audit/sample-rules. The above content can be found in /usr/share/audit/sample-rules/30-ospp-v42-1-create-success.rules. To deploy this configuration, it is recommended to copy it over to the /etc/audit/rules.d/ directory:
cp /usr/share/audit/sample-rules/30-ospp-v42-1-create-success.rules /etc/audit/rules.d/
Load new Audit rules into kernel by running:
augenrules --load
Rationale:
Auditing of successful attempts to create a file helps in investigation of actions which happened on the system.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_audit_create_success
Identifiers and References

References:  AU-2(a), FAU_GEN.1.1.c, SRG-OS-000458-GPOS-00203, SRG-OS-000474-GPOS-00219, SRG-OS-000475-GPOS-00220, SRG-OS-000463-GPOS-00207, SRG-OS-000465-GPOS-00209, SRG-OS-000461-GPOS-00205


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-1-create-success.rules
## Successful file creation (open with O_CREAT)
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create
-a always,exit -F arch=b32 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create
-a always,exit -F arch=b64 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create
-a always,exit -F arch=b32 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create
-a always,exit -F arch=b64 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create
EOF

chmod o-rwx /etc/audit/rules.d/30-ospp-v42-1-create-success.rules

augenrules --load

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Put contents into /etc/audit/rules.d/30-ospp-v42-1-create-success.rules according
    to policy
  copy:
    dest: /etc/audit/rules.d/30-ospp-v42-1-create-success.rules
    content: |
      ## Successful file creation (open with O_CREAT)
      -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create
      -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create
      -a always,exit -F arch=b32 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create
      -a always,exit -F arch=b64 -S open -F a1&0100 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create
      -a always,exit -F arch=b32 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create
      -a always,exit -F arch=b64 -S creat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-create
    force: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_create_success
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Remove any permissions from other group
  file:
    path: /etc/audit/rules.d/30-ospp-v42-1-create-success.rules
    mode: o-rwx
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_create_success
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Configure auditing of unsuccessful file deletions   [ref]

Ensure that unsuccessful attempts to delete a file are audited. The following rules configure audit as described above:
## Unsuccessful file delete
-a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete
-a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete
-a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete
-a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete    
The Audit package provides pre-configured rules in /usr/share/audit/sample-rules. The above content can be found in /usr/share/audit/sample-rules/30-ospp-v42-4-delete-failed.rules. To deploy this configuration, it is recommended to copy it over to the /etc/audit/rules.d/ directory:
cp /usr/share/audit/sample-rules/30-ospp-v42-4-delete-failed.rules /etc/audit/rules.d/
Load new Audit rules into kernel by running:
augenrules --load
Note: This rule utilizes a file provided by Audit package to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs.
Rationale:
Unsuccessful attempts to delete a file might be signs of malicious activities. Auditing of such events help in monitoring and investigating of such activities.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_audit_delete_failed
Identifiers and References

References:  AU-2(a), FAU_GEN.1.1.c, SRG-OS-000458-GPOS-00203, SRG-OS-000474-GPOS-00219, SRG-OS-000475-GPOS-00220, SRG-OS-000463-GPOS-00207, SRG-OS-000465-GPOS-00209, SRG-OS-000461-GPOS-00205, SRG-OS-000468-GPOS-00212, SRG-OS-000467-GPOS-00211


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules
## Unsuccessful file delete
-a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete
-a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete
-a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete
-a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete
EOF

chmod o-rwx /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules

augenrules --load

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Put contents into /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules according
    to policy
  copy:
    dest: /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules
    content: |
      ## Unsuccessful file delete
      -a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete
      -a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete
      -a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete
      -a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-delete
    force: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_delete_failed
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Remove any permissions from other group
  file:
    path: /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules
    mode: o-rwx
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_delete_failed
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,%23%23%20Unsuccessful%20file%20delete%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20unlink%2Cunlinkat%2Crename%2Crenameat%20-F%20exit%3D-EACCES%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-delete%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20unlink%2Cunlinkat%2Crename%2Crenameat%20-F%20exit%3D-EACCES%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-delete%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20unlink%2Cunlinkat%2Crename%2Crenameat%20-F%20exit%3D-EPERM%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-delete%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20unlink%2Cunlinkat%2Crename%2Crenameat%20-F%20exit%3D-EPERM%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-delete
        mode: 0600
        path: /etc/audit/rules.d/30-ospp-v42-4-delete-failed.rules
        overwrite: true

Rule   Configure auditing of successful file deletions   [ref]

Ensure that successful attempts to delete a file are audited. The following rules configure audit as described above:
## Successful file delete
-a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete
-a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete    
The Audit package provides pre-configured rules in /usr/share/audit/sample-rules. The above content can be found in /usr/share/audit/sample-rules/30-ospp-v42-4-delete-success.rules. To deploy this configuration, it is recommended to copy it over to the /etc/audit/rules.d/ directory:
cp /usr/share/audit/sample-rules/30-ospp-v42-4-delete-success.rules /etc/audit/rules.d/
Load new Audit rules into kernel by running:
augenrules --load
Note: This rule utilizes a file provided by Audit package to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs.
Rationale:
Auditing of successful attempts to delete a file may help in monitoring and investigation of activities performed on the system.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_audit_delete_success
Identifiers and References

References:  AU-2(a), FAU_GEN.1.1.c, SRG-OS-000458-GPOS-00203, SRG-OS-000474-GPOS-00219, SRG-OS-000475-GPOS-00220, SRG-OS-000463-GPOS-00207, SRG-OS-000465-GPOS-00209, SRG-OS-000461-GPOS-00205, SRG-OS-000468-GPOS-00212, SRG-OS-000467-GPOS-00211


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules
## Successful file delete
-a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete
-a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete
EOF

chmod o-rwx /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules

augenrules --load

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Put contents into /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules according
    to policy
  copy:
    dest: /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules
    content: |
      ## Successful file delete
      -a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete
      -a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-delete
    force: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_delete_success
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Remove any permissions from other group
  file:
    path: /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules
    mode: o-rwx
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_delete_success
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

---

apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,{{ %23%23%20Successful%20file%20delete%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20unlink%2Cunlinkat%2Crename%2Crenameat%20-F%20success%3D1%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dsuccessful-delete%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20unlink%2Cunlinkat%2Crename%2Crenameat%20-F%20success%3D1%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dsuccessful-delete }}
        mode: 0600
        path: /etc/audit/rules.d/30-ospp-v42-4-delete-success.rules
        overwrite: true

Rule   Configure auditing of unsuccessful file modifications   [ref]

Ensure that unsuccessful attempts to modify a file are audited. The following rules configure audit as described above:
## Unsuccessful file modifications (open for write or truncate)
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b32 -S open -F a1&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b64 -S open -F a1&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b32 -S truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b64 -S truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b32 -S open -F a1&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b64 -S open -F a1&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b32 -S truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b64 -S truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification    
The Audit package provides pre-configured rules in /usr/share/audit/sample-rules. The above content can be found in /usr/share/audit/sample-rules/30-ospp-v42-2-modify-failed.rules. To deploy this configuration, it is recommended to copy it over to the /etc/audit/rules.d/ directory:
cp /usr/share/audit/sample-rules/30-ospp-v42-2-modify-failed.rules /etc/audit/rules.d/
Load new Audit rules into kernel by running:
augenrules --load
Note: This rule utilizes a file provided by Audit package to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs.
Rationale:
Unsuccessful file modifications might be a sign of a malicious action being performed on the system. Auditing of such events helps in detection and investigation of such actions.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_audit_modify_failed
Identifiers and References

References:  AU-2(a), FAU_GEN.1.1.c, SRG-OS-000458-GPOS-00203, SRG-OS-000474-GPOS-00219, SRG-OS-000475-GPOS-00220, SRG-OS-000463-GPOS-00207, SRG-OS-000465-GPOS-00209, SRG-OS-000461-GPOS-00205


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules
## Unsuccessful file modifications (open for write or truncate)
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b32 -S open -F a1&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b64 -S open -F a1&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b32 -S truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b64 -S truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b32 -S open -F a1&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b64 -S open -F a1&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b32 -S truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
-a always,exit -F arch=b64 -S truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
EOF

chmod o-rwx /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules

augenrules --load

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Put contents into /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules according
    to policy
  copy:
    dest: /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules
    content: |
      ## Unsuccessful file modifications (open for write or truncate)
      -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
      -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
      -a always,exit -F arch=b32 -S open -F a1&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
      -a always,exit -F arch=b64 -S open -F a1&01003 -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
      -a always,exit -F arch=b32 -S truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
      -a always,exit -F arch=b64 -S truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
      -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
      -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
      -a always,exit -F arch=b32 -S open -F a1&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
      -a always,exit -F arch=b64 -S open -F a1&01003 -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
      -a always,exit -F arch=b32 -S truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
      -a always,exit -F arch=b64 -S truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-modification
    force: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_modify_failed
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Remove any permissions from other group
  file:
    path: /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules
    mode: o-rwx
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_modify_failed
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,%23%23%20Unsuccessful%20file%20modifications%20%28open%20for%20write%20or%20truncate%29%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20openat%2Copen_by_handle_at%20-F%20a2%2601003%20-F%20exit%3D-EACCES%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-modification%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20openat%2Copen_by_handle_at%20-F%20a2%2601003%20-F%20exit%3D-EACCES%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-modification%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20open%20-F%20a1%2601003%20-F%20exit%3D-EACCES%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-modification%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20open%20-F%20a1%2601003%20-F%20exit%3D-EACCES%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-modification%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20truncate%2Cftruncate%20-F%20exit%3D-EACCES%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-modification%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20truncate%2Cftruncate%20-F%20exit%3D-EACCES%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-modification%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20openat%2Copen_by_handle_at%20-F%20a2%2601003%20-F%20exit%3D-EPERM%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-modification%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20openat%2Copen_by_handle_at%20-F%20a2%2601003%20-F%20exit%3D-EPERM%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-modification%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20open%20-F%20a1%2601003%20-F%20exit%3D-EPERM%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-modification%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20open%20-F%20a1%2601003%20-F%20exit%3D-EPERM%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-modification%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20truncate%2Cftruncate%20-F%20exit%3D-EPERM%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-modification%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20truncate%2Cftruncate%20-F%20exit%3D-EPERM%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dunsuccessful-modification%0A
        mode: 0600
        path: /etc/audit/rules.d/30-ospp-v42-2-modify-failed.rules 
        overwrite: true

Rule   Configure auditing of successful file modifications   [ref]

Ensure that successful attempts to modify a file are audited. The following rules configure audit as described above:
## Successful file modifications (open for write or truncate)
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification
-a always,exit -F arch=b32 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification
-a always,exit -F arch=b64 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification
-a always,exit -F arch=b32 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification
-a always,exit -F arch=b64 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification    
The Audit package provides pre-configured rules in /usr/share/audit/sample-rules. The above content can be found in /usr/share/audit/sample-rules/30-ospp-v42-2-modify-success.rules. To deploy this configuration, it is recommended to copy it over to the /etc/audit/rules.d/ directory:
cp /usr/share/audit/sample-rules/30-ospp-v42-2-modify-success.rules /etc/audit/rules.d/
Load new Audit rules into kernel by running:
augenrules --load
Note: This rule utilizes a file provided by Audit package to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs.
Rationale:
Auditing of successful attempts to modify a file helps in investigation of actions which happened on the system.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_audit_modify_success
Identifiers and References

References:  AU-2(a), FAU_GEN.1.1.c, SRG-OS-000458-GPOS-00203, SRG-OS-000474-GPOS-00219, SRG-OS-000475-GPOS-00220, SRG-OS-000463-GPOS-00207, SRG-OS-000465-GPOS-00209, SRG-OS-000461-GPOS-00205


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules
## Successful file modifications (open for write or truncate)
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification
-a always,exit -F arch=b32 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification
-a always,exit -F arch=b64 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification
-a always,exit -F arch=b32 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification
-a always,exit -F arch=b64 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification
EOF

chmod o-rwx /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules

augenrules --load

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Put contents into /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules according
    to policy
  copy:
    dest: /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules
    content: |
      ## Successful file modifications (open for write or truncate)
      -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification
      -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification
      -a always,exit -F arch=b32 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification
      -a always,exit -F arch=b64 -S open -F a1&01003 -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification
      -a always,exit -F arch=b32 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification
      -a always,exit -F arch=b64 -S truncate,ftruncate -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-modification
    force: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_modify_success
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Remove any permissions from other group
  file:
    path: /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules
    mode: o-rwx
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_modify_success
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,%23%23%20Successful%20file%20modifications%20%28open%20for%20write%20or%20truncate%29%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20openat%2Copen_by_handle_at%20-F%20a2%26amp%3B01003%20-F%20success%3D1%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dsuccessful-modification%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20openat%2Copen_by_handle_at%20-F%20a2%26amp%3B01003%20-F%20success%3D1%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dsuccessful-modification%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20open%20-F%20a1%26amp%3B01003%20-F%20success%3D1%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dsuccessful-modification%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20open%20-F%20a1%26amp%3B01003%20-F%20success%3D1%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dsuccessful-modification%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20truncate%2Cftruncate%20-F%20success%3D1%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dsuccessful-modification%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20truncate%2Cftruncate%20-F%20success%3D1%20-F%20auid%26gt%3B%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dsuccessful-modification%0A
        mode: 0600
        path: /etc/audit/rules.d/30-ospp-v42-2-modify-success.rules
        overwrite: true

Rule   Configure auditing of loading and unloading of kernel modules   [ref]

Ensure that loading and unloading of kernel modules is audited. The following rules configure audit as described above:
## These rules watch for kernel module insertion. By monitoring
## the syscall, we do not need any watches on programs.
-a always,exit -F arch=b32 -S init_module,finit_module -F key=module-load
-a always,exit -F arch=b64 -S init_module,finit_module -F key=module-load
-a always,exit -F arch=b32 -S delete_module -F key=module-unload
-a always,exit -F arch=b64 -S delete_module -F key=module-unload    
The Audit package provides pre-configured rules in /usr/share/audit/sample-rules. The above content can be found in /usr/share/audit/sample-rules/43-module-load.rules. To deploy this configuration, it is recommended to copy it over to the /etc/audit/rules.d/ directory:
cp /usr/share/audit/sample-rules/43-module-load.rules /etc/audit/rules.d/
Load new Audit rules into kernel by running:
augenrules --load
Rationale:
Loading of a malicious kernel module introduces a risk to the system, as the module has access to sensitive data and perform actions at the operating system kernel level. Having such events audited helps in monitoring and investigating of malicious activities.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_audit_module_load
Identifiers and References

References:  AU-2(a), FAU_GEN.1.1.c, SRG-OS-000471-GPOS-00216, SRG-OS-000477-GPOS-00222, SRG-OS-000475-GPOS-00220


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

cat << 'EOF' > /etc/audit/rules.d/43-module-load.rules
## These rules watch for kernel module insertion. By monitoring
## the syscall, we do not need any watches on programs.
-a always,exit -F arch=b32 -S init_module,finit_module -F key=module-load
-a always,exit -F arch=b64 -S init_module,finit_module -F key=module-load
-a always,exit -F arch=b32 -S delete_module -F key=module-unload
-a always,exit -F arch=b64 -S delete_module -F key=module-unload
EOF

chmod o-rwx /etc/audit/rules.d/43-module-load.rules

augenrules --load

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Put contents into /etc/audit/rules.d/43-module-load.rules according to policy
  copy:
    dest: /etc/audit/rules.d/43-module-load.rules
    content: |
      ## These rules watch for kernel module insertion. By monitoring
      ## the syscall, we do not need any watches on programs.
      -a always,exit -F arch=b32 -S init_module,finit_module -F key=module-load
      -a always,exit -F arch=b64 -S init_module,finit_module -F key=module-load
      -a always,exit -F arch=b32 -S delete_module -F key=module-unload
      -a always,exit -F arch=b64 -S delete_module -F key=module-unload
    force: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_module_load
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Remove any permissions from other group
  file:
    path: /etc/audit/rules.d/43-module-load.rules
    mode: o-rwx
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_module_load
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,%23%23%20These%20rules%20watch%20for%20kernel%20module%20insertion.%20By%20monitoring%0A%23%23%20the%20syscall%2C%20we%20do%20not%20need%20any%20watches%20on%20programs.%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20init_module%2Cfinit_module%20-F%20key%3Dmodule-load%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20init_module%2Cfinit_module%20-F%20key%3Dmodule-load%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20delete_module%20-F%20key%3Dmodule-unload%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20delete_module%20-F%20key%3Dmodule-unload%0A
        mode: 0600
        path: /etc/audit/rules.d/43-module-load.rules
        overwrite: true

Rule   Perform general configuration of Audit for OSPP   [ref]

Configure some basic Audit parameters specific for OSPP profile. In particular, configure Audit to watch for direct modification of files storing system user and group information, and usage of applications with special rights which can change system configuration. Further audited events include access to audit log it self, attempts to Alter Process and Session Initiation Information, and attempts to modify MAC controls. The following rules configure audit as described above:
## The purpose of these rules is to meet the requirements for Operating
## System Protection Profile (OSPP)v4.2. These rules depends on having
## the following rule files copied to /etc/audit/rules.d:
##
## 10-base-config.rules, 11-loginuid.rules,
## 30-ospp-v42-1-create-failed.rules, 30-ospp-v42-1-create-success.rules,
## 30-ospp-v42-2-modify-failed.rules, 30-ospp-v42-2-modify-success.rules,
## 30-ospp-v42-3-access-failed.rules, 30-ospp-v42-3-access-success.rules,
## 30-ospp-v42-4-delete-failed.rules, 30-ospp-v42-4-delete-success.rules,
## 30-ospp-v42-5-perm-change-failed.rules,
## 30-ospp-v42-5-perm-change-success.rules,
## 30-ospp-v42-6-owner-change-failed.rules,
## 30-ospp-v42-6-owner-change-success.rules
##
## original copies may be found in /usr/share/audit/sample-rules/


## User add delete modify. This is covered by pam. However, someone could
## open a file and directly create or modify a user, so we'll watch passwd and
## shadow for writes
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b32 -S open -F a1&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b64 -S open -F a1&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b32 -S open -F a1&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b64 -S open -F a1&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify

## User enable and disable. This is entirely handled by pam.

## Group add delete modify. This is covered by pam. However, someone could
## open a file and directly create or modify a user, so we'll watch group and
## gshadow for writes
-a always,exit -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify
-a always,exit -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify


## Use of special rights for config changes. This would be use of setuid
## programs that relate to user accts. This is not all setuid apps because
## requirements are only for ones that affect system configuration.
-a always,exit -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes

## Privilege escalation via su or sudo. This is entirely handled by pam.

## Watch for configuration changes to privilege escalation.
-a always,exit -F path=/etc/sudoers -F perm=wa -F key=special-config-changes
-a always,exit -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes

## Audit log access
-a always,exit -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail
## Attempts to Alter Process and Session Initiation Information
-a always,exit -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session
-a always,exit -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session
-a always,exit -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session

## Attempts to modify MAC controls
-a always,exit -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy

## Software updates. This is entirely handled by rpm.

## System start and shutdown. This is entirely handled by systemd

## Kernel Module loading. This is handled in 43-module-load.rules

## Application invocation. The requirements list an optional requirement
## FPT_SRP_EXT.1 Software Restriction Policies. This event is intended to
## state results from that policy. This would be handled entirely by
## that daemon.
The Audit package provides pre-configured rules in /usr/share/audit/sample-rules. The above content can be found in /usr/share/audit/sample-rules/30-ospp-v42.rules. To deploy this configuration, it is recommended to copy it over to the /etc/audit/rules.d/ directory:
cp /usr/share/audit/sample-rules/30-ospp-v42.rules /etc/audit/rules.d/
Load new Audit rules into kernel by running:
augenrules --load
Note: This rule utilizes a file provided by Audit package to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs.
Rationale:
Auditing of events listed in the description provides data for monitoring and investigation of potentially malicious events e.g. tampering with Audit logs, malicious access to files storing information about system users and groups etc.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_audit_ospp_general
Identifiers and References

References:  AU-2(a), FAU_GEN.1.1.c, SRG-OS-000004-GPOS-00004, SRG-OS-000241-GPOS-00091, SRG-OS-000476-GPOS-00221, SRG-OS-000327-GPOS-00127, SRG-OS-000475-GPOS-00220, SRG-OS-000239-GPOS-00089, SRG-OS-000274-GPOS-00104, SRG-OS-000275-GPOS-00105, SRG-OS-000303-GPOS-00120, SRG-OS-000304-GPOS-00121


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42.rules
## The purpose of these rules is to meet the requirements for Operating
## System Protection Profile (OSPP)v4.2. These rules depends on having
## the following rule files copied to /etc/audit/rules.d:
##
## 10-base-config.rules, 11-loginuid.rules,
## 30-ospp-v42-1-create-failed.rules, 30-ospp-v42-1-create-success.rules,
## 30-ospp-v42-2-modify-failed.rules, 30-ospp-v42-2-modify-success.rules,
## 30-ospp-v42-3-access-failed.rules, 30-ospp-v42-3-access-success.rules,
## 30-ospp-v42-4-delete-failed.rules, 30-ospp-v42-4-delete-success.rules,
## 30-ospp-v42-5-perm-change-failed.rules,
## 30-ospp-v42-5-perm-change-success.rules,
## 30-ospp-v42-6-owner-change-failed.rules,
## 30-ospp-v42-6-owner-change-success.rules
##
## original copies may be found in /usr/share/audit/sample-rules/


## User add delete modify. This is covered by pam. However, someone could
## open a file and directly create or modify a user, so we'll watch passwd and
## shadow for writes
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b32 -S open -F a1&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b64 -S open -F a1&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b32 -S open -F a1&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F arch=b64 -S open -F a1&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify

## User enable and disable. This is entirely handled by pam.

## Group add delete modify. This is covered by pam. However, someone could
## open a file and directly create or modify a user, so we'll watch group and
## gshadow for writes
-a always,exit -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify
-a always,exit -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify
-a always,exit -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify


## Use of special rights for config changes. This would be use of setuid
## programs that relate to user accts. This is not all setuid apps because
## requirements are only for ones that affect system configuration.
-a always,exit -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
-a always,exit -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes

## Privilege escalation via su or sudo. This is entirely handled by pam.

## Watch for configuration changes to privilege escalation.
-a always,exit -F path=/etc/sudoers -F perm=wa -F key=special-config-changes
-a always,exit -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes

## Audit log access
-a always,exit -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail
## Attempts to Alter Process and Session Initiation Information
-a always,exit -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session
-a always,exit -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session
-a always,exit -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session

## Attempts to modify MAC controls
-a always,exit -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy

## Software updates. This is entirely handled by rpm.

## System start and shutdown. This is entirely handled by systemd

## Kernel Module loading. This is handled in 43-module-load.rules

## Application invocation. The requirements list an optional requirement
## FPT_SRP_EXT.1 Software Restriction Policies. This event is intended to
## state results from that policy. This would be handled entirely by
## that daemon.

EOF

chmod o-rwx /etc/audit/rules.d/30-ospp-v42.rules

augenrules --load

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Put contents into /etc/audit/rules.d/30-ospp-v42.rules according to policy
  copy:
    dest: /etc/audit/rules.d/30-ospp-v42.rules
    content: |+
      ## The purpose of these rules is to meet the requirements for Operating
      ## System Protection Profile (OSPP)v4.2. These rules depends on having
      ## the following rule files copied to /etc/audit/rules.d:
      ##
      ## 10-base-config.rules, 11-loginuid.rules,
      ## 30-ospp-v42-1-create-failed.rules, 30-ospp-v42-1-create-success.rules,
      ## 30-ospp-v42-2-modify-failed.rules, 30-ospp-v42-2-modify-success.rules,
      ## 30-ospp-v42-3-access-failed.rules, 30-ospp-v42-3-access-success.rules,
      ## 30-ospp-v42-4-delete-failed.rules, 30-ospp-v42-4-delete-success.rules,
      ## 30-ospp-v42-5-perm-change-failed.rules,
      ## 30-ospp-v42-5-perm-change-success.rules,
      ## 30-ospp-v42-6-owner-change-failed.rules,
      ## 30-ospp-v42-6-owner-change-success.rules
      ##
      ## original copies may be found in /usr/share/audit/sample-rules/


      ## User add delete modify. This is covered by pam. However, someone could
      ## open a file and directly create or modify a user, so we'll watch passwd and
      ## shadow for writes
      -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify
      -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify
      -a always,exit -F arch=b32 -S open -F a1&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify
      -a always,exit -F arch=b64 -S open -F a1&03 -F path=/etc/passwd -F auid>=1000 -F auid!=unset -F key=user-modify
      -a always,exit -F arch=b32 -S openat,open_by_handle_at -F a2&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify
      -a always,exit -F arch=b64 -S openat,open_by_handle_at -F a2&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify
      -a always,exit -F arch=b32 -S open -F a1&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify
      -a always,exit -F arch=b64 -S open -F a1&03 -F path=/etc/shadow -F auid>=1000 -F auid!=unset -F key=user-modify

      ## User enable and disable. This is entirely handled by pam.

      ## Group add delete modify. This is covered by pam. However, someone could
      ## open a file and directly create or modify a user, so we'll watch group and
      ## gshadow for writes
      -a always,exit -F path=/etc/passwd -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify
      -a always,exit -F path=/etc/shadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=user-modify
      -a always,exit -F path=/etc/group -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify
      -a always,exit -F path=/etc/gshadow -F perm=wa -F auid>=1000 -F auid!=unset -F key=group-modify


      ## Use of special rights for config changes. This would be use of setuid
      ## programs that relate to user accts. This is not all setuid apps because
      ## requirements are only for ones that affect system configuration.
      -a always,exit -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
      -a always,exit -F path=/usr/sbin/usernetctl -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
      -a always,exit -F path=/usr/sbin/userhelper -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
      -a always,exit -F path=/usr/sbin/seunshare -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
      -a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
      -a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
      -a always,exit -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
      -a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
      -a always,exit -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
      -a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
      -a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
      -a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes
      -a always,exit -F path=/usr/bin/at -F perm=x -F auid>=1000 -F auid!=unset -F key=special-config-changes

      ## Privilege escalation via su or sudo. This is entirely handled by pam.

      ## Watch for configuration changes to privilege escalation.
      -a always,exit -F path=/etc/sudoers -F perm=wa -F key=special-config-changes
      -a always,exit -F dir=/etc/sudoers.d/ -F perm=wa -F key=special-config-changes

      ## Audit log access
      -a always,exit -F dir=/var/log/audit/ -F perm=r -F auid>=1000 -F auid!=unset -F key=access-audit-trail
      ## Attempts to Alter Process and Session Initiation Information
      -a always,exit -F path=/var/run/utmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session
      -a always,exit -F path=/var/log/btmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session
      -a always,exit -F path=/var/log/wtmp -F perm=wa -F auid>=1000 -F auid!=unset -F key=session

      ## Attempts to modify MAC controls
      -a always,exit -F dir=/etc/selinux/ -F perm=wa -F auid>=1000 -F auid!=unset -F key=MAC-policy

      ## Software updates. This is entirely handled by rpm.

      ## System start and shutdown. This is entirely handled by systemd

      ## Kernel Module loading. This is handled in 43-module-load.rules

      ## Application invocation. The requirements list an optional requirement
      ## FPT_SRP_EXT.1 Software Restriction Policies. This event is intended to
      ## state results from that policy. This would be handled entirely by
      ## that daemon.

    force: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_ospp_general
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Remove any permissions from other group
  file:
    path: /etc/audit/rules.d/30-ospp-v42.rules
    mode: o-rwx
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_ospp_general
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,%23%23%20The%20purpose%20of%20these%20rules%20is%20to%20meet%20the%20requirements%20for%20Operating%0A%23%23%20System%20Protection%20Profile%20%28OSPP%29v4.2.%20These%20rules%20depends%20on%20having%0A%23%23%20the%20following%20rule%20files%20copied%20to%20/etc/audit/rules.d%3A%0A%23%23%0A%23%23%2010-base-config.rules%2C%2011-loginuid.rules%2C%0A%23%23%2030-ospp-v42-1-create-failed.rules%2C%2030-ospp-v42-1-create-success.rules%2C%0A%23%23%2030-ospp-v42-2-modify-failed.rules%2C%2030-ospp-v42-2-modify-success.rules%2C%0A%23%23%2030-ospp-v42-3-access-failed.rules%2C%2030-ospp-v42-3-access-success.rules%2C%0A%23%23%2030-ospp-v42-4-delete-failed.rules%2C%2030-ospp-v42-4-delete-success.rules%2C%0A%23%23%2030-ospp-v42-5-perm-change-failed.rules%2C%0A%23%23%2030-ospp-v42-5-perm-change-success.rules%2C%0A%23%23%2030-ospp-v42-6-owner-change-failed.rules%2C%0A%23%23%2030-ospp-v42-6-owner-change-success.rules%0A%23%23%0A%23%23%20original%20copies%20may%20be%20found%20in%20/usr/share/audit/sample-rules/%0A%0A%0A%23%23%20User%20add%20delete%20modify.%20This%20is%20covered%20by%20pam.%20However%2C%20someone%20could%0A%23%23%20open%20a%20file%20and%20directly%20create%20or%20modify%20a%20user%2C%20so%20we%27ll%20watch%20passwd%20and%0A%23%23%20shadow%20for%20writes%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20openat%2Copen_by_handle_at%20-F%20a2%2603%20-F%20path%3D/etc/passwd%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Duser-modify%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20openat%2Copen_by_handle_at%20-F%20a2%2603%20-F%20path%3D/etc/passwd%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Duser-modify%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20open%20-F%20a1%2603%20-F%20path%3D/etc/passwd%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Duser-modify%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20open%20-F%20a1%2603%20-F%20path%3D/etc/passwd%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Duser-modify%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20openat%2Copen_by_handle_at%20-F%20a2%2603%20-F%20path%3D/etc/shadow%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Duser-modify%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20openat%2Copen_by_handle_at%20-F%20a2%2603%20-F%20path%3D/etc/shadow%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Duser-modify%0A-a%20always%2Cexit%20-F%20arch%3Db32%20-S%20open%20-F%20a1%2603%20-F%20path%3D/etc/shadow%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Duser-modify%0A-a%20always%2Cexit%20-F%20arch%3Db64%20-S%20open%20-F%20a1%2603%20-F%20path%3D/etc/shadow%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Duser-modify%0A%0A%23%23%20User%20enable%20and%20disable.%20This%20is%20entirely%20handled%20by%20pam.%0A%0A%23%23%20Group%20add%20delete%20modify.%20This%20is%20covered%20by%20pam.%20However%2C%20someone%20could%0A%23%23%20open%20a%20file%20and%20directly%20create%20or%20modify%20a%20user%2C%20so%20we%27ll%20watch%20group%20and%0A%23%23%20gshadow%20for%20writes%0A-a%20always%2Cexit%20-F%20path%3D/etc/passwd%20-F%20perm%3Dwa%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Duser-modify%0A-a%20always%2Cexit%20-F%20path%3D/etc/shadow%20-F%20perm%3Dwa%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Duser-modify%0A-a%20always%2Cexit%20-F%20path%3D/etc/group%20-F%20perm%3Dwa%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dgroup-modify%0A-a%20always%2Cexit%20-F%20path%3D/etc/gshadow%20-F%20perm%3Dwa%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dgroup-modify%0A%0A%0A%23%23%20Use%20of%20special%20rights%20for%20config%20changes.%20This%20would%20be%20use%20of%20setuid%0A%23%23%20programs%20that%20relate%20to%20user%20accts.%20This%20is%20not%20all%20setuid%20apps%20because%0A%23%23%20requirements%20are%20only%20for%20ones%20that%20affect%20system%20configuration.%0A-a%20always%2Cexit%20-F%20path%3D/usr/sbin/unix_chkpwd%20-F%20perm%3Dx%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dspecial-config-changes%0A-a%20always%2Cexit%20-F%20path%3D/usr/sbin/usernetctl%20-F%20perm%3Dx%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dspecial-config-changes%0A-a%20always%2Cexit%20-F%20path%3D/usr/sbin/userhelper%20-F%20perm%3Dx%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dspecial-config-changes%0A-a%20always%2Cexit%20-F%20path%3D/usr/sbin/seunshare%20-F%20perm%3Dx%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dspecial-config-changes%0A-a%20always%2Cexit%20-F%20path%3D/usr/bin/mount%20-F%20perm%3Dx%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dspecial-config-changes%0A-a%20always%2Cexit%20-F%20path%3D/usr/bin/newgrp%20-F%20perm%3Dx%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dspecial-config-changes%0A-a%20always%2Cexit%20-F%20path%3D/usr/bin/newuidmap%20-F%20perm%3Dx%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dspecial-config-changes%0A-a%20always%2Cexit%20-F%20path%3D/usr/bin/gpasswd%20-F%20perm%3Dx%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dspecial-config-changes%0A-a%20always%2Cexit%20-F%20path%3D/usr/bin/newgidmap%20-F%20perm%3Dx%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dspecial-config-changes%0A-a%20always%2Cexit%20-F%20path%3D/usr/bin/umount%20-F%20perm%3Dx%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dspecial-config-changes%0A-a%20always%2Cexit%20-F%20path%3D/usr/bin/passwd%20-F%20perm%3Dx%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dspecial-config-changes%0A-a%20always%2Cexit%20-F%20path%3D/usr/bin/crontab%20-F%20perm%3Dx%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dspecial-config-changes%0A-a%20always%2Cexit%20-F%20path%3D/usr/bin/at%20-F%20perm%3Dx%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dspecial-config-changes%0A%0A%23%23%20Privilege%20escalation%20via%20su%20or%20sudo.%20This%20is%20entirely%20handled%20by%20pam.%0A%0A%23%23%20Audit%20log%20access%0A-a%20always%2Cexit%20-F%20dir%3D/var/log/audit/%20-F%20perm%3Dr%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Daccess-audit-trail%0A%23%23%20Attempts%20to%20Alter%20Process%20and%20Session%20Initiation%20Information%0A-a%20always%2Cexit%20-F%20path%3D/var/run/utmp%20-F%20perm%3Dwa%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dsession%0A-a%20always%2Cexit%20-F%20path%3D/var/log/btmp%20-F%20perm%3Dwa%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dsession%0A-a%20always%2Cexit%20-F%20path%3D/var/log/wtmp%20-F%20perm%3Dwa%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3Dsession%0A%0A%23%23%20Attempts%20to%20modify%20MAC%20controls%0A-a%20always%2Cexit%20-F%20dir%3D/etc/selinux/%20-F%20perm%3Dwa%20-F%20auid%3E%3D1000%20-F%20auid%21%3Dunset%20-F%20key%3DMAC-policy%0A%0A%23%23%20Software%20updates.%20This%20is%20entirely%20handled%20by%20rpm.%0A%0A%23%23%20System%20start%20and%20shutdown.%20This%20is%20entirely%20handled%20by%20systemd%0A%0A%23%23%20Kernel%20Module%20loading.%20This%20is%20handled%20in%2043-module-load.rules%0A%0A%23%23%20Application%20invocation.%20The%20requirements%20list%20an%20optional%20requirement%0A%23%23%20FPT_SRP_EXT.1%20Software%20Restriction%20Policies.%20This%20event%20is%20intended%20to%0A%23%23%20state%20results%20from%20that%20policy.%20This%20would%20be%20handled%20entirely%20by%0A%23%23%20that%20daemon.%0A
        mode: 0600
        path: /etc/audit/rules.d/30-ospp-v42.rules
        overwrite: true

Rule   Configure auditing of unsuccessful ownership changes   [ref]

Ensure that unsuccessful attempts to change an ownership of files or directories are audited. The following rules configure audit as described above:
## Unsuccessful ownership change
-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change
-a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change
-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change
-a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change    
The Audit package provides pre-configured rules in /usr/share/audit/sample-rules. The above content can be found in /usr/share/audit/sample-rules/30-ospp-v42-6-owner-change-failed.rules. To deploy this configuration, it is recommended to copy it over to the /etc/audit/rules.d/ directory:
cp /usr/share/audit/sample-rules/30-ospp-v42-6-owner-change-failed.rules /etc/audit/rules.d/
Load new Audit rules into kernel by running:
augenrules --load
Note: This rule utilizes a file provided by Audit package to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs.
Rationale:
Unsuccessful attempts to change an ownership of files or directories might be signs of a malicious activity. Having such events audited helps in monitoring and investigation of such activities.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_audit_owner_change_failed
Identifiers and References

References:  AU-2(a), FAU_GEN.1.1.c, SRG-OS-000462-GPOS-00206, SRG-OS-000463-GPOS-00207, SRG-OS-000465-GPOS-00209, SRG-OS-000474-GPOS-00219, SRG-OS-000475-GPOS-00220, SRG-OS-000466-GPOS-00210, SRG-OS-000064-GPOS-00033


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules
## Unsuccessful ownership change
-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change
-a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change
-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change
-a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change
EOF

chmod o-rwx /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules

augenrules --load

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Put contents into /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules
    according to policy
  copy:
    dest: /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules
    content: |
      ## Unsuccessful ownership change
      -a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change
      -a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change
      -a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change
      -a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-owner-change
    force: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_owner_change_failed
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Remove any permissions from other group
  file:
    path: /etc/audit/rules.d/30-ospp-v42-6-owner-change-failed.rules
    mode: o-rwx
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_owner_change_failed
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Configure auditing of successful ownership changes   [ref]

Ensure that successful attempts to change an ownership of files or directories are audited. The following rules configure audit as described above:
## Successful ownership change
-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change
-a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change    
The Audit package provides pre-configured rules in /usr/share/audit/sample-rules. The above content can be found in /usr/share/audit/sample-rules/30-ospp-v42-6-owner-change-success.rules. To deploy this configuration, it is recommended to copy it over to the /etc/audit/rules.d/ directory:
cp /usr/share/audit/sample-rules/30-ospp-v42-6-owner-change-success.rules /etc/audit/rules.d/
The file has the following SHA-256 checksum:
7eb41a6aaf6737c2571b6424fae7fa53af4b41a9115b6c5732a5778ccd9900ad
Load new Audit rules into kernel by running:
augenrules --load
Note: This rule utilizes a file provided by Audit package to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs.
Rationale:
Auditing of successful ownership changes of files or directories helps in monitoring or investingating of activities performed on the system.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_audit_owner_change_success
Identifiers and References

References:  AU-2(a), FAU_GEN.1.1.c, SRG-OS-000462-GPOS-00206, SRG-OS-000463-GPOS-00207, SRG-OS-000465-GPOS-00209, SRG-OS-000474-GPOS-00219, SRG-OS-000475-GPOS-00220, SRG-OS-000466-GPOS-00210, SRG-OS-000064-GPOS-00033


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules
## Successful ownership change
-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change
-a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change
EOF

chmod o-rwx /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules

augenrules --load

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Put contents into /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules
    according to policy
  copy:
    dest: /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules
    content: |
      ## Successful ownership change
      -a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change
      -a always,exit -F arch=b64 -S lchown,fchown,chown,fchownat -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-owner-change
    force: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_owner_change_success
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Remove any permissions from other group
  file:
    path: /etc/audit/rules.d/30-ospp-v42-6-owner-change-success.rules
    mode: o-rwx
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_owner_change_success
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Configure auditing of unsuccessful permission changes   [ref]

Ensure that unsuccessful attempts to change file or directory permissions are audited. The following rules configure audit as described above:
## Unsuccessful permission change
-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change
-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change    
The Audit package provides pre-configured rules in /usr/share/audit/sample-rules. The above content can be found in /usr/share/audit/sample-rules/30-ospp-v42-5-perm-change-failed.rules. To deploy this configuration, it is recommended to copy it over to the /etc/audit/rules.d/ directory:
cp /usr/share/audit/sample-rules/30-ospp-v42-5-perm-change-failed.rules /etc/audit/rules.d/
Load new Audit rules into kernel by running:
augenrules --load
Note: This rule utilizes a file provided by Audit package to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs.
Rationale:
Unsuccessful attempts to change permissions of files or directories might be signs of malicious activity. Having such events audited helps in monitoring and investigation of such activities.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_audit_perm_change_failed
Identifiers and References

References:  AU-2(a), FAU_GEN.1.1.c, SRG-OS-000462-GPOS-00206, SRG-OS-000463-GPOS-00207, SRG-OS-000465-GPOS-00209, SRG-OS-000474-GPOS-00219, SRG-OS-000475-GPOS-00220, SRG-OS-000466-GPOS-00210, SRG-OS-000064-GPOS-00033


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules
## Unsuccessful permission change
-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change
-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change
EOF

chmod o-rwx /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules

augenrules --load

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Put contents into /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules
    according to policy
  copy:
    dest: /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules
    content: |
      ## Unsuccessful permission change
      -a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change
      -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EACCES -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change
      -a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change
      -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F exit=-EPERM -F auid>=1000 -F auid!=unset -F key=unsuccessful-perm-change
    force: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_perm_change_failed
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Remove any permissions from other group
  file:
    path: /etc/audit/rules.d/30-ospp-v42-5-perm-change-failed.rules
    mode: o-rwx
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_perm_change_failed
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Configure auditing of successful permission changes   [ref]

Ensure that successful attempts to modify permissions of files or directories are audited. The following rules configure audit as described above:
## Successful permission change
-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change    
The Audit package provides pre-configured rules in /usr/share/audit/sample-rules. The above content can be found in /usr/share/audit/sample-rules/30-ospp-v42-5-perm-change-success.rules. To deploy this configuration, it is recommended to copy it over to the /etc/audit/rules.d/ directory:
cp /usr/share/audit/sample-rules/30-ospp-v42-5-perm-change-success.rules /etc/audit/rules.d/
Load new Audit rules into kernel by running:
augenrules --load
Note: This rule utilizes a file provided by Audit package to comply with OSPP 4.2.1. You may reuse this rule in different profiles. If you decide to do so, it is recommended that you inspect contents of the file closely and make sure that they are alligned with your needs.
Rationale:
Auditing successful file or directory permission changes helps in monitoring and investigating of activities performed on the system.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_audit_perm_change_success
Identifiers and References

References:  AU-2(a), FAU_GEN.1.1.c, SRG-OS-000462-GPOS-00206, SRG-OS-000463-GPOS-00207, SRG-OS-000465-GPOS-00209, SRG-OS-000474-GPOS-00219, SRG-OS-000475-GPOS-00220, SRG-OS-000466-GPOS-00210, SRG-OS-000064-GPOS-00033


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

cat << 'EOF' > /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules
## Successful permission change
-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change
EOF

chmod o-rwx /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules

augenrules --load

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Put contents into /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules
    according to policy
  copy:
    dest: /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules
    content: |
      ## Successful permission change
      -a always,exit -F arch=b32 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change
      -a always,exit -F arch=b64 -S chmod,fchmod,fchmodat,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F success=1 -F auid>=1000 -F auid!=unset -F key=successful-perm-change
    force: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_perm_change_success
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Remove any permissions from other group
  file:
    path: /etc/audit/rules.d/30-ospp-v42-5-perm-change-success.rules
    mode: o-rwx
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AU-2(a)
    - audit_perm_change_success
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Install audispd-plugins Package   [ref]

The audispd-plugins package can be installed with the following command:
$ sudo dnf install audispd-plugins
Rationale:
audispd-plugins provides plugins for the real-time interface to the audit subsystem, audispd. These plugins can do things like relay events to remote machines or analyze events for suspicious behavior.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_audispd-plugins_installed
Identifiers and References

References:  FMT_SMF_EXT.1, SRG-OS-000342-GPOS-00133


Complexity:low
Disruption:low
Strategy:enable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if ! rpm -q --quiet "audispd-plugins" ; then
    dnf install -y "audispd-plugins"
fi

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

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure audispd-plugins is installed
  package:
    name: audispd-plugins
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_audispd-plugins_installed

Complexity:low
Disruption:low
Strategy:enable
include install_audispd-plugins

class install_audispd-plugins {
  package { 'audispd-plugins':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=audispd-plugins


[[packages]]
name = "audispd-plugins"
version = "*"

Rule   Ensure the audit Subsystem is Installed   [ref]

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.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_audit_installed
Identifiers and References

References:  BP28(R50), CCI-000172, CCI-001814, CCI-001875, CCI-001877, CCI-001878, CCI-001879, CCI-001880, CCI-001881, CCI-001882, CCI-001889, CCI-001914, CCI-000169, CIP-004-6 R3.3, CIP-007-3 R6.5, AC-7(a), AU-7(1), AU-7(2), AU-14, AU-12(2), AU-2(a), CM-6(a), FAU_GEN.1, SRG-OS-000122-GPOS-00063, SRG-OS-000337-GPOS-00129, SRG-OS-000348-GPOS-00136, SRG-OS-000349-GPOS-00137, SRG-OS-000350-GPOS-00138, SRG-OS-000351-GPOS-00139, SRG-OS-000352-GPOS-00140, SRG-OS-000353-GPOS-00141, SRG-OS-000354-GPOS-00142, SRG-OS-000358-GPOS-00145, SRG-OS-000359-GPOS-00146, SRG-OS-000365-GPOS-00152, SRG-OS-000474-GPOS-00219, SRG-OS-000475-GPOS-00220, SRG-OS-000480-GPOS-00227, SRG-OS-000062-GPOS-00031


Complexity:low
Disruption:low
Strategy:enable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if ! rpm -q --quiet "audit" ; then
    dnf install -y "audit"
fi

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

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure audit is installed
  package:
    name: audit
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AC-7(a)
    - NIST-800-53-AU-12(2)
    - NIST-800-53-AU-14
    - NIST-800-53-AU-2(a)
    - NIST-800-53-AU-7(1)
    - NIST-800-53-AU-7(2)
    - NIST-800-53-CM-6(a)
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_audit_installed

Complexity:low
Disruption:low
Strategy:enable
include install_audit

class install_audit {
  package { 'audit':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=audit


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

Rule   Enable auditd Service   [ref]

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.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_service_auditd_enabled
Identifiers and References

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, CIP-004-6 R3.3, CIP-007-3 R6.5, AC-2(g), AU-3, AU-10, AU-2(d), AU-12(c), AU-14(1), AC-6(9), CM-6(a), SI-4(23), 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, FAU_GEN.1, 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, 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


Complexity:low
Disruption:low
Strategy:enable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ] && { rpm --quiet -q audit; }; 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

Complexity:low
Disruption:low
Strategy:enable
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CJIS-5.4.1.1
    - NIST-800-171-3.3.1
    - NIST-800-171-3.3.2
    - NIST-800-171-3.3.6
    - NIST-800-53-AC-2(g)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-10
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-14(1)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-AU-3
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SI-4(23)
    - PCI-DSS-Req-10.1
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_auditd_enabled

- 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"]
    - '"audit" in ansible_facts.packages'
  tags:
    - CJIS-5.4.1.1
    - NIST-800-171-3.3.1
    - NIST-800-171-3.3.2
    - NIST-800-171-3.3.6
    - NIST-800-53-AC-2(g)
    - NIST-800-53-AC-6(9)
    - NIST-800-53-AU-10
    - NIST-800-53-AU-12(c)
    - NIST-800-53-AU-14(1)
    - NIST-800-53-AU-2(d)
    - NIST-800-53-AU-3
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SI-4(23)
    - PCI-DSS-Req-10.1
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_auditd_enabled

Complexity:low
Disruption:low
Strategy:enable
include enable_auditd

class enable_auditd {
  service {'auditd':
    enable => true,
    ensure => 'running',
  }
}

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    systemd:
      units:
      - name: auditd.service
        enabled: true


[customizations.services]
enabled = ["auditd"]

Rule   Enable Auditing for Processes Which Start Prior to the Audit Daemon   [ref]

To ensure all processes can be audited, even those which start prior to the audit daemon, add the argument audit=1 to the default GRUB 2 command line for the Linux operating system. Configure the default Grub2 kernel command line to contain audit=1 as follows:
# grub2-editenv - set "$(grub2-editenv - list | grep kernelopts) audit=1"
Rationale:
Each process on the system carries an "auditable" flag which indicates whether its activities can be audited. Although auditd takes care of enabling this for all processes which launch after it does, adding the kernel argument ensures it is set for every process during boot.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_grub2_audit_argument
Identifiers and References

References:  1, 11, 12, 13, 14, 15, 16, 19, 3, 4, 5, 6, 7, 8, 5.4.1.1, APO10.01, APO10.03, APO10.04, APO10.05, APO11.04, APO12.06, APO13.01, BAI03.05, BAI08.02, DSS01.04, DSS02.02, DSS02.04, DSS02.07, DSS03.01, DSS05.02, DSS05.03, DSS05.04, DSS05.07, MEA01.01, MEA01.02, MEA01.03, MEA01.04, MEA01.05, MEA02.01, 3.3.1, CCI-001464, CCI-000130, 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 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.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, AC-17(1), AU-14(1), AU-10, CM-6(a), IR-5(1), DE.AE-3, DE.AE-5, ID.SC-4, PR.AC-3, PR.PT-1, PR.PT-4, RS.AN-1, RS.AN-4, Req-10.3, SRG-OS-000037-GPOS-00015, SRG-OS-000042-GPOS-00020, SRG-OS-000062-GPOS-00031, SRG-OS-000392-GPOS-00172, SRG-OS-000462-GPOS-00206, SRG-OS-000471-GPOS-00215, SRG-OS-000473-GPOS-00218, SRG-OS-000254-GPOS-00095, SRG-OS-000254-VMM-000880


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

grubby --update-kernel=ALL --args=audit=1

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

Complexity:medium
Disruption:low
Reboot:true
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CJIS-5.4.1.1
    - NIST-800-171-3.3.1
    - NIST-800-53-AC-17(1)
    - NIST-800-53-AU-10
    - NIST-800-53-AU-14(1)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IR-5(1)
    - PCI-DSS-Req-10.3
    - grub2_audit_argument
    - low_disruption
    - medium_complexity
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Update grub defaults and the bootloader menu
  command: /sbin/grubby --update-kernel=ALL --args="audit=1"
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"grub2-common" in ansible_facts.packages'
  tags:
    - CJIS-5.4.1.1
    - NIST-800-171-3.3.1
    - NIST-800-53-AC-17(1)
    - NIST-800-53-AU-10
    - NIST-800-53-AU-14(1)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IR-5(1)
    - PCI-DSS-Req-10.3
    - grub2_audit_argument
    - low_disruption
    - medium_complexity
    - medium_severity
    - reboot_required
    - restrict_strategy


[customizations.kernel]
append = "audit=1"

Rule   Extend Audit Backlog Limit for the Audit Daemon   [ref]

To improve the kernel capacity to queue all log events, even those which occurred prior to the audit daemon, add the argument audit_backlog_limit=8192 to the default GRUB 2 command line for the Linux operating system. Configure the default Grub2 kernel command line to contain audit_backlog_limit=8192 as follows:
# grub2-editenv - set "$(grub2-editenv - list | grep kernelopts) audit_backlog_limit=8192"
Rationale:
audit_backlog_limit sets the queue length for audit events awaiting transfer to the audit daemon. Until the audit daemon is up and running, all log messages are stored in this queue. If the queue is overrun during boot process, the action defined by audit failure flag is taken.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_grub2_audit_backlog_limit_argument
Identifiers and References

References:  CCI-001849, CM-6(a), FAU_STG.1, FAU_STG.3, SRG-OS-000254-GPOS-00095, SRG-OS-000341-GPOS-00132


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

grubby --update-kernel=ALL --args=audit_backlog_limit=8192

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

Complexity:medium
Disruption:low
Reboot:true
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - NIST-800-53-CM-6(a)
    - grub2_audit_backlog_limit_argument
    - low_disruption
    - medium_complexity
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Update grub defaults and the bootloader menu
  command: /sbin/grubby --update-kernel=ALL --args="audit_backlog_limit=8192"
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"grub2-common" in ansible_facts.packages'
  tags:
    - NIST-800-53-CM-6(a)
    - grub2_audit_backlog_limit_argument
    - low_disruption
    - medium_complexity
    - medium_severity
    - reboot_required
    - restrict_strategy


[customizations.kernel]
append = "audit_backlog_limit=8192"
Group   GRUB2 bootloader configuration   Group contains 1 group and 4 rules
[ref]   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 AlmaLinux 9 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.
Group   UEFI GRUB2 bootloader configuration   Group contains 1 rule
[ref]   UEFI GRUB2 bootloader configuration

Rule   Set the UEFI Boot Loader Password   [ref]

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-setpassword
When prompted, enter the password that was selected.

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.
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_grub2_uefi_password
Identifiers and References

References:  BP28(R17), 11, 12, 14, 15, 16, 18, 3, 5, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.03, DSS06.06, 3.4.5, CCI-000213, 164.308(a)(1)(ii)(B), 164.308(a)(7)(i), 164.308(a)(7)(ii)(A), 164.310(a)(1), 164.310(a)(2)(i), 164.310(a)(2)(ii), 164.310(a)(2)(iii), 164.310(b), 164.310(c), 164.310(d)(1), 164.310(d)(2)(iii), 4.3.3.2.2, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, A.6.1.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), PR.AC-4, PR.AC-6, PR.PT-3, FIA_UAU.1, SRG-OS-000080-GPOS-00048

Rule   Configure kernel to zero out memory before allocation   [ref]

To configure the kernel to zero out memory before allocating it, add the init_on_alloc=1 argument to the default GRUB 2 command line. Configure the default Grub2 kernel command line to contain init_on_alloc=1 as follows:
# grub2-editenv - set "$(grub2-editenv - list | grep kernelopts) init_on_alloc=1"
Rationale:
When the kernel configuration option init_on_alloc is enabled, all page allocator and slab allocator memory will be zeroed when allocated, eliminating many kinds of "uninitialized heap memory" flaws, effectively preventing data leaks.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_grub2_init_on_alloc_argument
Identifiers and References

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

grubby --update-kernel=ALL --args=init_on_alloc=1

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

Complexity:medium
Disruption:low
Reboot:true
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - grub2_init_on_alloc_argument
    - low_disruption
    - medium_complexity
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Update grub defaults and the bootloader menu
  command: /sbin/grubby --update-kernel=ALL --args="init_on_alloc=1"
  when:
    - '"grub2-common" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - grub2_init_on_alloc_argument
    - low_disruption
    - medium_complexity
    - medium_severity
    - reboot_required
    - restrict_strategy


[customizations.kernel]
append = "init_on_alloc=1"

Rule   Enable randomization of the page allocator   [ref]

To enable randomization of the page allocator in the kernel, add the page_alloc.shuffle=1 argument to the default GRUB 2 command line. Configure the default Grub2 kernel command line to contain page_alloc.shuffle=1 as follows:
# grub2-editenv - set "$(grub2-editenv - list | grep kernelopts) page_alloc.shuffle=1"
Rationale:
The CONFIG_SHUFFLE_PAGE_ALLOCATOR config option is primarily focused on improving the average utilization of a direct-mapped memory-side-cache. Aside of this performance effect, it also reduces predictability of page allocations in situations when the bad actor can crash the system and somehow leverage knowledge of (page) allocation order right after a fresh reboot, or can control the timing between a hot-pluggable memory node (as in NUMA node) and applications allocating memory ouf of that node. The page_alloc.shuffle=1 kernel command line parameter then forces this functionality irrespectively of memory cache architecture.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_grub2_page_alloc_shuffle_argument
Identifiers and References

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

grubby --update-kernel=ALL --args=page_alloc.shuffle=1

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

Complexity:medium
Disruption:low
Reboot:true
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - grub2_page_alloc_shuffle_argument
    - low_disruption
    - medium_complexity
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Update grub defaults and the bootloader menu
  command: /sbin/grubby --update-kernel=ALL --args="page_alloc.shuffle=1"
  when:
    - '"grub2-common" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - grub2_page_alloc_shuffle_argument
    - low_disruption
    - medium_complexity
    - medium_severity
    - reboot_required
    - restrict_strategy


[customizations.kernel]
append = "page_alloc.shuffle=1"

Rule   Disable vsyscalls   [ref]

To disable use of virtual syscalls, add the argument vsyscall=none to the default GRUB 2 command line for the Linux operating system. Configure the default Grub2 kernel command line to contain vsyscall=none as follows:
# grub2-editenv - set "$(grub2-editenv - list | grep kernelopts) vsyscall=none"
Rationale:
Virtual Syscalls provide an opportunity of attack for a user who has control of the return instruction pointer.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_grub2_vsyscall_argument
Identifiers and References

References:  CCI-001084, CM-7(a), FPT_ASLR_EXT.1, SRG-OS-000480-GPOS-00227, SRG-OS-000134-GPOS-00068


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

grubby --update-kernel=ALL --args=vsyscall=none

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

Complexity:medium
Disruption:low
Reboot:true
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - NIST-800-53-CM-7(a)
    - grub2_vsyscall_argument
    - low_disruption
    - medium_complexity
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Update grub defaults and the bootloader menu
  command: /sbin/grubby --update-kernel=ALL --args="vsyscall=none"
  when:
    - '"grub2-common" in ansible_facts.packages'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-CM-7(a)
    - grub2_vsyscall_argument
    - low_disruption
    - medium_complexity
    - medium_severity
    - reboot_required
    - restrict_strategy


[customizations.kernel]
append = "vsyscall=none"
Group   zIPL bootloader configuration   Group contains 7 rules
[ref]   During the boot process, the bootloader is responsible for starting the execution of the kernel and passing options to it. The default AlmaLinux 9 boot loader for s390x systems is called zIPL.

Rule   Enable Auditing to Start Prior to the Audit Daemon in zIPL   [ref]

To ensure all processes can be audited, even those which start prior to the audit daemon, check that all boot entries in /boot/loader/entries/*.conf have audit=1 included in its options.
To ensure that new kernels and boot entries continue to enable audit, add audit=1 to /etc/kernel/cmdline.
Rationale:
Each process on the system carries an "auditable" flag which indicates whether its activities can be audited. Although auditd takes care of enabling this for all processes which launch after it does, adding the kernel argument ensures it is set for every process during boot.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_zipl_audit_argument
Identifiers and References

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

# Correct BLS option using grubby, which is a thin wrapper around BLS operations
grubby --update-kernel=ALL --args="audit=1"

# Ensure new kernels and boot entries retain the boot option
if [ ! -f /etc/kernel/cmdline ]; then
    echo "audit=1" > /etc/kernel/cmdline
elif ! grep -q '^(.*\s)?audit=1(\s.*)?$' /etc/kernel/cmdline; then
    
    sed -Ei 's/^(.*)$/\1 audit=1/' /etc/kernel/cmdline
fi

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

Complexity:medium
Disruption:low
Reboot:true
Strategy:configure
- name: Ensure BLS boot entries options contain audit=1
  block:

    - name: 'Check how many boot entries exist '
      find:
        paths: /boot/loader/entries/
        patterns: '*.conf'
      register: n_entries

    - name: Check how many boot entries set audit=1
      find:
        paths: /boot/loader/entries/
        contains: ^options .*audit=1.*$
        patterns: '*.conf'
      register: n_entries_options

    - name: Update boot entries options
      command: grubby --update-kernel=ALL --args="audit=1"
      when: n_entries is defined and n_entries_options is defined and n_entries.matched
        != n_entries_options.matched

    - name: Check if /etc/kernel/cmdline exists
      stat:
        path: /etc/kernel/cmdline
      register: cmdline_stat

    - name: Check if /etc/kernel/cmdline contains audit=1
      find:
        paths: /etc/kernel/
        patterns: cmdline
        contains: ^.*audit=1.*$
      register: cmdline_find

    - name: Add /etc/kernel/cmdline contains audit=1
      lineinfile:
        create: true
        path: /etc/kernel/cmdline
        line: audit=1
      when: cmdline_stat is defined and not cmdline_stat.stat.exists

    - name: Append /etc/kernel/cmdline contains audit=1
      lineinfile:
        path: /etc/kernel/cmdline
        backrefs: true
        regexp: ^(.*)$
        line: \1 audit=1
      when: cmdline_stat is defined and cmdline_stat.stat.exists and cmdline_find
        is defined and cmdline_find.matched == 0
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - configure_strategy
    - low_disruption
    - medium_complexity
    - medium_severity
    - reboot_required
    - zipl_audit_argument

Rule   Extend Audit Backlog Limit for the Audit Daemon in zIPL   [ref]

To improve the kernel capacity to queue all log events, even those which start prior to the audit daemon, check that all boot entries in /boot/loader/entries/*.conf have audit_backlog_limit=8192 included in its options.
To ensure that new kernels and boot entries continue to extend the audit log events queue, add audit_backlog_limit=8192 to /etc/kernel/cmdline.
Rationale:
audit_backlog_limit sets the queue length for audit events awaiting transfer to the audit daemon. Until the audit daemon is up and running, all log messages are stored in this queue. If the queue is overrun during boot process, the action defined by audit failure flag is taken.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_zipl_audit_backlog_limit_argument
Identifiers and References

References:  FAU_STG.1, FAU_STG.3


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

# Correct BLS option using grubby, which is a thin wrapper around BLS operations
grubby --update-kernel=ALL --args="audit_backlog_limit=8192"

# Ensure new kernels and boot entries retain the boot option
if [ ! -f /etc/kernel/cmdline ]; then
    echo "audit_backlog_limit=8192" > /etc/kernel/cmdline
elif ! grep -q '^(.*\s)?audit_backlog_limit=8192(\s.*)?$' /etc/kernel/cmdline; then
    
    sed -Ei 's/^(.*)$/\1 audit_backlog_limit=8192/' /etc/kernel/cmdline
fi

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

Complexity:medium
Disruption:low
Reboot:true
Strategy:configure
- name: Ensure BLS boot entries options contain audit_backlog_limit=8192
  block:

    - name: 'Check how many boot entries exist '
      find:
        paths: /boot/loader/entries/
        patterns: '*.conf'
      register: n_entries

    - name: Check how many boot entries set audit_backlog_limit=8192
      find:
        paths: /boot/loader/entries/
        contains: ^options .*audit_backlog_limit=8192.*$
        patterns: '*.conf'
      register: n_entries_options

    - name: Update boot entries options
      command: grubby --update-kernel=ALL --args="audit_backlog_limit=8192"
      when: n_entries is defined and n_entries_options is defined and n_entries.matched
        != n_entries_options.matched

    - name: Check if /etc/kernel/cmdline exists
      stat:
        path: /etc/kernel/cmdline
      register: cmdline_stat

    - name: Check if /etc/kernel/cmdline contains audit_backlog_limit=8192
      find:
        paths: /etc/kernel/
        patterns: cmdline
        contains: ^.*audit_backlog_limit=8192.*$
      register: cmdline_find

    - name: Add /etc/kernel/cmdline contains audit_backlog_limit=8192
      lineinfile:
        create: true
        path: /etc/kernel/cmdline
        line: audit_backlog_limit=8192
      when: cmdline_stat is defined and not cmdline_stat.stat.exists

    - name: Append /etc/kernel/cmdline contains audit_backlog_limit=8192
      lineinfile:
        path: /etc/kernel/cmdline
        backrefs: true
        regexp: ^(.*)$
        line: \1 audit_backlog_limit=8192
      when: cmdline_stat is defined and cmdline_stat.stat.exists and cmdline_find
        is defined and cmdline_find.matched == 0
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - configure_strategy
    - low_disruption
    - medium_complexity
    - medium_severity
    - reboot_required
    - zipl_audit_backlog_limit_argument

Rule   Ensure all zIPL boot entries are BLS compliant   [ref]

Ensure that zIPL boot entries fully adheres to Boot Loader Specification (BLS) by checking that /etc/zipl.conf doesn't contain image = .
Warning:  To prevent breakage or removal of all boot entries oconfigured in /etc/zipl.conf automated remediation for this rule is not available.
Rationale:
AlmaLinux 9 adheres to Boot Loader Specification (BLS) and is the prefered method of configuration.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_zipl_bls_entries_only
Identifiers and References

Rule   Ensure zIPL bootmap is up to date   [ref]

Make sure that /boot/bootmap is up to date.
Every time a boot entry or zIPL configuration is changed /boot/bootmap needs to be updated to reflect the changes.
Run zipl command to generate an updated /boot/bootmap.
Rationale:
The file /boot/bootmap contains all boot data, keeping it up to date is crucial to boot correct kernel and options.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_zipl_bootmap_is_up_to_date
Identifiers and References

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

/usr/sbin/zipl

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

Rule   Configure kernel to zero out memory before allocation in zIPL   [ref]

To ensure that the kernel is configured to zero out memory before allocation, check that all boot entries in /boot/loader/entries/*.conf have init_on_alloc=1 included in its options.
To ensure that new kernels and boot entries continue to zero out memory before allocation, add init_on_alloc=1 to /etc/kernel/cmdline.
Rationale:
When the kernel configuration option init_on_alloc is enabled, all page allocator and slab allocator memory will be zeroed when allocated, eliminating many kinds of "uninitialized heap memory" flaws, effectively preventing data leaks.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_zipl_init_on_alloc_argument
Identifiers and References

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

# Correct BLS option using grubby, which is a thin wrapper around BLS operations
grubby --update-kernel=ALL --args="init_on_alloc=1"

# Ensure new kernels and boot entries retain the boot option
if [ ! -f /etc/kernel/cmdline ]; then
    echo "init_on_alloc=1" > /etc/kernel/cmdline
elif ! grep -q '^(.*\s)?init_on_alloc=1(\s.*)?$' /etc/kernel/cmdline; then
    
    sed -Ei 's/^(.*)$/\1 init_on_alloc=1/' /etc/kernel/cmdline
fi

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

Complexity:medium
Disruption:low
Reboot:true
Strategy:configure
- name: Ensure BLS boot entries options contain init_on_alloc=1
  block:

    - name: 'Check how many boot entries exist '
      find:
        paths: /boot/loader/entries/
        patterns: '*.conf'
      register: n_entries

    - name: Check how many boot entries set init_on_alloc=1
      find:
        paths: /boot/loader/entries/
        contains: ^options .*init_on_alloc=1.*$
        patterns: '*.conf'
      register: n_entries_options

    - name: Update boot entries options
      command: grubby --update-kernel=ALL --args="init_on_alloc=1"
      when: n_entries is defined and n_entries_options is defined and n_entries.matched
        != n_entries_options.matched

    - name: Check if /etc/kernel/cmdline exists
      stat:
        path: /etc/kernel/cmdline
      register: cmdline_stat

    - name: Check if /etc/kernel/cmdline contains init_on_alloc=1
      find:
        paths: /etc/kernel/
        patterns: cmdline
        contains: ^.*init_on_alloc=1.*$
      register: cmdline_find

    - name: Add /etc/kernel/cmdline contains init_on_alloc=1
      lineinfile:
        create: true
        path: /etc/kernel/cmdline
        line: init_on_alloc=1
      when: cmdline_stat is defined and not cmdline_stat.stat.exists

    - name: Append /etc/kernel/cmdline contains init_on_alloc=1
      lineinfile:
        path: /etc/kernel/cmdline
        backrefs: true
        regexp: ^(.*)$
        line: \1 init_on_alloc=1
      when: cmdline_stat is defined and cmdline_stat.stat.exists and cmdline_find
        is defined and cmdline_find.matched == 0
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - configure_strategy
    - low_disruption
    - medium_complexity
    - medium_severity
    - reboot_required
    - zipl_init_on_alloc_argument

Rule   Enable randomization of the page allocator in zIPL   [ref]

To enable the randomization of the page allocator in the kernel, check that all boot entries in /boot/loader/entries/*.conf have page_alloc.shuffle=1 included in its options.
To enable randomization of the page allocator also for newly installed kernels, add page_alloc.shuffle=1 to /etc/kernel/cmdline.
Rationale:
The CONFIG_SHUFFLE_PAGE_ALLOCATOR config option is primarily focused on improving the average utilization of a direct-mapped memory-side-cache. Aside of this performance effect, it also reduces predictability of page allocations in situations when the bad actor can crash the system and somehow leverage knowledge of (page) allocation order right after a fresh reboot, or can control the timing between a hot-pluggable memory node (as in NUMA node) and applications allocating memory ouf of that node. The page_alloc.shuffle=1 kernel command line parameter then forces this functionality irrespectively of memory cache architecture.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_zipl_page_alloc_shuffle_argument
Identifiers and References

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

# Correct BLS option using grubby, which is a thin wrapper around BLS operations
grubby --update-kernel=ALL --args="page_alloc.shuffle=1"

# Ensure new kernels and boot entries retain the boot option
if [ ! -f /etc/kernel/cmdline ]; then
    echo "page_alloc.shuffle=1" > /etc/kernel/cmdline
elif ! grep -q '^(.*\s)?page_alloc.shuffle=1(\s.*)?$' /etc/kernel/cmdline; then
    
    sed -Ei 's/^(.*)$/\1 page_alloc.shuffle=1/' /etc/kernel/cmdline
fi

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

Complexity:medium
Disruption:low
Reboot:true
Strategy:configure
- name: Ensure BLS boot entries options contain page_alloc.shuffle=1
  block:

    - name: 'Check how many boot entries exist '
      find:
        paths: /boot/loader/entries/
        patterns: '*.conf'
      register: n_entries

    - name: Check how many boot entries set page_alloc.shuffle=1
      find:
        paths: /boot/loader/entries/
        contains: ^options .*page_alloc.shuffle=1.*$
        patterns: '*.conf'
      register: n_entries_options

    - name: Update boot entries options
      command: grubby --update-kernel=ALL --args="page_alloc.shuffle=1"
      when: n_entries is defined and n_entries_options is defined and n_entries.matched
        != n_entries_options.matched

    - name: Check if /etc/kernel/cmdline exists
      stat:
        path: /etc/kernel/cmdline
      register: cmdline_stat

    - name: Check if /etc/kernel/cmdline contains page_alloc.shuffle=1
      find:
        paths: /etc/kernel/
        patterns: cmdline
        contains: ^.*page_alloc.shuffle=1.*$
      register: cmdline_find

    - name: Add /etc/kernel/cmdline contains page_alloc.shuffle=1
      lineinfile:
        create: true
        path: /etc/kernel/cmdline
        line: page_alloc.shuffle=1
      when: cmdline_stat is defined and not cmdline_stat.stat.exists

    - name: Append /etc/kernel/cmdline contains page_alloc.shuffle=1
      lineinfile:
        path: /etc/kernel/cmdline
        backrefs: true
        regexp: ^(.*)$
        line: \1 page_alloc.shuffle=1
      when: cmdline_stat is defined and cmdline_stat.stat.exists and cmdline_find
        is defined and cmdline_find.matched == 0
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - configure_strategy
    - low_disruption
    - medium_complexity
    - medium_severity
    - reboot_required
    - zipl_page_alloc_shuffle_argument

Rule   Disable vsyscalls in zIPL   [ref]

To disable use of virtual syscalls, check that all boot entries in /boot/loader/entries/*.conf have vsyscall=none included in its options.
To ensure that new kernels and boot entries continue to disable virtual syscalls, add vsyscall=none to /etc/kernel/cmdline.
Rationale:
Virtual Syscalls provide an opportunity of attack for a user who has control of the return instruction pointer.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_zipl_vsyscall_argument
Identifiers and References

References:  FPT_ASLR_EXT.1


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

# Correct BLS option using grubby, which is a thin wrapper around BLS operations
grubby --update-kernel=ALL --args="vsyscall=none"

# Ensure new kernels and boot entries retain the boot option
if [ ! -f /etc/kernel/cmdline ]; then
    echo "vsyscall=none" > /etc/kernel/cmdline
elif ! grep -q '^(.*\s)?vsyscall=none(\s.*)?$' /etc/kernel/cmdline; then
    
    sed -Ei 's/^(.*)$/\1 vsyscall=none/' /etc/kernel/cmdline
fi

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

Complexity:medium
Disruption:low
Reboot:true
Strategy:configure
- name: Ensure BLS boot entries options contain vsyscall=none
  block:

    - name: 'Check how many boot entries exist '
      find:
        paths: /boot/loader/entries/
        patterns: '*.conf'
      register: n_entries

    - name: Check how many boot entries set vsyscall=none
      find:
        paths: /boot/loader/entries/
        contains: ^options .*vsyscall=none.*$
        patterns: '*.conf'
      register: n_entries_options

    - name: Update boot entries options
      command: grubby --update-kernel=ALL --args="vsyscall=none"
      when: n_entries is defined and n_entries_options is defined and n_entries.matched
        != n_entries_options.matched

    - name: Check if /etc/kernel/cmdline exists
      stat:
        path: /etc/kernel/cmdline
      register: cmdline_stat

    - name: Check if /etc/kernel/cmdline contains vsyscall=none
      find:
        paths: /etc/kernel/
        patterns: cmdline
        contains: ^.*vsyscall=none.*$
      register: cmdline_find

    - name: Add /etc/kernel/cmdline contains vsyscall=none
      lineinfile:
        create: true
        path: /etc/kernel/cmdline
        line: vsyscall=none
      when: cmdline_stat is defined and not cmdline_stat.stat.exists

    - name: Append /etc/kernel/cmdline contains vsyscall=none
      lineinfile:
        path: /etc/kernel/cmdline
        backrefs: true
        regexp: ^(.*)$
        line: \1 vsyscall=none
      when: cmdline_stat is defined and cmdline_stat.stat.exists and cmdline_find
        is defined and cmdline_find.matched == 0
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - configure_strategy
    - low_disruption
    - medium_complexity
    - medium_severity
    - reboot_required
    - zipl_vsyscall_argument
Group   Configure Syslog   Group contains 1 group and 4 rules
[ref]   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 AlmaLinux 9, 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.
Group   Rsyslog Logs Sent To Remote Host   Group contains 2 rules
[ref]   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.

Rule   Configure TLS for rsyslog remote logging   [ref]

Configure rsyslog to use Transport Layer Security (TLS) support for logging to remote server for the Forwarding Output Module in /etc/rsyslog.conf using action. You can use the following command:
echo 'action(type="omfwd" protocol="tcp" Target="<remote system>" port="6514"
    StreamDriver="gtls" StreamDriverMode="1" StreamDriverAuthMode="x509/name" streamdriver.CheckExtendedKeyPurpose="on")' >> /etc/rsyslog.conf
Replace the <remote system> in the above command with an IP address or a host name of the remote logging server.
Rationale:
For protection of data being logged, the connection to the remote logging server needs to be authenticated and encrypted.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_rsyslog_remote_tls
Identifiers and References

References:  BP28(R43), 0988, 1405, AU-9(3), CM-6(a), FCS_TLSC_EXT.1, FTP_ITC_EXT.1.1, FIA_X509_EXT.1.1, FMT_SMF_EXT.1.1, SRG-OS-000480-GPOS-00227, SRG-OS-000120-GPOS-00061

Rule   Configure CA certificate for rsyslog remote logging   [ref]

Configure CA certificate for rsyslog logging to remote server using Transport Layer Security (TLS) using correct path for the DefaultNetstreamDriverCAFile global option in /etc/rsyslog.conf, for example with the following command:
echo 'global(DefaultNetstreamDriverCAFile="/etc/pki/tls/cert.pem")' >> /etc/rsyslog.conf
Replace the /etc/pki/tls/cert.pem in the above command with the path to the file with CA certificate generated for the purpose of remote logging.
Rationale:
The CA certificate needs to be set or rsyslog.service fails to start with
error: ca certificate is not set, cannot continue
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_rsyslog_remote_tls_cacert
Identifiers and References

References:  BP28(R43), 0988, 1405, FCS_TLSC_EXT.1, SRG-OS-000480-GPOS-00227

Rule   Ensure rsyslog-gnutls is installed   [ref]

TLS protocol support for rsyslog is installed. The rsyslog-gnutls package can be installed with the following command:
$ sudo dnf install rsyslog-gnutls
Rationale:
The rsyslog-gnutls package provides Transport Layer Security (TLS) support for the rsyslog daemon, which enables secure remote logging.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_rsyslog-gnutls_installed
Identifiers and References

References:  BP28(R43), CCI-000366, FTP_ITC_EXT.1.1, SRG-OS-000480-GPOS-00227, SRG-OS-000120-GPOS-00061


Complexity:low
Disruption:low
Strategy:enable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if ! rpm -q --quiet "rsyslog-gnutls" ; then
    dnf install -y "rsyslog-gnutls"
fi

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

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure rsyslog-gnutls is installed
  package:
    name: rsyslog-gnutls
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_rsyslog-gnutls_installed

Complexity:low
Disruption:low
Strategy:enable
include install_rsyslog-gnutls

class install_rsyslog-gnutls {
  package { 'rsyslog-gnutls':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=rsyslog-gnutls


[[packages]]
name = "rsyslog-gnutls"
version = "*"

Rule   Ensure rsyslog is Installed   [ref]

Rsyslog is installed by default. The rsyslog package can be installed with the following command:
 $ sudo dnf install rsyslog
Rationale:
The rsyslog package provides the rsyslog daemon, which provides system logging services.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_rsyslog_installed
Identifiers and References

References:  BP28(R5), NT28(R46), 1, 14, 15, 16, 3, 5, 6, APO11.04, BAI03.05, DSS05.04, DSS05.07, MEA02.01, CCI-001311, CCI-001312, CCI-000366, 164.312(a)(2)(ii), 4.3.3.3.9, 4.3.3.5.8, 4.3.4.4.7, 4.4.2.1, 4.4.2.2, 4.4.2.4, SR 2.10, SR 2.11, SR 2.12, SR 2.8, SR 2.9, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.7.1, CM-6(a), PR.PT-1, FTP_ITC_EXT.1.1, SRG-OS-000479-GPOS-00224, SRG-OS-000051-GPOS-00024, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:low
Strategy:enable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if ! rpm -q --quiet "rsyslog" ; then
    dnf install -y "rsyslog"
fi

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

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure rsyslog is installed
  package:
    name: rsyslog
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-CM-6(a)
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_rsyslog_installed

Complexity:low
Disruption:low
Strategy:enable
include install_rsyslog

class install_rsyslog {
  package { 'rsyslog':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=rsyslog


[[packages]]
name = "rsyslog"
version = "*"
Group   Network Configuration and Firewalls   Group contains 10 groups and 28 rules
[ref]   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.
Group   firewalld   Group contains 1 group and 2 rules
[ref]   The dynamic firewall daemon firewalld provides a dynamically managed firewall with support for network “zones” to assign a level of trust to a network and its associated connections and interfaces. It has support for IPv4 and IPv6 firewall settings. It supports Ethernet bridges and has a separation of runtime and permanent configuration options. It also has an interface for services or applications to add firewall rules directly.
A graphical configuration tool, firewall-config, is used to configure firewalld, which in turn uses iptables tool to communicate with Netfilter in the kernel which implements packet filtering.
The firewall service provided by firewalld is dynamic rather than static because changes to the configuration can be made at anytime and are immediately implemented. There is no need to save or apply the changes. No unintended disruption of existing network connections occurs as no part of the firewall has to be reloaded.
Group   Inspect and Activate Default firewalld Rules   Group contains 2 rules
[ref]   Firewalls can be used to separate networks into different zones based on the level of trust the user has decided to place on the devices and traffic within that network. NetworkManager informs firewalld to which zone an interface belongs. An interface's assigned zone can be changed by NetworkManager or via the firewall-config tool.
The zone settings in /etc/firewalld/ are a range of preset settings which can be quickly applied to a network interface. These are the zones provided by firewalld sorted according to the default trust level of the zones from untrusted to trusted:
  • drop

    Any incoming network packets are dropped, there is no reply. Only outgoing network connections are possible.

  • block

    Any incoming network connections are rejected with an icmp-host-prohibited message for IPv4 and icmp6-adm-prohibited for IPv6. Only network connections initiated from within the system are possible.

  • public

    For use in public areas. You do not trust the other computers on the network to not harm your computer. Only selected incoming connections are accepted.

  • external

    For use on external networks with masquerading enabled especially for routers. You do not trust the other computers on the network to not harm your computer. Only selected incoming connections are accepted.

  • dmz

    For computers in your demilitarized zone that are publicly-accessible with limited access to your internal network. Only selected incoming connections are accepted.

  • work

    For use in work areas. You mostly trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted.

  • home

    For use in home areas. You mostly trust the other computers on networks to not harm your computer. Only selected incoming connections are accepted.

  • internal

    For use on internal networks. You mostly trust the other computers on the networks to not harm your computer. Only selected incoming connections are accepted.

  • trusted

    All network connections are accepted.


It is possible to designate one of these zones to be the default zone. When interface connections are added to NetworkManager, they are assigned to the default zone. On installation, the default zone in firewalld is set to be the public zone.
To find out all the settings of a zone, for example the public zone, enter the following command as root:
# firewall-cmd --zone=public --list-all
Example output of this command might look like the following:
# firewall-cmd --zone=public --list-all
public
  interfaces:
  services: mdns dhcpv6-client ssh
  ports:
  forward-ports:
  icmp-blocks: source-quench
To view the network zones currently active, enter the following command as root:
# firewall-cmd --get-service
The following listing displays the result of this command on common AlmaLinux 9 system:
# firewall-cmd --get-service
amanda-client bacula bacula-client dhcp dhcpv6 dhcpv6-client dns ftp
high-availability http https imaps ipp ipp-client ipsec kerberos kpasswd
ldap ldaps libvirt libvirt-tls mdns mountd ms-wbt mysql nfs ntp openvpn
pmcd pmproxy pmwebapi pmwebapis pop3s postgresql proxy-dhcp radius rpc-bind
samba samba-client smtp ssh telnet tftp tftp-client transmission-client
vnc-server wbem-https
Finally to view the network zones that will be active after the next firewalld service reload, enter the following command as root:
# firewall-cmd --get-service --permanent

Rule   Install firewalld Package   [ref]

The firewalld package can be installed with the following command:
$ sudo dnf install firewalld
Rationale:
The firewalld package should be installed to provide access control methods.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_firewalld_installed
Identifiers and References

References:  CCI-002314, CM-6(a), SRG-OS-000096-GPOS-00050, SRG-OS-000297-GPOS-00115, SRG-OS-000298-GPOS-00116, SRG-OS-000480-GPOS-00227, SRG-OS-000480-GPOS-00232


Complexity:low
Disruption:low
Strategy:enable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if ! rpm -q --quiet "firewalld" ; then
    dnf install -y "firewalld"
fi

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

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure firewalld is installed
  package:
    name: firewalld
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-CM-6(a)
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_firewalld_installed

Complexity:low
Disruption:low
Strategy:enable
include install_firewalld

class install_firewalld {
  package { 'firewalld':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=firewalld


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

Rule   Verify firewalld Enabled   [ref]

The firewalld service can be enabled with the following command:
$ sudo systemctl enable firewalld.service
Rationale:
Access control methods provide the ability to enhance system security posture by restricting services and known good IP addresses and address ranges. This prevents connections from unknown hosts and protocols.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_service_firewalld_enabled
Identifiers and References

References:  11, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, 3.1.3, 3.4.7, CCI-000366, CCI-000382, CCI-002314, 4.3.4.3.2, 4.3.4.3.3, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, CIP-003-8 R4, CIP-003-8 R5, CIP-004-6 R3, AC-4, CM-7(b), CA-3(5), SC-7(21), CM-6(a), PR.IP-1, FMT_MOF_EXT.1, SRG-OS-000096-GPOS-00050, SRG-OS-000297-GPOS-00115, SRG-OS-000480-GPOS-00227, SRG-OS-000480-GPOS-00231, SRG-OS-000480-GPOS-00232


Complexity:low
Disruption:low
Strategy:enable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

SYSTEMCTL_EXEC='/usr/bin/systemctl'
"$SYSTEMCTL_EXEC" unmask 'firewalld.service'
"$SYSTEMCTL_EXEC" start 'firewalld.service'
"$SYSTEMCTL_EXEC" enable 'firewalld.service'

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

Complexity:low
Disruption:low
Strategy:enable
- name: Enable service firewalld
  block:

    - name: Gather the package facts
      package_facts:
        manager: auto

    - name: Enable service firewalld
      service:
        name: firewalld
        enabled: 'yes'
        state: started
        masked: 'no'
      when:
        - '"firewalld" in ansible_facts.packages'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.3
    - NIST-800-171-3.4.7
    - NIST-800-53-AC-4
    - NIST-800-53-CA-3(5)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-SC-7(21)
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_firewalld_enabled

Complexity:low
Disruption:low
Strategy:enable
include enable_firewalld

class enable_firewalld {
  service {'firewalld':
    enable => true,
    ensure => 'running',
  }
}


[customizations.services]
enabled = ["firewalld"]
Group   IPv6   Group contains 1 group and 6 rules
[ref]   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.
Group   Configure IPv6 Settings if Necessary   Group contains 6 rules
[ref]   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.

Rule   Configure Accepting Router Advertisements on All IPv6 Interfaces   [ref]

To set the runtime status of the net.ipv6.conf.all.accept_ra kernel parameter, run the following command:
$ sudo sysctl -w net.ipv6.conf.all.accept_ra=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_ra = 0
Rationale:
An illicit router advertisement message could result in a man-in-the-middle attack.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv6_conf_all_accept_ra
Identifiers and References

References:  11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 3.1.20, CCI-000366, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv6.conf.all.accept_ra from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv6.conf.all.accept_ra.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv6.conf.all.accept_ra" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done
sysctl_net_ipv6_conf_all_accept_ra_value='0'


#
# Set runtime for net.ipv6.conf.all.accept_ra
#
/sbin/sysctl -q -n -w net.ipv6.conf.all.accept_ra="$sysctl_net_ipv6_conf_all_accept_ra_value"

#
# If net.ipv6.conf.all.accept_ra present in /etc/sysctl.conf, change value to appropriate value
#	else, add "net.ipv6.conf.all.accept_ra = value" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv6.conf.all.accept_ra")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_accept_ra_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 -i -e "^net.ipv6.conf.all.accept_ra\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv6.conf.all.accept_ra\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv6.conf.all.accept_ra.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_ra

- name: Comment out any occurrences of net.ipv6.conf.all.accept_ra from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv6.conf.all.accept_ra
    replace: '#net.ipv6.conf.all.accept_ra'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_ra
- name: XCCDF Value sysctl_net_ipv6_conf_all_accept_ra_value # promote to variable
  set_fact:
    sysctl_net_ipv6_conf_all_accept_ra_value: !!str 0
  tags:
    - always

- name: Ensure sysctl net.ipv6.conf.all.accept_ra is set
  sysctl:
    name: net.ipv6.conf.all.accept_ra
    value: '{{ sysctl_net_ipv6_conf_all_accept_ra_value }}'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_ra

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv6.conf.all.accept_ra%3D0%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv6_conf_all_accept_ra.conf
        overwrite: true

Rule   Disable Accepting ICMP Redirects for All IPv6 Interfaces   [ref]

To set the runtime status of the net.ipv6.conf.all.accept_redirects kernel parameter, run the following command:
$ sudo sysctl -w net.ipv6.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.ipv6.conf.all.accept_redirects = 0
Rationale:
An illicit ICMP redirect message could result in a man-in-the-middle attack.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv6_conf_all_accept_redirects
Identifiers and References

References:  BP28(R22), 11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 3.1.20, CCI-000366, CCI-001551, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), CM-6(b), CM-6.1(iv), PR.IP-1, PR.PT-3, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv6.conf.all.accept_redirects from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv6.conf.all.accept_redirects.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv6.conf.all.accept_redirects" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done
sysctl_net_ipv6_conf_all_accept_redirects_value='0'


#
# Set runtime for net.ipv6.conf.all.accept_redirects
#
/sbin/sysctl -q -n -w net.ipv6.conf.all.accept_redirects="$sysctl_net_ipv6_conf_all_accept_redirects_value"

#
# If net.ipv6.conf.all.accept_redirects present in /etc/sysctl.conf, change value to appropriate value
#	else, add "net.ipv6.conf.all.accept_redirects = value" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv6.conf.all.accept_redirects")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_accept_redirects_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 -i -e "^net.ipv6.conf.all.accept_redirects\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv6.conf.all.accept_redirects\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv6.conf.all.accept_redirects.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1(iv)
    - 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_redirects

- name: Comment out any occurrences of net.ipv6.conf.all.accept_redirects from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv6.conf.all.accept_redirects
    replace: '#net.ipv6.conf.all.accept_redirects'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1(iv)
    - 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_redirects
- name: XCCDF Value sysctl_net_ipv6_conf_all_accept_redirects_value # promote to variable
  set_fact:
    sysctl_net_ipv6_conf_all_accept_redirects_value: !!str 0
  tags:
    - always

- name: Ensure sysctl net.ipv6.conf.all.accept_redirects is set
  sysctl:
    name: net.ipv6.conf.all.accept_redirects
    value: '{{ sysctl_net_ipv6_conf_all_accept_redirects_value }}'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1(iv)
    - 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_redirects

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv6.conf.all.accept_redirects%3D0%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv6_conf_all_accept_redirects.conf
        overwrite: true

Rule   Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv6 Interfaces   [ref]

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.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv6_conf_all_accept_source_route
Identifiers and References

References:  BP28(R22), 1, 12, 13, 14, 15, 16, 18, 4, 6, 8, 9, APO01.06, APO13.01, DSS01.05, DSS03.01, DSS05.02, DSS05.04, DSS05.07, DSS06.02, 3.1.20, CCI-000366, 4.2.3.4, 4.3.3.4, 4.4.3.3, 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.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-7(a), CM-7(b), CM-6(a), DE.AE-1, ID.AM-3, PR.AC-5, PR.DS-5, PR.PT-4, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv6.conf.all.accept_source_route from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv6.conf.all.accept_source_route.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv6.conf.all.accept_source_route" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done
sysctl_net_ipv6_conf_all_accept_source_route_value='0'


#
# Set runtime for net.ipv6.conf.all.accept_source_route
#
/sbin/sysctl -q -n -w net.ipv6.conf.all.accept_source_route="$sysctl_net_ipv6_conf_all_accept_source_route_value"

#
# If net.ipv6.conf.all.accept_source_route present in /etc/sysctl.conf, change value to appropriate value
#	else, add "net.ipv6.conf.all.accept_source_route = value" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv6.conf.all.accept_source_route")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_all_accept_source_route_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 -i -e "^net.ipv6.conf.all.accept_source_route\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv6.conf.all.accept_source_route\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv6.conf.all.accept_source_route.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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

- name: Comment out any occurrences of net.ipv6.conf.all.accept_source_route from
    /etc/sysctl.d/*.conf files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv6.conf.all.accept_source_route
    replace: '#net.ipv6.conf.all.accept_source_route'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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
- 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:
    - 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

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv6.conf.all.accept_source_route%3D0%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv6_conf_all_accept_source_route.conf
        overwrite: true

Rule   Disable Accepting Router Advertisements on all IPv6 Interfaces by Default   [ref]

To set the runtime status of the net.ipv6.conf.default.accept_ra kernel parameter, run the following command:
$ sudo sysctl -w net.ipv6.conf.default.accept_ra=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_ra = 0
Rationale:
An illicit router advertisement message could result in a man-in-the-middle attack.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv6_conf_default_accept_ra
Identifiers and References

References:  11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 3.1.20, CCI-000366, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv6.conf.default.accept_ra from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv6.conf.default.accept_ra.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv6.conf.default.accept_ra" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done
sysctl_net_ipv6_conf_default_accept_ra_value='0'


#
# Set runtime for net.ipv6.conf.default.accept_ra
#
/sbin/sysctl -q -n -w net.ipv6.conf.default.accept_ra="$sysctl_net_ipv6_conf_default_accept_ra_value"

#
# If net.ipv6.conf.default.accept_ra present in /etc/sysctl.conf, change value to appropriate value
#	else, add "net.ipv6.conf.default.accept_ra = value" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv6.conf.default.accept_ra")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_accept_ra_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 -i -e "^net.ipv6.conf.default.accept_ra\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv6.conf.default.accept_ra\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv6.conf.default.accept_ra.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_default_accept_ra

- name: Comment out any occurrences of net.ipv6.conf.default.accept_ra from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv6.conf.default.accept_ra
    replace: '#net.ipv6.conf.default.accept_ra'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_default_accept_ra
- name: XCCDF Value sysctl_net_ipv6_conf_default_accept_ra_value # promote to variable
  set_fact:
    sysctl_net_ipv6_conf_default_accept_ra_value: !!str 0
  tags:
    - always

- name: Ensure sysctl net.ipv6.conf.default.accept_ra is set
  sysctl:
    name: net.ipv6.conf.default.accept_ra
    value: '{{ sysctl_net_ipv6_conf_default_accept_ra_value }}'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_default_accept_ra

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv6.conf.default.accept_ra%3D0%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv6_conf_default_accept_ra.conf
        overwrite: true

Rule   Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv6 Interfaces   [ref]

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.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv6_conf_default_accept_redirects
Identifiers and References

References:  BP28(R22), 11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 3.1.20, CCI-000366, CCI-001551, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv6.conf.default.accept_redirects from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv6.conf.default.accept_redirects.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv6.conf.default.accept_redirects" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done
sysctl_net_ipv6_conf_default_accept_redirects_value='0'


#
# Set runtime for net.ipv6.conf.default.accept_redirects
#
/sbin/sysctl -q -n -w net.ipv6.conf.default.accept_redirects="$sysctl_net_ipv6_conf_default_accept_redirects_value"

#
# If net.ipv6.conf.default.accept_redirects present in /etc/sysctl.conf, change value to appropriate value
#	else, add "net.ipv6.conf.default.accept_redirects = value" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv6.conf.default.accept_redirects")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_accept_redirects_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 -i -e "^net.ipv6.conf.default.accept_redirects\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv6.conf.default.accept_redirects\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv6.conf.default.accept_redirects.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_default_accept_redirects

- name: Comment out any occurrences of net.ipv6.conf.default.accept_redirects from
    /etc/sysctl.d/*.conf files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv6.conf.default.accept_redirects
    replace: '#net.ipv6.conf.default.accept_redirects'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_default_accept_redirects
- 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:
    - 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_default_accept_redirects

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv6.conf.default.accept_redirects%20%3D%200%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv6_conf_default_accept_redirects.conf
        overwrite: true

Rule   Disable Kernel Parameter for Accepting Source-Routed Packets on IPv6 Interfaces by Default   [ref]

To set the runtime status of the net.ipv6.conf.default.accept_source_route kernel parameter, run the following command:
$ sudo sysctl -w net.ipv6.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.ipv6.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. 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.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv6_conf_default_accept_source_route
Identifiers and References

References:  BP28(R22), 1, 12, 13, 14, 15, 16, 18, 4, 6, 8, 9, APO01.06, APO13.01, DSS01.05, DSS03.01, DSS05.02, DSS05.04, DSS05.07, DSS06.02, 3.1.20, CCI-000366, 4.2.3.4, 4.3.3.4, 4.4.3.3, 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.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-7(a), CM-7(b), CM-6(a), CM-6(b), CM-6.1(iv), DE.AE-1, ID.AM-3, PR.AC-5, PR.DS-5, PR.PT-4, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv6.conf.default.accept_source_route from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv6.conf.default.accept_source_route.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv6.conf.default.accept_source_route" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done
sysctl_net_ipv6_conf_default_accept_source_route_value='0'


#
# Set runtime for net.ipv6.conf.default.accept_source_route
#
/sbin/sysctl -q -n -w net.ipv6.conf.default.accept_source_route="$sysctl_net_ipv6_conf_default_accept_source_route_value"

#
# If net.ipv6.conf.default.accept_source_route present in /etc/sysctl.conf, change value to appropriate value
#	else, add "net.ipv6.conf.default.accept_source_route = value" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv6.conf.default.accept_source_route")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv6_conf_default_accept_source_route_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 -i -e "^net.ipv6.conf.default.accept_source_route\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv6.conf.default.accept_source_route\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv6.conf.default.accept_source_route.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1(iv)
    - 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_default_accept_source_route

- name: Comment out any occurrences of net.ipv6.conf.default.accept_source_route from
    /etc/sysctl.d/*.conf files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv6.conf.default.accept_source_route
    replace: '#net.ipv6.conf.default.accept_source_route'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1(iv)
    - 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_default_accept_source_route
- name: XCCDF Value sysctl_net_ipv6_conf_default_accept_source_route_value # promote to variable
  set_fact:
    sysctl_net_ipv6_conf_default_accept_source_route_value: !!str 0
  tags:
    - always

- name: Ensure sysctl net.ipv6.conf.default.accept_source_route is set
  sysctl:
    name: net.ipv6.conf.default.accept_source_route
    value: '{{ sysctl_net_ipv6_conf_default_accept_source_route_value }}'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-6(b)
    - NIST-800-53-CM-6.1(iv)
    - 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_default_accept_source_route

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv6.conf.default.accept_source_route%3D0%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv6_conf_default_accept_source_route.conf
        overwrite: true
Group   Kernel Parameters Which Affect Networking   Group contains 2 groups and 16 rules
[ref]   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.
Group   Network Related Kernel Runtime Parameters for Hosts and Routers   Group contains 13 rules
[ref]   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.

Rule   Disable Accepting ICMP Redirects for All IPv4 Interfaces   [ref]

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."
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_all_accept_redirects
Identifiers and References

References:  BP28(R22), 1, 11, 12, 13, 14, 15, 16, 2, 3, 7, 8, 9, 5.10.1.1, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS03.05, DSS05.02, DSS05.05, DSS05.07, DSS06.06, 3.1.20, CCI-000366, CCI-001503, CCI-001551, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 6.2, SR 7.1, SR 7.2, SR 7.6, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), SC-7(a), DE.CM-1, PR.DS-4, PR.IP-1, PR.PT-3, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv4.conf.all.accept_redirects from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv4.conf.all.accept_redirects.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv4.conf.all.accept_redirects" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done
sysctl_net_ipv4_conf_all_accept_redirects_value='0'


#
# Set runtime for net.ipv4.conf.all.accept_redirects
#
/sbin/sysctl -q -n -w net.ipv4.conf.all.accept_redirects="$sysctl_net_ipv4_conf_all_accept_redirects_value"

#
# If net.ipv4.conf.all.accept_redirects present in /etc/sysctl.conf, change value to appropriate value
#	else, add "net.ipv4.conf.all.accept_redirects = value" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv4.conf.all.accept_redirects")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_accept_redirects_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 -i -e "^net.ipv4.conf.all.accept_redirects\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv4.conf.all.accept_redirects\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv4.conf.all.accept_redirects.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CJIS-5.10.1.1
    - 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

- name: Comment out any occurrences of net.ipv4.conf.all.accept_redirects from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv4.conf.all.accept_redirects
    replace: '#net.ipv4.conf.all.accept_redirects'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CJIS-5.10.1.1
    - 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
- 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:
    - CJIS-5.10.1.1
    - 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

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv4.conf.all.accept_redirects%3D0%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_all_accept_redirects.conf
        overwrite: true

Rule   Disable Kernel Parameter for Accepting Source-Routed Packets on all IPv4 Interfaces   [ref]

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.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_all_accept_source_route
Identifiers and References

References:  BP28(R22), 1, 11, 12, 13, 14, 15, 16, 18, 2, 3, 4, 6, 7, 8, 9, APO01.06, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.06, 3.1.20, CCI-000366, 4.2.3.4, 4.3.3.4, 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.4.3.3, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, 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.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-007-3 R4, CIP-007-3 R4.1, CIP-007-3 R4.2, CIP-007-3 R5.1, CM-7(a), CM-7(b), SC-5, CM-6(a), SC-7(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv4.conf.all.accept_source_route from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv4.conf.all.accept_source_route.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv4.conf.all.accept_source_route" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done
sysctl_net_ipv4_conf_all_accept_source_route_value='0'


#
# Set runtime for net.ipv4.conf.all.accept_source_route
#
/sbin/sysctl -q -n -w net.ipv4.conf.all.accept_source_route="$sysctl_net_ipv4_conf_all_accept_source_route_value"

#
# If net.ipv4.conf.all.accept_source_route present in /etc/sysctl.conf, change value to appropriate value
#	else, add "net.ipv4.conf.all.accept_source_route = value" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv4.conf.all.accept_source_route")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_accept_source_route_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 -i -e "^net.ipv4.conf.all.accept_source_route\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv4.conf.all.accept_source_route\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv4.conf.all.accept_source_route.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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

- name: Comment out any occurrences of net.ipv4.conf.all.accept_source_route from
    /etc/sysctl.d/*.conf files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv4.conf.all.accept_source_route
    replace: '#net.ipv4.conf.all.accept_source_route'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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
- 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:
    - 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

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv4.conf.all.accept_source_route%3D0%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_all_accept_source_route.conf
        overwrite: true

Rule   Enable Kernel Parameter to Log Martian Packets on all IPv4 Interfaces   [ref]

To set the runtime status of the net.ipv4.conf.all.log_martians kernel parameter, run the following command:
$ sudo sysctl -w net.ipv4.conf.all.log_martians=1
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.log_martians = 1
Rationale:
The presence of "martian" packets (which have impossible addresses) as well as spoofed packets, source-routed packets, and redirects could be a sign of nefarious network activity. Logging these packets enables this activity to be detected.
Severity: 
unknown
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_all_log_martians
Identifiers and References

References:  BP28(R22), 1, 11, 12, 13, 14, 15, 16, 2, 3, 7, 8, 9, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.04, DSS03.05, DSS05.02, DSS05.03, DSS05.05, DSS05.07, DSS06.06, 3.1.20, CCI-000126, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, 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.2, SR 7.1, SR 7.2, SR 7.6, A.11.2.6, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, 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.17.2.1, A.6.2.1, A.6.2.2, A.9.1.2, CM-7(a), CM-7(b), SC-5(3)(a), DE.CM-1, PR.AC-3, PR.DS-4, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv4.conf.all.log_martians from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv4.conf.all.log_martians.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv4.conf.all.log_martians" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done
sysctl_net_ipv4_conf_all_log_martians_value='1'


#
# Set runtime for net.ipv4.conf.all.log_martians
#
/sbin/sysctl -q -n -w net.ipv4.conf.all.log_martians="$sysctl_net_ipv4_conf_all_log_martians_value"

#
# If net.ipv4.conf.all.log_martians present in /etc/sysctl.conf, change value to appropriate value
#	else, add "net.ipv4.conf.all.log_martians = value" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv4.conf.all.log_martians")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_log_martians_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 -i -e "^net.ipv4.conf.all.log_martians\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv4.conf.all.log_martians\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv4.conf.all.log_martians.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-SC-5(3)(a)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - reboot_required
    - sysctl_net_ipv4_conf_all_log_martians
    - unknown_severity

- name: Comment out any occurrences of net.ipv4.conf.all.log_martians from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv4.conf.all.log_martians
    replace: '#net.ipv4.conf.all.log_martians'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-SC-5(3)(a)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - reboot_required
    - sysctl_net_ipv4_conf_all_log_martians
    - unknown_severity
- name: XCCDF Value sysctl_net_ipv4_conf_all_log_martians_value # promote to variable
  set_fact:
    sysctl_net_ipv4_conf_all_log_martians_value: !!str 1
  tags:
    - always

- name: Ensure sysctl net.ipv4.conf.all.log_martians is set
  sysctl:
    name: net.ipv4.conf.all.log_martians
    value: '{{ sysctl_net_ipv4_conf_all_log_martians_value }}'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-SC-5(3)(a)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - reboot_required
    - sysctl_net_ipv4_conf_all_log_martians
    - unknown_severity

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv4.conf.all.log_martians%3D1%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_all_log_martians.conf
        overwrite: true

Rule   Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces   [ref]

To set the runtime status of the net.ipv4.conf.all.rp_filter kernel parameter, run the following command:
$ sudo sysctl -w net.ipv4.conf.all.rp_filter=1
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.rp_filter = 1
Rationale:
Enabling reverse path filtering drops packets with source addresses that should not have been able to be received on the interface they were received on. It should not be used on systems which are routers for complicated networks, but is helpful for end hosts and routers serving small networks.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_all_rp_filter
Identifiers and References

References:  BP28(R22), 1, 12, 13, 14, 15, 16, 18, 2, 4, 6, 7, 8, 9, APO01.06, APO13.01, BAI04.04, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.07, DSS06.02, 3.1.20, CCI-000366, CCI-001551, 4.2.3.4, 4.3.3.4, 4.4.3.3, 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.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-7(a), CM-7(b), CM-6(a), SC-7(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.PT-4, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv4.conf.all.rp_filter from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv4.conf.all.rp_filter.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv4.conf.all.rp_filter" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done
sysctl_net_ipv4_conf_all_rp_filter_value='1'


#
# Set runtime for net.ipv4.conf.all.rp_filter
#
/sbin/sysctl -q -n -w net.ipv4.conf.all.rp_filter="$sysctl_net_ipv4_conf_all_rp_filter_value"

#
# If net.ipv4.conf.all.rp_filter present in /etc/sysctl.conf, change value to appropriate value
#	else, add "net.ipv4.conf.all.rp_filter = value" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv4.conf.all.rp_filter")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_rp_filter_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 -i -e "^net.ipv4.conf.all.rp_filter\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv4.conf.all.rp_filter\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv4.conf.all.rp_filter.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_rp_filter

- name: Comment out any occurrences of net.ipv4.conf.all.rp_filter from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv4.conf.all.rp_filter
    replace: '#net.ipv4.conf.all.rp_filter'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_rp_filter
- name: XCCDF Value sysctl_net_ipv4_conf_all_rp_filter_value # promote to variable
  set_fact:
    sysctl_net_ipv4_conf_all_rp_filter_value: !!str 1
  tags:
    - always

- name: Ensure sysctl net.ipv4.conf.all.rp_filter is set
  sysctl:
    name: net.ipv4.conf.all.rp_filter
    value: '{{ sysctl_net_ipv4_conf_all_rp_filter_value }}'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_rp_filter

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv4.conf.all.rp_filter%3D1%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_all_rp_filter.conf
        overwrite: true

Rule   Disable Kernel Parameter for Accepting Secure ICMP Redirects on all IPv4 Interfaces   [ref]

To set the runtime status of the net.ipv4.conf.all.secure_redirects kernel parameter, run the following command:
$ sudo sysctl -w net.ipv4.conf.all.secure_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.secure_redirects = 0
Rationale:
Accepting "secure" ICMP redirects (from those gateways listed as default gateways) has few legitimate uses. It should be disabled unless it is absolutely required.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_all_secure_redirects
Identifiers and References

References:  BP28(R22), 1, 11, 12, 13, 14, 15, 16, 18, 2, 3, 4, 6, 7, 8, 9, APO01.06, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.06, 3.1.20, CCI-001503, CCI-001551, 4.2.3.4, 4.3.3.4, 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.4.3.3, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, 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.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-7(a), CM-7(b), CM-6(a), SC-7(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv4.conf.all.secure_redirects from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv4.conf.all.secure_redirects.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv4.conf.all.secure_redirects" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done
sysctl_net_ipv4_conf_all_secure_redirects_value='0'


#
# Set runtime for net.ipv4.conf.all.secure_redirects
#
/sbin/sysctl -q -n -w net.ipv4.conf.all.secure_redirects="$sysctl_net_ipv4_conf_all_secure_redirects_value"

#
# If net.ipv4.conf.all.secure_redirects present in /etc/sysctl.conf, change value to appropriate value
#	else, add "net.ipv4.conf.all.secure_redirects = value" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv4.conf.all.secure_redirects")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_all_secure_redirects_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 -i -e "^net.ipv4.conf.all.secure_redirects\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv4.conf.all.secure_redirects\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv4.conf.all.secure_redirects.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_secure_redirects

- name: Comment out any occurrences of net.ipv4.conf.all.secure_redirects from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv4.conf.all.secure_redirects
    replace: '#net.ipv4.conf.all.secure_redirects'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_secure_redirects
- name: XCCDF Value sysctl_net_ipv4_conf_all_secure_redirects_value # promote to variable
  set_fact:
    sysctl_net_ipv4_conf_all_secure_redirects_value: !!str 0
  tags:
    - always

- name: Ensure sysctl net.ipv4.conf.all.secure_redirects is set
  sysctl:
    name: net.ipv4.conf.all.secure_redirects
    value: '{{ sysctl_net_ipv4_conf_all_secure_redirects_value }}'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_secure_redirects

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv4.conf.all.secure_redirects%3D0%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_all_secure_redirects.conf
        overwrite: true

Rule   Disable Kernel Parameter for Accepting ICMP Redirects by Default on IPv4 Interfaces   [ref]

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.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_default_accept_redirects
Identifiers and References

References:  BP28(R22), 1, 11, 12, 13, 14, 15, 16, 18, 2, 3, 4, 6, 7, 8, 9, 5.10.1.1, APO01.06, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.06, 3.1.20, CCI-000366, CCI-001551, 4.2.3.4, 4.3.3.4, 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.4.3.3, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, 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.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-7(a), CM-7(b), CM-6(a), SC-7(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv4.conf.default.accept_redirects from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv4.conf.default.accept_redirects.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv4.conf.default.accept_redirects" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done
sysctl_net_ipv4_conf_default_accept_redirects_value='0'


#
# Set runtime for net.ipv4.conf.default.accept_redirects
#
/sbin/sysctl -q -n -w net.ipv4.conf.default.accept_redirects="$sysctl_net_ipv4_conf_default_accept_redirects_value"

#
# If net.ipv4.conf.default.accept_redirects present in /etc/sysctl.conf, change value to appropriate value
#	else, add "net.ipv4.conf.default.accept_redirects = value" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv4.conf.default.accept_redirects")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_accept_redirects_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 -i -e "^net.ipv4.conf.default.accept_redirects\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv4.conf.default.accept_redirects\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv4.conf.default.accept_redirects.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CJIS-5.10.1.1
    - 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

- name: Comment out any occurrences of net.ipv4.conf.default.accept_redirects from
    /etc/sysctl.d/*.conf files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv4.conf.default.accept_redirects
    replace: '#net.ipv4.conf.default.accept_redirects'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CJIS-5.10.1.1
    - 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
- 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:
    - CJIS-5.10.1.1
    - 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

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv4.conf.default.accept_redirects%3D0%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_default_accept_redirects.conf
        overwrite: true

Rule   Disable Kernel Parameter for Accepting Source-Routed Packets on IPv4 Interfaces by Default   [ref]

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.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_default_accept_source_route
Identifiers and References

References:  BP28(R22), 1, 11, 12, 13, 14, 15, 16, 18, 2, 3, 4, 6, 7, 8, 9, 5.10.1.1, APO01.06, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.06, 3.1.20, CCI-000366, CCI-001551, 4.2.3.4, 4.3.3.4, 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.4.3.3, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, 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.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-007-3 R4, CIP-007-3 R4.1, CIP-007-3 R4.2, CIP-007-3 R5.1, CM-7(a), CM-7(b), SC-5, SC-7(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv4.conf.default.accept_source_route from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv4.conf.default.accept_source_route.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv4.conf.default.accept_source_route" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done
sysctl_net_ipv4_conf_default_accept_source_route_value='0'


#
# Set runtime for net.ipv4.conf.default.accept_source_route
#
/sbin/sysctl -q -n -w net.ipv4.conf.default.accept_source_route="$sysctl_net_ipv4_conf_default_accept_source_route_value"

#
# If net.ipv4.conf.default.accept_source_route present in /etc/sysctl.conf, change value to appropriate value
#	else, add "net.ipv4.conf.default.accept_source_route = value" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv4.conf.default.accept_source_route")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_accept_source_route_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 -i -e "^net.ipv4.conf.default.accept_source_route\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv4.conf.default.accept_source_route\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv4.conf.default.accept_source_route.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CJIS-5.10.1.1
    - 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

- name: Comment out any occurrences of net.ipv4.conf.default.accept_source_route from
    /etc/sysctl.d/*.conf files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv4.conf.default.accept_source_route
    replace: '#net.ipv4.conf.default.accept_source_route'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CJIS-5.10.1.1
    - 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
- 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:
    - CJIS-5.10.1.1
    - 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

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv4.conf.default.accept_source_route%3D0%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_default_accept_source_route.conf
        overwrite: true

Rule   Enable Kernel Paremeter to Log Martian Packets on all IPv4 Interfaces by Default   [ref]

To set the runtime status of the net.ipv4.conf.default.log_martians kernel parameter, run the following command:
$ sudo sysctl -w net.ipv4.conf.default.log_martians=1
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.log_martians = 1
Rationale:
The presence of "martian" packets (which have impossible addresses) as well as spoofed packets, source-routed packets, and redirects could be a sign of nefarious network activity. Logging these packets enables this activity to be detected.
Severity: 
unknown
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_default_log_martians
Identifiers and References

References:  1, 11, 12, 13, 14, 15, 16, 2, 3, 7, 8, 9, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.04, DSS03.05, DSS05.02, DSS05.03, DSS05.05, DSS05.07, DSS06.06, 3.1.20, CCI-000126, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, 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.2, SR 7.1, SR 7.2, SR 7.6, A.11.2.6, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, 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.17.2.1, A.6.2.1, A.6.2.2, A.9.1.2, CM-7(a), CM-7(b), SC-5(3)(a), DE.CM-1, PR.AC-3, PR.DS-4, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv4.conf.default.log_martians from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv4.conf.default.log_martians.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv4.conf.default.log_martians" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done
sysctl_net_ipv4_conf_default_log_martians_value='1'


#
# Set runtime for net.ipv4.conf.default.log_martians
#
/sbin/sysctl -q -n -w net.ipv4.conf.default.log_martians="$sysctl_net_ipv4_conf_default_log_martians_value"

#
# If net.ipv4.conf.default.log_martians present in /etc/sysctl.conf, change value to appropriate value
#	else, add "net.ipv4.conf.default.log_martians = value" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv4.conf.default.log_martians")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_log_martians_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 -i -e "^net.ipv4.conf.default.log_martians\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv4.conf.default.log_martians\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv4.conf.default.log_martians.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-SC-5(3)(a)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - reboot_required
    - sysctl_net_ipv4_conf_default_log_martians
    - unknown_severity

- name: Comment out any occurrences of net.ipv4.conf.default.log_martians from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv4.conf.default.log_martians
    replace: '#net.ipv4.conf.default.log_martians'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-SC-5(3)(a)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - reboot_required
    - sysctl_net_ipv4_conf_default_log_martians
    - unknown_severity
- name: XCCDF Value sysctl_net_ipv4_conf_default_log_martians_value # promote to variable
  set_fact:
    sysctl_net_ipv4_conf_default_log_martians_value: !!str 1
  tags:
    - always

- name: Ensure sysctl net.ipv4.conf.default.log_martians is set
  sysctl:
    name: net.ipv4.conf.default.log_martians
    value: '{{ sysctl_net_ipv4_conf_default_log_martians_value }}'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.20
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - NIST-800-53-SC-5(3)(a)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - reboot_required
    - sysctl_net_ipv4_conf_default_log_martians
    - unknown_severity

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv4.conf.default.log_martians%3D1%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_default_log_martians.conf
        overwrite: true

Rule   Enable Kernel Parameter to Use Reverse Path Filtering on all IPv4 Interfaces by Default   [ref]

To set the runtime status of the net.ipv4.conf.default.rp_filter kernel parameter, run the following command:
$ sudo sysctl -w net.ipv4.conf.default.rp_filter=1
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.rp_filter = 1
Rationale:
Enabling reverse path filtering drops packets with source addresses that should not have been able to be received on the interface they were received on. It should not be used on systems which are routers for complicated networks, but is helpful for end hosts and routers serving small networks.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_default_rp_filter
Identifiers and References

References:  BP28(R22), 1, 12, 13, 14, 15, 16, 18, 2, 4, 6, 7, 8, 9, APO01.06, APO13.01, BAI04.04, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.07, DSS06.02, 3.1.20, CCI-000366, 4.2.3.4, 4.3.3.4, 4.4.3.3, 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.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-7(a), CM-7(b), CM-6(a), SC-7(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.PT-4, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv4.conf.default.rp_filter from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv4.conf.default.rp_filter.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv4.conf.default.rp_filter" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done
sysctl_net_ipv4_conf_default_rp_filter_value='1'


#
# Set runtime for net.ipv4.conf.default.rp_filter
#
/sbin/sysctl -q -n -w net.ipv4.conf.default.rp_filter="$sysctl_net_ipv4_conf_default_rp_filter_value"

#
# If net.ipv4.conf.default.rp_filter present in /etc/sysctl.conf, change value to appropriate value
#	else, add "net.ipv4.conf.default.rp_filter = value" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv4.conf.default.rp_filter")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_rp_filter_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 -i -e "^net.ipv4.conf.default.rp_filter\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv4.conf.default.rp_filter\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv4.conf.default.rp_filter.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_rp_filter

- name: Comment out any occurrences of net.ipv4.conf.default.rp_filter from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv4.conf.default.rp_filter
    replace: '#net.ipv4.conf.default.rp_filter'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_rp_filter
- name: XCCDF Value sysctl_net_ipv4_conf_default_rp_filter_value # promote to variable
  set_fact:
    sysctl_net_ipv4_conf_default_rp_filter_value: !!str 1
  tags:
    - always

- name: Ensure sysctl net.ipv4.conf.default.rp_filter is set
  sysctl:
    name: net.ipv4.conf.default.rp_filter
    value: '{{ sysctl_net_ipv4_conf_default_rp_filter_value }}'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_rp_filter

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv4.conf.default.rp_filter%3D1%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_default_rp_filter.conf
        overwrite: true

Rule   Configure Kernel Parameter for Accepting Secure Redirects By Default   [ref]

To set the runtime status of the net.ipv4.conf.default.secure_redirects kernel parameter, run the following command:
$ sudo sysctl -w net.ipv4.conf.default.secure_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.secure_redirects = 0
Rationale:
Accepting "secure" ICMP redirects (from those gateways listed as default gateways) has few legitimate uses. It should be disabled unless it is absolutely required.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_default_secure_redirects
Identifiers and References

References:  BP28(R22), 1, 11, 12, 13, 14, 15, 16, 18, 2, 3, 4, 6, 7, 8, 9, APO01.06, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.06, 3.1.20, CCI-001551, 4.2.3.4, 4.3.3.4, 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.4.3.3, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, 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.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-007-3 R4, CIP-007-3 R4.1, CIP-007-3 R4.2, CIP-007-3 R5.1, CM-7(a), CM-7(b), SC-5, SC-7(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv4.conf.default.secure_redirects from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv4.conf.default.secure_redirects.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv4.conf.default.secure_redirects" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done
sysctl_net_ipv4_conf_default_secure_redirects_value='0'


#
# Set runtime for net.ipv4.conf.default.secure_redirects
#
/sbin/sysctl -q -n -w net.ipv4.conf.default.secure_redirects="$sysctl_net_ipv4_conf_default_secure_redirects_value"

#
# If net.ipv4.conf.default.secure_redirects present in /etc/sysctl.conf, change value to appropriate value
#	else, add "net.ipv4.conf.default.secure_redirects = value" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv4.conf.default.secure_redirects")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_conf_default_secure_redirects_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 -i -e "^net.ipv4.conf.default.secure_redirects\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv4.conf.default.secure_redirects\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv4.conf.default.secure_redirects.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_secure_redirects

- name: Comment out any occurrences of net.ipv4.conf.default.secure_redirects from
    /etc/sysctl.d/*.conf files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv4.conf.default.secure_redirects
    replace: '#net.ipv4.conf.default.secure_redirects'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_secure_redirects
- name: XCCDF Value sysctl_net_ipv4_conf_default_secure_redirects_value # promote to variable
  set_fact:
    sysctl_net_ipv4_conf_default_secure_redirects_value: !!str 0
  tags:
    - always

- name: Ensure sysctl net.ipv4.conf.default.secure_redirects is set
  sysctl:
    name: net.ipv4.conf.default.secure_redirects
    value: '{{ sysctl_net_ipv4_conf_default_secure_redirects_value }}'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_secure_redirects

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv4.conf.default.secure_redirects%3D0%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_default_secure_redirects.conf
        overwrite: true

Rule   Enable Kernel Parameter to Ignore ICMP Broadcast Echo Requests on IPv4 Interfaces   [ref]

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.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_icmp_echo_ignore_broadcasts
Identifiers and References

References:  1, 11, 12, 13, 14, 15, 16, 18, 2, 3, 4, 6, 7, 8, 9, 5.10.1.1, APO01.06, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.06, 3.1.20, CCI-000366, 4.2.3.4, 4.3.3.4, 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.4.3.3, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, 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.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-007-3 R4, CIP-007-3 R4.1, CIP-007-3 R4.2, CIP-007-3 R5.1, CM-7(a), CM-7(b), SC-5, DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv4.icmp_echo_ignore_broadcasts from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv4.icmp_echo_ignore_broadcasts.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv4.icmp_echo_ignore_broadcasts" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done
sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value='1'


#
# Set runtime for net.ipv4.icmp_echo_ignore_broadcasts
#
/sbin/sysctl -q -n -w net.ipv4.icmp_echo_ignore_broadcasts="$sysctl_net_ipv4_icmp_echo_ignore_broadcasts_value"

#
# If net.ipv4.icmp_echo_ignore_broadcasts present in /etc/sysctl.conf, change value to appropriate value
#	else, add "net.ipv4.icmp_echo_ignore_broadcasts = value" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv4.icmp_echo_ignore_broadcasts")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_icmp_echo_ignore_broadcasts_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 -i -e "^net.ipv4.icmp_echo_ignore_broadcasts\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv4.icmp_echo_ignore_broadcasts\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CJIS-5.10.1.1
    - 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

- name: Comment out any occurrences of net.ipv4.icmp_echo_ignore_broadcasts from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv4.icmp_echo_ignore_broadcasts
    replace: '#net.ipv4.icmp_echo_ignore_broadcasts'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CJIS-5.10.1.1
    - 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
- 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:
    - CJIS-5.10.1.1
    - 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

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv4.icmp_echo_ignore_broadcasts%3D1%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv4_icmp_echo_ignore_broadcasts.conf
        overwrite: true

Rule   Enable Kernel Parameter to Ignore Bogus ICMP Error Responses on IPv4 Interfaces   [ref]

To set the runtime status of the net.ipv4.icmp_ignore_bogus_error_responses kernel parameter, run the following command:
$ sudo sysctl -w net.ipv4.icmp_ignore_bogus_error_responses=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_ignore_bogus_error_responses = 1
Rationale:
Ignoring bogus ICMP error responses reduces log size, although some activity would not be logged.
Severity: 
unknown
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_icmp_ignore_bogus_error_responses
Identifiers and References

References:  BP28(R22), 1, 11, 12, 13, 14, 15, 16, 2, 3, 7, 8, 9, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS03.05, DSS05.02, DSS05.05, DSS05.07, DSS06.06, 3.1.20, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 6.2, SR 7.1, SR 7.2, SR 7.6, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.9.1.2, CIP-007-3 R4, CIP-007-3 R4.1, CIP-007-3 R4.2, CIP-007-3 R5.1, CM-7(a), CM-7(b), SC-5, DE.CM-1, PR.DS-4, PR.IP-1, PR.PT-3, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv4.icmp_ignore_bogus_error_responses from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv4.icmp_ignore_bogus_error_responses.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv4.icmp_ignore_bogus_error_responses" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done
sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value='1'


#
# Set runtime for net.ipv4.icmp_ignore_bogus_error_responses
#
/sbin/sysctl -q -n -w net.ipv4.icmp_ignore_bogus_error_responses="$sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value"

#
# If net.ipv4.icmp_ignore_bogus_error_responses present in /etc/sysctl.conf, change value to appropriate value
#	else, add "net.ipv4.icmp_ignore_bogus_error_responses = value" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv4.icmp_ignore_bogus_error_responses")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_icmp_ignore_bogus_error_responses_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 -i -e "^net.ipv4.icmp_ignore_bogus_error_responses\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv4.icmp_ignore_bogus_error_responses\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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
    - reboot_required
    - sysctl_net_ipv4_icmp_ignore_bogus_error_responses
    - unknown_severity

- name: Comment out any occurrences of net.ipv4.icmp_ignore_bogus_error_responses
    from /etc/sysctl.d/*.conf files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv4.icmp_ignore_bogus_error_responses
    replace: '#net.ipv4.icmp_ignore_bogus_error_responses'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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
    - reboot_required
    - sysctl_net_ipv4_icmp_ignore_bogus_error_responses
    - unknown_severity
- name: XCCDF Value sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value # promote to variable
  set_fact:
    sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value: !!str 1
  tags:
    - always

- name: Ensure sysctl net.ipv4.icmp_ignore_bogus_error_responses is set
  sysctl:
    name: net.ipv4.icmp_ignore_bogus_error_responses
    value: '{{ sysctl_net_ipv4_icmp_ignore_bogus_error_responses_value }}'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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
    - reboot_required
    - sysctl_net_ipv4_icmp_ignore_bogus_error_responses
    - unknown_severity

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv4.icmp_ignore_bogus_error_responses%3D1%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv4_icmp_ignore_bogus_error_responses.conf
        overwrite: true

Rule   Enable Kernel Parameter to Use TCP Syncookies on IPv4 Interfaces   [ref]

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.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_tcp_syncookies
Identifiers and References

References:  BP28(R22), 1, 12, 13, 14, 15, 16, 18, 2, 4, 6, 7, 8, 9, 5.10.1.1, APO01.06, APO13.01, BAI04.04, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.07, DSS06.02, 3.1.20, CCI-000366, CCI-001095, 4.2.3.4, 4.3.3.4, 4.4.3.3, 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.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-7(a), CM-7(b), SC-5(1), SC-5(2), SC-5(3)(a), CM-6(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.PT-4, SRG-OS-000480-GPOS-00227, SRG-OS-000420-GPOS-00186, SRG-OS-000142-GPOS-00071


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv4.tcp_syncookies from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv4.tcp_syncookies.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv4.tcp_syncookies" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done
sysctl_net_ipv4_tcp_syncookies_value='1'


#
# Set runtime for net.ipv4.tcp_syncookies
#
/sbin/sysctl -q -n -w net.ipv4.tcp_syncookies="$sysctl_net_ipv4_tcp_syncookies_value"

#
# If net.ipv4.tcp_syncookies present in /etc/sysctl.conf, change value to appropriate value
#	else, add "net.ipv4.tcp_syncookies = value" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv4.tcp_syncookies")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "$sysctl_net_ipv4_tcp_syncookies_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 -i -e "^net.ipv4.tcp_syncookies\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv4.tcp_syncookies\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv4.tcp_syncookies.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CJIS-5.10.1.1
    - 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

- name: Comment out any occurrences of net.ipv4.tcp_syncookies from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv4.tcp_syncookies
    replace: '#net.ipv4.tcp_syncookies'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CJIS-5.10.1.1
    - 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
- 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:
    - CJIS-5.10.1.1
    - 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

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv4.tcp_syncookies%3D1%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv4_tcp_syncookies.conf
        overwrite: true
Group   Network Parameters for Hosts Only   Group contains 3 rules
[ref]   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.

Rule   Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces   [ref]

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.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_all_send_redirects
Identifiers and References

References:  BP28(R22), 1, 11, 12, 13, 14, 15, 16, 18, 2, 3, 4, 6, 7, 8, 9, 5.10.1.1, APO01.06, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.06, 3.1.20, CCI-000366, 4.2.3.4, 4.3.3.4, 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.4.3.3, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, 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.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-007-3 R4, CIP-007-3 R4.1, CIP-007-3 R4.2, CIP-007-3 R5.1, CM-7(a), CM-7(b), SC-5, CM-6(a), SC-7(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv4.conf.all.send_redirects from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv4.conf.all.send_redirects.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv4.conf.all.send_redirects" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done

#
# Set runtime for net.ipv4.conf.all.send_redirects
#
/sbin/sysctl -q -n -w net.ipv4.conf.all.send_redirects="0"

#
# If net.ipv4.conf.all.send_redirects present in /etc/sysctl.conf, change value to "0"
#	else, add "net.ipv4.conf.all.send_redirects = 0" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv4.conf.all.send_redirects")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "0"

# 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 -i -e "^net.ipv4.conf.all.send_redirects\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv4.conf.all.send_redirects\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv4.conf.all.send_redirects.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CJIS-5.10.1.1
    - 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

- name: Comment out any occurrences of net.ipv4.conf.all.send_redirects from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv4.conf.all.send_redirects
    replace: '#net.ipv4.conf.all.send_redirects'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CJIS-5.10.1.1
    - 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

- 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:
    - CJIS-5.10.1.1
    - 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

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv4.conf.all.send_redirects%3D0%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_all_send_redirects.conf
        overwrite: true

Rule   Disable Kernel Parameter for Sending ICMP Redirects on all IPv4 Interfaces by Default   [ref]

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.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_conf_default_send_redirects
Identifiers and References

References:  BP28(R22), 1, 11, 12, 13, 14, 15, 16, 18, 2, 3, 4, 6, 7, 8, 9, 5.10.1.1, APO01.06, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS01.05, DSS03.01, DSS03.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.06, 3.1.20, CCI-000366, 4.2.3.4, 4.3.3.4, 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.4.3.3, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, 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.2, SR 7.1, SR 7.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.17.2.1, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-007-3 R4, CIP-007-3 R4.1, CIP-007-3 R4.2, CIP-007-3 R5.1, CM-7(a), CM-7(b), SC-5, CM-6(a), SC-7(a), DE.AE-1, DE.CM-1, ID.AM-3, PR.AC-5, PR.DS-4, PR.DS-5, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv4.conf.default.send_redirects from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv4.conf.default.send_redirects.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv4.conf.default.send_redirects" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done

#
# Set runtime for net.ipv4.conf.default.send_redirects
#
/sbin/sysctl -q -n -w net.ipv4.conf.default.send_redirects="0"

#
# If net.ipv4.conf.default.send_redirects present in /etc/sysctl.conf, change value to "0"
#	else, add "net.ipv4.conf.default.send_redirects = 0" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv4.conf.default.send_redirects")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "0"

# 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 -i -e "^net.ipv4.conf.default.send_redirects\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv4.conf.default.send_redirects\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv4.conf.default.send_redirects.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CJIS-5.10.1.1
    - 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

- name: Comment out any occurrences of net.ipv4.conf.default.send_redirects from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv4.conf.default.send_redirects
    replace: '#net.ipv4.conf.default.send_redirects'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CJIS-5.10.1.1
    - 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

- 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:
    - CJIS-5.10.1.1
    - 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

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.ipv4.conf.default.send_redirects%3D0%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_ipv4_conf_default_send_redirects.conf
        overwrite: true

Rule   Disable Kernel Parameter for IP Forwarding on IPv4 Interfaces   [ref]

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.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_ipv4_ip_forward
Identifiers and References

References:  BP28(R22), 1, 11, 12, 13, 14, 15, 16, 2, 3, 7, 8, 9, APO13.01, BAI04.04, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS03.05, DSS05.02, DSS05.05, DSS05.07, DSS06.06, 3.1.20, CCI-000366, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, 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.2, SR 7.1, SR 7.2, SR 7.6, A.12.1.2, A.12.1.3, A.12.5.1, A.12.6.2, 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.17.2.1, A.9.1.2, CIP-007-3 R4, CIP-007-3 R4.1, CIP-007-3 R4.2, CIP-007-3 R5.1, CM-7(a), CM-7(b), SC-5, CM-6(a), SC-7(a), DE.CM-1, PR.DS-4, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.ipv4.ip_forward from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.ipv4.ip_forward.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.ipv4.ip_forward" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done

#
# Set runtime for net.ipv4.ip_forward
#
/sbin/sysctl -q -n -w net.ipv4.ip_forward="0"

#
# If net.ipv4.ip_forward present in /etc/sysctl.conf, change value to "0"
#	else, add "net.ipv4.ip_forward = 0" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.ipv4.ip_forward")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "0"

# 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 -i -e "^net.ipv4.ip_forward\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.ipv4.ip_forward\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.ipv4.ip_forward.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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

- name: Comment out any occurrences of net.ipv4.ip_forward from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.ipv4.ip_forward
    replace: '#net.ipv4.ip_forward'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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

- 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:
    - 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
Group   Uncommon Network Protocols   Group contains 3 rules
[ref]   The system includes support for several network protocols which are not commonly used. Although security vulnerabilities in kernel networking code are not frequently discovered, the consequences can be dramatic. Ensuring uncommon network protocols are disabled reduces the system's risk to attacks targeted at its implementation of those protocols.
Warning:  Although these protocols are not commonly used, avoid disruption in your network environment by ensuring they are not needed prior to disabling them.

Rule   Disable CAN Support   [ref]

The Controller Area Network (CAN) is a serial communications protocol which was initially developed for automotive and is now also used in marine, industrial, and medical applications. To configure the system to prevent the can kernel module from being loaded, add the following line to a file in the directory /etc/modprobe.d:
install can /bin/true
Rationale:
Disabling CAN protects the system against exploitation of any flaws in its implementation.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_kernel_module_can_disabled
Identifiers and References

References:  CCI-000381, AC-18, FMT_SMF_EXT.1, SRG-OS-000095-GPOS-00049


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if LC_ALL=C grep -q -m 1 "^install can" /etc/modprobe.d/can.conf ; then
	
	sed -i 's#^install can.*#install can /bin/true#g' /etc/modprobe.d/can.conf
else
	echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/can.conf
	echo "install can /bin/true" >> /etc/modprobe.d/can.conf
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: Ensure kernel module 'can' is disabled
  lineinfile:
    create: true
    dest: /etc/modprobe.d/can.conf
    regexp: can
    line: install can /bin/true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AC-18
    - disable_strategy
    - kernel_module_can_disabled
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,install%20can%20/bin/true%0A
        mode: 0644
        path: /etc/modprobe.d/75-kernel_module_can_disabled.conf
        overwrite: true

Rule   Disable SCTP Support   [ref]

The Stream Control Transmission Protocol (SCTP) is a transport layer protocol, designed to support the idea of message-oriented communication, with several streams of messages within one connection. To configure the system to prevent the sctp kernel module from being loaded, add the following line to a file in the directory /etc/modprobe.d:
install sctp /bin/true
Rationale:
Disabling SCTP protects the system against exploitation of any flaws in its implementation.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_kernel_module_sctp_disabled
Identifiers and References

References:  11, 14, 3, 9, 5.10.1, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, 3.4.6, CCI-000381, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3, SRG-OS-000095-GPOS-00049


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if LC_ALL=C grep -q -m 1 "^install sctp" /etc/modprobe.d/sctp.conf ; then
	
	sed -i 's#^install sctp.*#install sctp /bin/true#g' /etc/modprobe.d/sctp.conf
else
	echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/sctp.conf
	echo "install sctp /bin/true" >> /etc/modprobe.d/sctp.conf
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: Ensure kernel module 'sctp' is disabled
  lineinfile:
    create: true
    dest: /etc/modprobe.d/sctp.conf
    regexp: sctp
    line: install sctp /bin/true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CJIS-5.10.1
    - NIST-800-171-3.4.6
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - disable_strategy
    - kernel_module_sctp_disabled
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,install%20sctp%20/bin/true%0A
        mode: 0644
        path: /etc/modprobe.d/75-kernel_module_sctp_disabled.conf
        overwrite: true

Rule   Disable TIPC Support   [ref]

The Transparent Inter-Process Communication (TIPC) protocol is designed to provide communications between nodes in a cluster. To configure the system to prevent the tipc kernel module from being loaded, add the following line to a file in the directory /etc/modprobe.d:
install tipc /bin/true
Warning:  This configuration baseline was created to deploy the base operating system for general purpose workloads. When the operating system is configured for certain purposes, such as a node in High Performance Computing cluster, it is expected that the tipc kernel module will be loaded.
Rationale:
Disabling TIPC protects the system against exploitation of any flaws in its implementation.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_kernel_module_tipc_disabled
Identifiers and References

References:  11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, CCI-000381, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3, FMT_SMF_EXT.1, SRG-OS-000095-GPOS-00049


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if LC_ALL=C grep -q -m 1 "^install tipc" /etc/modprobe.d/tipc.conf ; then
	
	sed -i 's#^install tipc.*#install tipc /bin/true#g' /etc/modprobe.d/tipc.conf
else
	echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/tipc.conf
	echo "install tipc /bin/true" >> /etc/modprobe.d/tipc.conf
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: Ensure kernel module 'tipc' is disabled
  lineinfile:
    create: true
    dest: /etc/modprobe.d/tipc.conf
    regexp: tipc
    line: install tipc /bin/true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - disable_strategy
    - kernel_module_tipc_disabled
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,install%20tipc%20/bin/true%0A
        mode: 0644
        path: /etc/modprobe.d/75-kernel_module_tipc_disabled.conf
        overwrite: true
Group   Wireless Networking   Group contains 1 group and 1 rule
[ref]   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.
Group   Disable Wireless Through Software Configuration   Group contains 1 rule
[ref]   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.

Rule   Disable Bluetooth Kernel Module   [ref]

The kernel's module loading system can be configured to prevent loading of the Bluetooth module. Add the following to the appropriate /etc/modprobe.d configuration file to prevent the loading of the Bluetooth module:
install bluetooth /bin/true
Rationale:
If Bluetooth functionality must be disabled, preventing the kernel from loading the kernel module provides an additional safeguard against its activation.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_kernel_module_bluetooth_disabled
Identifiers and References

References:  11, 12, 14, 15, 3, 8, 9, 5.13.1.3, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.04, DSS05.02, DSS05.03, DSS05.05, DSS06.06, 3.1.16, CCI-000085, CCI-001551, CCI-001443, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, 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.5.1, A.12.6.2, 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.6.2.1, A.6.2.2, A.9.1.2, AC-18(a), AC-18(3), CM-7(a), CM-7(b), CM-6(a), MP-7, PR.AC-3, PR.IP-1, PR.PT-3, PR.PT-4, SRG-OS-000095-GPOS-00049, SRG-OS-000300-GPOS-00118


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if LC_ALL=C grep -q -m 1 "^install bluetooth" /etc/modprobe.d/bluetooth.conf ; then
	
	sed -i 's#^install bluetooth.*#install bluetooth /bin/true#g' /etc/modprobe.d/bluetooth.conf
else
	echo -e "\n# Disable per security requirements" >> /etc/modprobe.d/bluetooth.conf
	echo "install bluetooth /bin/true" >> /etc/modprobe.d/bluetooth.conf
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: Ensure kernel module 'bluetooth' is disabled
  lineinfile:
    create: true
    dest: /etc/modprobe.d/bluetooth.conf
    regexp: bluetooth
    line: install bluetooth /bin/true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CJIS-5.13.1.3
    - NIST-800-171-3.1.16
    - NIST-800-53-AC-18(3)
    - NIST-800-53-AC-18(a)
    - 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_bluetooth_disabled
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,install%20bluetooth%20/bin/true%0A
        mode: 0644
        path: /etc/modprobe.d/75-kernel_module_bluetooth_disabled.conf
        overwrite: true
Group   File Permissions and Masks   Group contains 5 groups and 36 rules
[ref]   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 AlmaLinux 9 installations:
$ mount -t xfs | awk '{print $3}'
For any systems that use a different local filesystem type, modify this command as appropriate.
Group   Verify Permissions on Important Files and Directories   Group contains 2 rules
[ref]   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.
Group   Restrict Partition Mount Options   Group contains 21 rules
[ref]   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.

Rule   Add nodev Option to /boot   [ref]

The nodev mount option can be used to prevent device files from being created in /boot. Legitimate character and block devices should exist only in the /dev directory on the root partition or within chroot jails built for system services. Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of /boot.
Rationale:
The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_boot_nodev
Identifiers and References

References:  CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154


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

function perform_remediation {
    
        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/boot")"

    grep "$mount_point_match_regexp" -q /etc/fstab \
        || { echo "The mount point '/boot' is not even in /etc/fstab, so we can't set up mount options" >&2; 
                echo "Not remediating, because there is no record of /boot in /etc/fstab" >&2; return 1; }
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /boot)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|nodev)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo " /boot  defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nodev")" -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,nodev|" /etc/fstab
    fi

    if mkdir -p "/boot"; then
        if mountpoint -q "/boot"; then
            mount -o remount --target "/boot"
        else
            mount --target "/boot"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- name: Check information associated to mountpoint
  command: findmnt --fstab '/boot'
  register: device_name
  failed_when: device_name.rc > 1
  changed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_boot_nodev
    - 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:
    - 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_boot_nodev
    - no_reboot_needed

- name: If /boot not mounted, craft mount_info manually
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - - target
      - source
      - fstype
      - options
    - - /boot
      - ''
      - ''
      - defaults
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ("--fstab" | length == 0)
    - (device_name.stdout | length == 0)
  tags:
    - 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_boot_nodev
    - no_reboot_needed

- name: Make sure nodev option is part of the to /boot options
  set_fact:
    mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev''
      }) }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - mount_info is defined and "nodev" not in mount_info.options
  tags:
    - 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_boot_nodev
    - no_reboot_needed

- name: Ensure /boot is mounted with nodev option
  mount:
    path: /boot
    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:
    - 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_boot_nodev
    - no_reboot_needed

Complexity:low
Disruption:high
Strategy:enable

part /boot --mountoptions="nodev"

Rule   Add nosuid Option to /boot   [ref]

The nosuid mount option can be used to prevent execution of setuid programs in /boot. The SUID and SGID permissions should not be required on the boot partition. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of /boot.
Rationale:
The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from boot partitions.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_boot_nosuid
Identifiers and References

References:  BP28(R12), CCI-000366, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154, SRG-OS-000480-GPOS-00227


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

function perform_remediation {
    
        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/boot")"

    grep "$mount_point_match_regexp" -q /etc/fstab \
        || { echo "The mount point '/boot' is not even in /etc/fstab, so we can't set up mount options" >&2; 
                echo "Not remediating, because there is no record of /boot in /etc/fstab" >&2; return 1; }
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /boot)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|nosuid)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo " /boot  defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nosuid")" -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,nosuid|" /etc/fstab
    fi

    if mkdir -p "/boot"; then
        if mountpoint -q "/boot"; then
            mount -o remount --target "/boot"
        else
            mount --target "/boot"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- name: Check information associated to mountpoint
  command: findmnt --fstab '/boot'
  register: device_name
  failed_when: device_name.rc > 1
  changed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_boot_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:
    - 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_boot_nosuid
    - no_reboot_needed

- name: If /boot not mounted, craft mount_info manually
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - - target
      - source
      - fstype
      - options
    - - /boot
      - ''
      - ''
      - defaults
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ("--fstab" | length == 0)
    - (device_name.stdout | length == 0)
  tags:
    - 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_boot_nosuid
    - no_reboot_needed

- name: Make sure nosuid option is part of the to /boot 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:
    - 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_boot_nosuid
    - no_reboot_needed

- name: Ensure /boot is mounted with nosuid option
  mount:
    path: /boot
    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:
    - 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_boot_nosuid
    - no_reboot_needed

Complexity:low
Disruption:high
Strategy:enable

part /boot --mountoptions="nosuid"

Rule   Add nodev Option to /dev/shm   [ref]

The nodev mount option can be used to prevent creation of device files in /dev/shm. Legitimate character and block devices should not exist within temporary directories like /dev/shm. Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of /dev/shm.
Rationale:
The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails.
Severity: 
low
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_dev_shm_nodev
Identifiers and References

References:  11, 13, 14, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS05.06, DSS06.06, CCI-001764, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.11.2.9, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.8.2.1, A.8.2.2, A.8.2.3, A.8.3.1, A.8.3.3, A.9.1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154


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

function perform_remediation {
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /dev/shm)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|nodev)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo "tmpfs /dev/shm tmpfs defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nodev")" -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,nodev|" /etc/fstab
    fi

    if mkdir -p "/dev/shm"; then
        if mountpoint -q "/dev/shm"; then
            mount -o remount --target "/dev/shm"
        else
            mount --target "/dev/shm"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- name: Check information associated to mountpoint
  command: findmnt  '/dev/shm'
  register: device_name
  failed_when: device_name.rc > 1
  changed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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
    - low_severity
    - mount_option_dev_shm_nodev
    - 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:
    - 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
    - low_severity
    - mount_option_dev_shm_nodev
    - no_reboot_needed

- name: If /dev/shm not mounted, craft mount_info manually
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - - target
      - source
      - fstype
      - options
    - - /dev/shm
      - tmpfs
      - tmpfs
      - defaults
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ("" | length == 0)
    - (device_name.stdout | length == 0)
  tags:
    - 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
    - low_severity
    - mount_option_dev_shm_nodev
    - no_reboot_needed

- name: Make sure nodev option is part of the to /dev/shm options
  set_fact:
    mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev''
      }) }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - mount_info is defined and "nodev" not in mount_info.options
  tags:
    - 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
    - low_severity
    - mount_option_dev_shm_nodev
    - no_reboot_needed

- name: Ensure /dev/shm is mounted with nodev option
  mount:
    path: /dev/shm
    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 (""
      | length == 0)
  tags:
    - 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
    - low_severity
    - mount_option_dev_shm_nodev
    - no_reboot_needed

Rule   Add noexec Option to /dev/shm   [ref]

The noexec mount option can be used to prevent binaries from being executed out of /dev/shm. It can be dangerous to allow the execution of binaries from world-writable temporary storage directories such as /dev/shm. Add the noexec option to the fourth column of /etc/fstab for the line which controls mounting of /dev/shm.
Rationale:
Allowing users to execute binaries from world-writable directories such as /dev/shm can expose the system to potential compromise.
Severity: 
low
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_dev_shm_noexec
Identifiers and References

References:  11, 13, 14, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS05.06, DSS06.06, CCI-001764, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.11.2.9, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.8.2.1, A.8.2.2, A.8.2.3, A.8.3.1, A.8.3.3, A.9.1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154


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

function perform_remediation {
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /dev/shm)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|noexec)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo "tmpfs /dev/shm tmpfs defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "noexec")" -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,noexec|" /etc/fstab
    fi

    if mkdir -p "/dev/shm"; then
        if mountpoint -q "/dev/shm"; then
            mount -o remount --target "/dev/shm"
        else
            mount --target "/dev/shm"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- name: Check information associated to mountpoint
  command: findmnt  '/dev/shm'
  register: device_name
  failed_when: device_name.rc > 1
  changed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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
    - low_severity
    - mount_option_dev_shm_noexec
    - 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:
    - 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
    - low_severity
    - mount_option_dev_shm_noexec
    - no_reboot_needed

- name: If /dev/shm not mounted, craft mount_info manually
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - - target
      - source
      - fstype
      - options
    - - /dev/shm
      - tmpfs
      - tmpfs
      - defaults
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ("" | length == 0)
    - (device_name.stdout | length == 0)
  tags:
    - 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
    - low_severity
    - mount_option_dev_shm_noexec
    - no_reboot_needed

- name: Make sure noexec option is part of the to /dev/shm options
  set_fact:
    mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec''
      }) }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - mount_info is defined and "noexec" not in mount_info.options
  tags:
    - 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
    - low_severity
    - mount_option_dev_shm_noexec
    - no_reboot_needed

- name: Ensure /dev/shm is mounted with noexec option
  mount:
    path: /dev/shm
    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 (""
      | length == 0)
  tags:
    - 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
    - low_severity
    - mount_option_dev_shm_noexec
    - no_reboot_needed

Rule   Add nosuid Option to /dev/shm   [ref]

The nosuid mount option can be used to prevent execution of setuid programs in /dev/shm. The SUID and SGID permissions should not be required in these world-writable directories. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of /dev/shm.
Rationale:
The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from temporary storage partitions.
Severity: 
low
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_dev_shm_nosuid
Identifiers and References

References:  11, 13, 14, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS05.06, DSS06.06, CCI-001764, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.11.2.9, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.8.2.1, A.8.2.2, A.8.2.3, A.8.3.1, A.8.3.3, A.9.1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154


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

function perform_remediation {
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /dev/shm)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|nosuid)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo "tmpfs /dev/shm tmpfs defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nosuid")" -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,nosuid|" /etc/fstab
    fi

    if mkdir -p "/dev/shm"; then
        if mountpoint -q "/dev/shm"; then
            mount -o remount --target "/dev/shm"
        else
            mount --target "/dev/shm"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- name: Check information associated to mountpoint
  command: findmnt  '/dev/shm'
  register: device_name
  failed_when: device_name.rc > 1
  changed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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
    - low_severity
    - mount_option_dev_shm_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:
    - 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
    - low_severity
    - mount_option_dev_shm_nosuid
    - no_reboot_needed

- name: If /dev/shm not mounted, craft mount_info manually
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - - target
      - source
      - fstype
      - options
    - - /dev/shm
      - tmpfs
      - tmpfs
      - defaults
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ("" | length == 0)
    - (device_name.stdout | length == 0)
  tags:
    - 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
    - low_severity
    - mount_option_dev_shm_nosuid
    - no_reboot_needed

- name: Make sure nosuid option is part of the to /dev/shm 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:
    - 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
    - low_severity
    - mount_option_dev_shm_nosuid
    - no_reboot_needed

- name: Ensure /dev/shm is mounted with nosuid option
  mount:
    path: /dev/shm
    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 (""
      | length == 0)
  tags:
    - 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
    - low_severity
    - mount_option_dev_shm_nosuid
    - no_reboot_needed

Rule   Add nodev Option to /home   [ref]

The nodev mount option can be used to prevent device files from being created in /home. Legitimate character and block devices should exist only in the /dev directory on the root partition or within chroot jails built for system services. Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of /home.
Rationale:
The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails.
Severity: 
unknown
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_home_nodev
Identifiers and References

References:  BP28(R12), SRG-OS-000368-GPOS-00154


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

function perform_remediation {
    
        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/home")"

    grep "$mount_point_match_regexp" -q /etc/fstab \
        || { echo "The mount point '/home' is not even in /etc/fstab, so we can't set up mount options" >&2; 
                echo "Not remediating, because there is no record of /home in /etc/fstab" >&2; return 1; }
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /home)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|nodev)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo " /home  defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nodev")" -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,nodev|" /etc/fstab
    fi

    if mkdir -p "/home"; then
        if mountpoint -q "/home"; then
            mount -o remount --target "/home"
        else
            mount --target "/home"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- 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:
    - configure_strategy
    - high_disruption
    - low_complexity
    - mount_option_home_nodev
    - no_reboot_needed
    - unknown_severity

- 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:
    - configure_strategy
    - high_disruption
    - low_complexity
    - mount_option_home_nodev
    - no_reboot_needed
    - unknown_severity

- 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:
    - configure_strategy
    - high_disruption
    - low_complexity
    - mount_option_home_nodev
    - no_reboot_needed
    - unknown_severity

- name: Make sure nodev option is part of the to /home options
  set_fact:
    mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev''
      }) }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - mount_info is defined and "nodev" not in mount_info.options
  tags:
    - configure_strategy
    - high_disruption
    - low_complexity
    - mount_option_home_nodev
    - no_reboot_needed
    - unknown_severity

- name: Ensure /home is mounted with nodev 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:
    - configure_strategy
    - high_disruption
    - low_complexity
    - mount_option_home_nodev
    - no_reboot_needed
    - unknown_severity

Complexity:low
Disruption:high
Strategy:enable

part /home --mountoptions="nodev"

Rule   Add nosuid Option to /home   [ref]

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.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_home_nosuid
Identifiers and References

References:  BP28(R12), 11, 13, 14, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS05.06, DSS06.06, CCI-000366, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.11.2.9, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.8.2.1, A.8.2.2, A.8.2.3, A.8.3.1, A.8.3.3, A.9.1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154, SRG-OS-000480-GPOS-00227


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

function perform_remediation {
    
        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/home")"

    grep "$mount_point_match_regexp" -q /etc/fstab \
        || { echo "The mount point '/home' is not even in /etc/fstab, so we can't set up mount options" >&2; 
                echo "Not remediating, because there is no record of /home in /etc/fstab" >&2; return 1; }
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /home)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|nosuid)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo " /home  defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nosuid")" -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,nosuid|" /etc/fstab
    fi

    if mkdir -p "/home"; then
        if mountpoint -q "/home"; then
            mount -o remount --target "/home"
        else
            mount --target "/home"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- 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:
    - 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:
    - 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:
    - 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:
    - 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:
    - 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

Complexity:low
Disruption:high
Strategy:enable

part /home --mountoptions="nosuid"

Rule   Add nodev Option to Non-Root Local Partitions   [ref]

The nodev mount option prevents files from being interpreted as character or block devices. Legitimate character and block devices should exist only in the /dev directory on the root partition or within chroot jails built for system services. Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of any non-root local partitions.
Rationale:
The nodev mount option prevents files from being interpreted as character or block devices. The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails, for which it is not advised to set nodev on these filesystems.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_nodev_nonroot_local_partitions
Identifiers and References

References:  BP28(R12), 11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, CCI-000366, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-3, SRG-OS-000368-GPOS-00154, SRG-OS-000480-GPOS-00227


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

MOUNT_OPTION="nodev"
# Create array of local non-root partitions
readarray -t partitions_records < <(findmnt --mtab --raw --evaluate | grep "^/\w" | grep "\s/dev/\w")

for partition_record in "${partitions_records[@]}"; do
    # Get all important information for fstab
    mount_point="$(echo ${partition_record} | cut -d " " -f1)"
    device="$(echo ${partition_record} | cut -d " " -f2)"
    device_type="$(echo ${partition_record} | cut -d " " -f3)"
    # device and device_type will be used only in case when the device doesn't have fstab record
    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" $mount_point)"

# If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
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|$MOUNT_OPTION)(,|$)//g;s/,$//")
    [ "$previous_mount_opts" ] && previous_mount_opts+=","
    echo "$device $mount_point $device_type defaults,${previous_mount_opts}$MOUNT_OPTION 0 0" >> /etc/fstab
# If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "$MOUNT_OPTION")" -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,$MOUNT_OPTION|" /etc/fstab
fi
    if mkdir -p "$mount_point"; then
    if mountpoint -q "$mount_point"; then
        mount -o remount --target "$mount_point"
    else
        mount --target "$mount_point"
    fi
fi
done

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

Complexity:low
Disruption:high
Strategy:configure
- name: Ensure non-root local partitions are mounted with nodev option
  mount:
    path: '{{ item.mount }}'
    src: '{{ item.device }}'
    opts: '{{ item.options }},nodev'
    state: mounted
    fstype: '{{ item.fstype }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - item.mount is match('/\w')
    - item.options is not search('nodev')
  with_items:
    - '{{ ansible_facts.mounts }}'
  tags:
    - 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_nodev_nonroot_local_partitions
    - no_reboot_needed

Rule   Add nodev Option to /tmp   [ref]

The nodev mount option can be used to prevent device files from being created in /tmp. Legitimate character and block devices should not exist within temporary directories like /tmp. Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of /tmp.
Rationale:
The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_tmp_nodev
Identifiers and References

References:  BP28(R12), 11, 13, 14, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS05.06, DSS06.06, CCI-001764, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.11.2.9, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.8.2.1, A.8.2.2, A.8.2.3, A.8.3.1, A.8.3.3, A.9.1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154


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

function perform_remediation {
    
        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/tmp")"

    grep "$mount_point_match_regexp" -q /etc/fstab \
        || { echo "The mount point '/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2; 
                echo "Not remediating, because there is no record of /tmp in /etc/fstab" >&2; return 1; }
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /tmp)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|nodev)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo " /tmp  defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nodev")" -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,nodev|" /etc/fstab
    fi

    if mkdir -p "/tmp"; then
        if mountpoint -q "/tmp"; then
            mount -o remount --target "/tmp"
        else
            mount --target "/tmp"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- name: Check information associated to mountpoint
  command: findmnt --fstab '/tmp'
  register: device_name
  failed_when: device_name.rc > 1
  changed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_tmp_nodev
    - 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:
    - 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_tmp_nodev
    - no_reboot_needed

- name: If /tmp not mounted, craft mount_info manually
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - - target
      - source
      - fstype
      - options
    - - /tmp
      - ''
      - ''
      - defaults
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ("--fstab" | length == 0)
    - (device_name.stdout | length == 0)
  tags:
    - 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_tmp_nodev
    - no_reboot_needed

- name: Make sure nodev option is part of the to /tmp options
  set_fact:
    mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev''
      }) }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - mount_info is defined and "nodev" not in mount_info.options
  tags:
    - 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_tmp_nodev
    - no_reboot_needed

- name: Ensure /tmp is mounted with nodev option
  mount:
    path: /tmp
    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:
    - 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_tmp_nodev
    - no_reboot_needed

Complexity:low
Disruption:high
Strategy:enable

part /tmp --mountoptions="nodev"

Rule   Add noexec Option to /tmp   [ref]

The noexec mount option can be used to prevent binaries from being executed out of /tmp. Add the noexec option to the fourth column of /etc/fstab for the line which controls mounting of /tmp.
Rationale:
Allowing users to execute binaries from world-writable directories such as /tmp should never be necessary in normal operation and can expose the system to potential compromise.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_tmp_noexec
Identifiers and References

References:  BP28(R12), 11, 13, 14, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS05.06, DSS06.06, CCI-001764, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.11.2.9, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.8.2.1, A.8.2.2, A.8.2.3, A.8.3.1, A.8.3.3, A.9.1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154


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

function perform_remediation {
    
        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/tmp")"

    grep "$mount_point_match_regexp" -q /etc/fstab \
        || { echo "The mount point '/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2; 
                echo "Not remediating, because there is no record of /tmp in /etc/fstab" >&2; return 1; }
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /tmp)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|noexec)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo " /tmp  defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "noexec")" -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,noexec|" /etc/fstab
    fi

    if mkdir -p "/tmp"; then
        if mountpoint -q "/tmp"; then
            mount -o remount --target "/tmp"
        else
            mount --target "/tmp"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- name: Check information associated to mountpoint
  command: findmnt --fstab '/tmp'
  register: device_name
  failed_when: device_name.rc > 1
  changed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_tmp_noexec
    - 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:
    - 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_tmp_noexec
    - no_reboot_needed

- name: If /tmp not mounted, craft mount_info manually
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - - target
      - source
      - fstype
      - options
    - - /tmp
      - ''
      - ''
      - defaults
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ("--fstab" | length == 0)
    - (device_name.stdout | length == 0)
  tags:
    - 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_tmp_noexec
    - no_reboot_needed

- name: Make sure noexec option is part of the to /tmp options
  set_fact:
    mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec''
      }) }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - mount_info is defined and "noexec" not in mount_info.options
  tags:
    - 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_tmp_noexec
    - no_reboot_needed

- name: Ensure /tmp is mounted with noexec option
  mount:
    path: /tmp
    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:
    - 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_tmp_noexec
    - no_reboot_needed

Complexity:low
Disruption:high
Strategy:enable

part /tmp --mountoptions="noexec"

Rule   Add nosuid Option to /tmp   [ref]

The nosuid mount option can be used to prevent execution of setuid programs in /tmp. The SUID and SGID permissions should not be required in these world-writable directories. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of /tmp.
Rationale:
The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from temporary storage partitions.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_tmp_nosuid
Identifiers and References

References:  BP28(R12), 11, 13, 14, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS05.06, DSS06.06, CCI-001764, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.11.2.9, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.8.2.1, A.8.2.2, A.8.2.3, A.8.3.1, A.8.3.3, A.9.1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154


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

function perform_remediation {
    
        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/tmp")"

    grep "$mount_point_match_regexp" -q /etc/fstab \
        || { echo "The mount point '/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2; 
                echo "Not remediating, because there is no record of /tmp in /etc/fstab" >&2; return 1; }
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /tmp)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|nosuid)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo " /tmp  defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nosuid")" -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,nosuid|" /etc/fstab
    fi

    if mkdir -p "/tmp"; then
        if mountpoint -q "/tmp"; then
            mount -o remount --target "/tmp"
        else
            mount --target "/tmp"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- name: Check information associated to mountpoint
  command: findmnt --fstab '/tmp'
  register: device_name
  failed_when: device_name.rc > 1
  changed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_tmp_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:
    - 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_tmp_nosuid
    - no_reboot_needed

- name: If /tmp not mounted, craft mount_info manually
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - - target
      - source
      - fstype
      - options
    - - /tmp
      - ''
      - ''
      - defaults
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ("--fstab" | length == 0)
    - (device_name.stdout | length == 0)
  tags:
    - 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_tmp_nosuid
    - no_reboot_needed

- name: Make sure nosuid option is part of the to /tmp 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:
    - 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_tmp_nosuid
    - no_reboot_needed

- name: Ensure /tmp is mounted with nosuid option
  mount:
    path: /tmp
    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:
    - 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_tmp_nosuid
    - no_reboot_needed

Complexity:low
Disruption:high
Strategy:enable

part /tmp --mountoptions="nosuid"

Rule   Add nodev Option to /var/log/audit   [ref]

The nodev mount option can be used to prevent device files from being created in /var/log/audit. Legitimate character and block devices should exist only in the /dev directory on the root partition or within chroot jails built for system services. Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of /var/log/audit.
Rationale:
The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_var_log_audit_nodev
Identifiers and References

References:  CCI-001764, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154


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

function perform_remediation {
    
        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var/log/audit")"

    grep "$mount_point_match_regexp" -q /etc/fstab \
        || { echo "The mount point '/var/log/audit' is not even in /etc/fstab, so we can't set up mount options" >&2; 
                echo "Not remediating, because there is no record of /var/log/audit in /etc/fstab" >&2; return 1; }
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var/log/audit)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|nodev)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo " /var/log/audit  defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nodev")" -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,nodev|" /etc/fstab
    fi

    if mkdir -p "/var/log/audit"; then
        if mountpoint -q "/var/log/audit"; then
            mount -o remount --target "/var/log/audit"
        else
            mount --target "/var/log/audit"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- name: Check information associated to mountpoint
  command: findmnt --fstab '/var/log/audit'
  register: device_name
  failed_when: device_name.rc > 1
  changed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_var_log_audit_nodev
    - 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:
    - 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_var_log_audit_nodev
    - no_reboot_needed

- name: If /var/log/audit not mounted, craft mount_info manually
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - - target
      - source
      - fstype
      - options
    - - /var/log/audit
      - ''
      - ''
      - defaults
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ("--fstab" | length == 0)
    - (device_name.stdout | length == 0)
  tags:
    - 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_var_log_audit_nodev
    - no_reboot_needed

- name: Make sure nodev option is part of the to /var/log/audit options
  set_fact:
    mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev''
      }) }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - mount_info is defined and "nodev" not in mount_info.options
  tags:
    - 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_var_log_audit_nodev
    - no_reboot_needed

- name: Ensure /var/log/audit is mounted with nodev option
  mount:
    path: /var/log/audit
    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:
    - 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_var_log_audit_nodev
    - no_reboot_needed

Complexity:low
Disruption:high
Strategy:enable

part /var/log/audit --mountoptions="nodev"

Rule   Add noexec Option to /var/log/audit   [ref]

The noexec mount option can be used to prevent binaries from being executed out of /var/log/audit. Add the noexec option to the fourth column of /etc/fstab for the line which controls mounting of /var/log/audit.
Rationale:
Allowing users to execute binaries from directories containing audit log files such as /var/log/audit should never be necessary in normal operation and can expose the system to potential compromise.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_var_log_audit_noexec
Identifiers and References

References:  CCI-001764, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154


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

function perform_remediation {
    
        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var/log/audit")"

    grep "$mount_point_match_regexp" -q /etc/fstab \
        || { echo "The mount point '/var/log/audit' is not even in /etc/fstab, so we can't set up mount options" >&2; 
                echo "Not remediating, because there is no record of /var/log/audit in /etc/fstab" >&2; return 1; }
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var/log/audit)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|noexec)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo " /var/log/audit  defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "noexec")" -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,noexec|" /etc/fstab
    fi

    if mkdir -p "/var/log/audit"; then
        if mountpoint -q "/var/log/audit"; then
            mount -o remount --target "/var/log/audit"
        else
            mount --target "/var/log/audit"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- name: Check information associated to mountpoint
  command: findmnt --fstab '/var/log/audit'
  register: device_name
  failed_when: device_name.rc > 1
  changed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_var_log_audit_noexec
    - 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:
    - 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_var_log_audit_noexec
    - no_reboot_needed

- name: If /var/log/audit not mounted, craft mount_info manually
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - - target
      - source
      - fstype
      - options
    - - /var/log/audit
      - ''
      - ''
      - defaults
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ("--fstab" | length == 0)
    - (device_name.stdout | length == 0)
  tags:
    - 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_var_log_audit_noexec
    - no_reboot_needed

- name: Make sure noexec option is part of the to /var/log/audit options
  set_fact:
    mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec''
      }) }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - mount_info is defined and "noexec" not in mount_info.options
  tags:
    - 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_var_log_audit_noexec
    - no_reboot_needed

- name: Ensure /var/log/audit is mounted with noexec option
  mount:
    path: /var/log/audit
    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:
    - 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_var_log_audit_noexec
    - no_reboot_needed

Complexity:low
Disruption:high
Strategy:enable

part /var/log/audit --mountoptions="noexec"

Rule   Add nosuid Option to /var/log/audit   [ref]

The nosuid mount option can be used to prevent execution of setuid programs in /var/log/audit. The SUID and SGID permissions should not be required in directories containing audit log files. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of /var/log/audit.
Rationale:
The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from partitions designated for audit log files.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_var_log_audit_nosuid
Identifiers and References

References:  CCI-001764, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154


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

function perform_remediation {
    
        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var/log/audit")"

    grep "$mount_point_match_regexp" -q /etc/fstab \
        || { echo "The mount point '/var/log/audit' is not even in /etc/fstab, so we can't set up mount options" >&2; 
                echo "Not remediating, because there is no record of /var/log/audit in /etc/fstab" >&2; return 1; }
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var/log/audit)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|nosuid)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo " /var/log/audit  defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nosuid")" -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,nosuid|" /etc/fstab
    fi

    if mkdir -p "/var/log/audit"; then
        if mountpoint -q "/var/log/audit"; then
            mount -o remount --target "/var/log/audit"
        else
            mount --target "/var/log/audit"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- name: Check information associated to mountpoint
  command: findmnt --fstab '/var/log/audit'
  register: device_name
  failed_when: device_name.rc > 1
  changed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_var_log_audit_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:
    - 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_var_log_audit_nosuid
    - no_reboot_needed

- name: If /var/log/audit not mounted, craft mount_info manually
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - - target
      - source
      - fstype
      - options
    - - /var/log/audit
      - ''
      - ''
      - defaults
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ("--fstab" | length == 0)
    - (device_name.stdout | length == 0)
  tags:
    - 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_var_log_audit_nosuid
    - no_reboot_needed

- name: Make sure nosuid option is part of the to /var/log/audit 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:
    - 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_var_log_audit_nosuid
    - no_reboot_needed

- name: Ensure /var/log/audit is mounted with nosuid option
  mount:
    path: /var/log/audit
    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:
    - 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_var_log_audit_nosuid
    - no_reboot_needed

Complexity:low
Disruption:high
Strategy:enable

part /var/log/audit --mountoptions="nosuid"

Rule   Add nodev Option to /var/log   [ref]

The nodev mount option can be used to prevent device files from being created in /var/log. Legitimate character and block devices should exist only in the /dev directory on the root partition or within chroot jails built for system services. Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of /var/log.
Rationale:
The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_var_log_nodev
Identifiers and References

References:  CCI-001764, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154


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

function perform_remediation {
    
        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var/log")"

    grep "$mount_point_match_regexp" -q /etc/fstab \
        || { echo "The mount point '/var/log' is not even in /etc/fstab, so we can't set up mount options" >&2; 
                echo "Not remediating, because there is no record of /var/log in /etc/fstab" >&2; return 1; }
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var/log)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|nodev)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo " /var/log  defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nodev")" -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,nodev|" /etc/fstab
    fi

    if mkdir -p "/var/log"; then
        if mountpoint -q "/var/log"; then
            mount -o remount --target "/var/log"
        else
            mount --target "/var/log"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- name: Check information associated to mountpoint
  command: findmnt --fstab '/var/log'
  register: device_name
  failed_when: device_name.rc > 1
  changed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_var_log_nodev
    - 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:
    - 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_var_log_nodev
    - no_reboot_needed

- name: If /var/log not mounted, craft mount_info manually
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - - target
      - source
      - fstype
      - options
    - - /var/log
      - ''
      - ''
      - defaults
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ("--fstab" | length == 0)
    - (device_name.stdout | length == 0)
  tags:
    - 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_var_log_nodev
    - no_reboot_needed

- name: Make sure nodev option is part of the to /var/log options
  set_fact:
    mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev''
      }) }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - mount_info is defined and "nodev" not in mount_info.options
  tags:
    - 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_var_log_nodev
    - no_reboot_needed

- name: Ensure /var/log is mounted with nodev option
  mount:
    path: /var/log
    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:
    - 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_var_log_nodev
    - no_reboot_needed

Complexity:low
Disruption:high
Strategy:enable

part /var/log --mountoptions="nodev"

Rule   Add noexec Option to /var/log   [ref]

The noexec mount option can be used to prevent binaries from being executed out of /var/log. Add the noexec option to the fourth column of /etc/fstab for the line which controls mounting of /var/log.
Rationale:
Allowing users to execute binaries from directories containing log files such as /var/log should never be necessary in normal operation and can expose the system to potential compromise.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_var_log_noexec
Identifiers and References

References:  BP28(R12), CCI-001764, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154


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

function perform_remediation {
    
        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var/log")"

    grep "$mount_point_match_regexp" -q /etc/fstab \
        || { echo "The mount point '/var/log' is not even in /etc/fstab, so we can't set up mount options" >&2; 
                echo "Not remediating, because there is no record of /var/log in /etc/fstab" >&2; return 1; }
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var/log)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|noexec)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo " /var/log  defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "noexec")" -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,noexec|" /etc/fstab
    fi

    if mkdir -p "/var/log"; then
        if mountpoint -q "/var/log"; then
            mount -o remount --target "/var/log"
        else
            mount --target "/var/log"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- name: Check information associated to mountpoint
  command: findmnt --fstab '/var/log'
  register: device_name
  failed_when: device_name.rc > 1
  changed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_var_log_noexec
    - 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:
    - 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_var_log_noexec
    - no_reboot_needed

- name: If /var/log not mounted, craft mount_info manually
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - - target
      - source
      - fstype
      - options
    - - /var/log
      - ''
      - ''
      - defaults
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ("--fstab" | length == 0)
    - (device_name.stdout | length == 0)
  tags:
    - 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_var_log_noexec
    - no_reboot_needed

- name: Make sure noexec option is part of the to /var/log options
  set_fact:
    mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec''
      }) }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - mount_info is defined and "noexec" not in mount_info.options
  tags:
    - 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_var_log_noexec
    - no_reboot_needed

- name: Ensure /var/log is mounted with noexec option
  mount:
    path: /var/log
    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:
    - 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_var_log_noexec
    - no_reboot_needed

Complexity:low
Disruption:high
Strategy:enable

part /var/log --mountoptions="noexec"

Rule   Add nosuid Option to /var/log   [ref]

The nosuid mount option can be used to prevent execution of setuid programs in /var/log. The SUID and SGID permissions should not be required in directories containing log files. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of /var/log.
Rationale:
The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from partitions designated for log files.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_var_log_nosuid
Identifiers and References

References:  BP28(R12), CCI-001764, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154


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

function perform_remediation {
    
        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var/log")"

    grep "$mount_point_match_regexp" -q /etc/fstab \
        || { echo "The mount point '/var/log' is not even in /etc/fstab, so we can't set up mount options" >&2; 
                echo "Not remediating, because there is no record of /var/log in /etc/fstab" >&2; return 1; }
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var/log)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|nosuid)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo " /var/log  defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nosuid")" -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,nosuid|" /etc/fstab
    fi

    if mkdir -p "/var/log"; then
        if mountpoint -q "/var/log"; then
            mount -o remount --target "/var/log"
        else
            mount --target "/var/log"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- name: Check information associated to mountpoint
  command: findmnt --fstab '/var/log'
  register: device_name
  failed_when: device_name.rc > 1
  changed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_var_log_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:
    - 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_var_log_nosuid
    - no_reboot_needed

- name: If /var/log not mounted, craft mount_info manually
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - - target
      - source
      - fstype
      - options
    - - /var/log
      - ''
      - ''
      - defaults
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ("--fstab" | length == 0)
    - (device_name.stdout | length == 0)
  tags:
    - 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_var_log_nosuid
    - no_reboot_needed

- name: Make sure nosuid option is part of the to /var/log 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:
    - 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_var_log_nosuid
    - no_reboot_needed

- name: Ensure /var/log is mounted with nosuid option
  mount:
    path: /var/log
    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:
    - 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_var_log_nosuid
    - no_reboot_needed

Complexity:low
Disruption:high
Strategy:enable

part /var/log --mountoptions="nosuid"

Rule   Add nodev Option to /var   [ref]

The nodev mount option can be used to prevent device files from being created in /var. Legitimate character and block devices should exist only in the /dev directory on the root partition or within chroot jails built for system services. Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of /var.
Rationale:
The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_var_nodev
Identifiers and References

References:  CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, CM-7(a), CM-7(b), CM-6(a), AC-6, AC-6(1), MP-7, PR.IP-1, PR.PT-2, PR.PT-3, SRG-OS-000368-GPOS-00154


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

function perform_remediation {
    
        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var")"

    grep "$mount_point_match_regexp" -q /etc/fstab \
        || { echo "The mount point '/var' is not even in /etc/fstab, so we can't set up mount options" >&2; 
                echo "Not remediating, because there is no record of /var in /etc/fstab" >&2; return 1; }
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|nodev)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo " /var  defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nodev")" -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,nodev|" /etc/fstab
    fi

    if mkdir -p "/var"; then
        if mountpoint -q "/var"; then
            mount -o remount --target "/var"
        else
            mount --target "/var"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- name: Check information associated to mountpoint
  command: findmnt --fstab '/var'
  register: device_name
  failed_when: device_name.rc > 1
  changed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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_var_nodev
    - 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:
    - 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_var_nodev
    - no_reboot_needed

- name: If /var not mounted, craft mount_info manually
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - - target
      - source
      - fstype
      - options
    - - /var
      - ''
      - ''
      - defaults
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ("--fstab" | length == 0)
    - (device_name.stdout | length == 0)
  tags:
    - 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_var_nodev
    - no_reboot_needed

- name: Make sure nodev option is part of the to /var options
  set_fact:
    mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev''
      }) }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - mount_info is defined and "nodev" not in mount_info.options
  tags:
    - 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_var_nodev
    - no_reboot_needed

- name: Ensure /var is mounted with nodev option
  mount:
    path: /var
    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:
    - 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_var_nodev
    - no_reboot_needed

Complexity:low
Disruption:high
Strategy:enable

part /var --mountoptions="nodev"

Rule   Add nodev Option to /var/tmp   [ref]

The nodev mount option can be used to prevent device files from being created in /var/tmp. Legitimate character and block devices should not exist within temporary directories like /var/tmp. Add the nodev option to the fourth column of /etc/fstab for the line which controls mounting of /var/tmp.
Rationale:
The only legitimate location for device files is the /dev directory located on the root partition. The only exception to this is chroot jails.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_var_tmp_nodev
Identifiers and References

References:  BP28(R12), CCI-001764, SRG-OS-000368-GPOS-00154


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

function perform_remediation {
    
        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var/tmp")"

    grep "$mount_point_match_regexp" -q /etc/fstab \
        || { echo "The mount point '/var/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2; 
                echo "Not remediating, because there is no record of /var/tmp in /etc/fstab" >&2; return 1; }
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var/tmp)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|nodev)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo " /var/tmp  defaults,${previous_mount_opts}nodev 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nodev")" -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,nodev|" /etc/fstab
    fi

    if mkdir -p "/var/tmp"; then
        if mountpoint -q "/var/tmp"; then
            mount -o remount --target "/var/tmp"
        else
            mount --target "/var/tmp"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- name: Check information associated to mountpoint
  command: findmnt --fstab '/var/tmp'
  register: device_name
  failed_when: device_name.rc > 1
  changed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_var_tmp_nodev
    - 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:
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_var_tmp_nodev
    - no_reboot_needed

- name: If /var/tmp not mounted, craft mount_info manually
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - - target
      - source
      - fstype
      - options
    - - /var/tmp
      - ''
      - ''
      - defaults
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ("--fstab" | length == 0)
    - (device_name.stdout | length == 0)
  tags:
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_var_tmp_nodev
    - no_reboot_needed

- name: Make sure nodev option is part of the to /var/tmp options
  set_fact:
    mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',nodev''
      }) }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - mount_info is defined and "nodev" not in mount_info.options
  tags:
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_var_tmp_nodev
    - no_reboot_needed

- name: Ensure /var/tmp is mounted with nodev option
  mount:
    path: /var/tmp
    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:
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_var_tmp_nodev
    - no_reboot_needed

Complexity:low
Disruption:high
Strategy:enable

part /var/tmp --mountoptions="nodev"

Rule   Add noexec Option to /var/tmp   [ref]

The noexec mount option can be used to prevent binaries from being executed out of /var/tmp. Add the noexec option to the fourth column of /etc/fstab for the line which controls mounting of /var/tmp.
Rationale:
Allowing users to execute binaries from world-writable directories such as /var/tmp should never be necessary in normal operation and can expose the system to potential compromise.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_var_tmp_noexec
Identifiers and References

References:  BP28(R12), CCI-001764, SRG-OS-000368-GPOS-00154


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

function perform_remediation {
    
        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var/tmp")"

    grep "$mount_point_match_regexp" -q /etc/fstab \
        || { echo "The mount point '/var/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2; 
                echo "Not remediating, because there is no record of /var/tmp in /etc/fstab" >&2; return 1; }
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var/tmp)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|noexec)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo " /var/tmp  defaults,${previous_mount_opts}noexec 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "noexec")" -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,noexec|" /etc/fstab
    fi

    if mkdir -p "/var/tmp"; then
        if mountpoint -q "/var/tmp"; then
            mount -o remount --target "/var/tmp"
        else
            mount --target "/var/tmp"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- name: Check information associated to mountpoint
  command: findmnt --fstab '/var/tmp'
  register: device_name
  failed_when: device_name.rc > 1
  changed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_var_tmp_noexec
    - 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:
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_var_tmp_noexec
    - no_reboot_needed

- name: If /var/tmp not mounted, craft mount_info manually
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - - target
      - source
      - fstype
      - options
    - - /var/tmp
      - ''
      - ''
      - defaults
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ("--fstab" | length == 0)
    - (device_name.stdout | length == 0)
  tags:
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_var_tmp_noexec
    - no_reboot_needed

- name: Make sure noexec option is part of the to /var/tmp options
  set_fact:
    mount_info: '{{ mount_info | combine( {''options'':''''~mount_info.options~'',noexec''
      }) }}'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - mount_info is defined and "noexec" not in mount_info.options
  tags:
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_var_tmp_noexec
    - no_reboot_needed

- name: Ensure /var/tmp is mounted with noexec option
  mount:
    path: /var/tmp
    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:
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_var_tmp_noexec
    - no_reboot_needed

Complexity:low
Disruption:high
Strategy:enable

part /var/tmp --mountoptions="noexec"

Rule   Add nosuid Option to /var/tmp   [ref]

The nosuid mount option can be used to prevent execution of setuid programs in /var/tmp. The SUID and SGID permissions should not be required in these world-writable directories. Add the nosuid option to the fourth column of /etc/fstab for the line which controls mounting of /var/tmp.
Rationale:
The presence of SUID and SGID executables should be tightly controlled. Users should not be able to execute SUID or SGID binaries from temporary storage partitions.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_mount_option_var_tmp_nosuid
Identifiers and References

References:  BP28(R12), CCI-001764, SRG-OS-000368-GPOS-00154


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

function perform_remediation {
    
        mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" "/var/tmp")"

    grep "$mount_point_match_regexp" -q /etc/fstab \
        || { echo "The mount point '/var/tmp' is not even in /etc/fstab, so we can't set up mount options" >&2; 
                echo "Not remediating, because there is no record of /var/tmp in /etc/fstab" >&2; return 1; }
    

    mount_point_match_regexp="$(printf "[[:space:]]%s[[:space:]]" /var/tmp)"

    # If the mount point is not in /etc/fstab, get previous mount options from /etc/mtab
    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|nosuid)(,|$)//g;s/,$//")
        [ "$previous_mount_opts" ] && previous_mount_opts+=","
        echo " /var/tmp  defaults,${previous_mount_opts}nosuid 0 0" >> /etc/fstab
    # If the mount_opt option is not already in the mount point's /etc/fstab entry, add it
    elif [ "$(grep "$mount_point_match_regexp" /etc/fstab | grep -c "nosuid")" -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,nosuid|" /etc/fstab
    fi

    if mkdir -p "/var/tmp"; then
        if mountpoint -q "/var/tmp"; then
            mount -o remount --target "/var/tmp"
        else
            mount --target "/var/tmp"
        fi
    fi
}

perform_remediation

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

Complexity:low
Disruption:high
Strategy:configure
- name: Check information associated to mountpoint
  command: findmnt --fstab '/var/tmp'
  register: device_name
  failed_when: device_name.rc > 1
  changed_when: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_var_tmp_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:
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_var_tmp_nosuid
    - no_reboot_needed

- name: If /var/tmp not mounted, craft mount_info manually
  set_fact:
    mount_info: '{{ mount_info|default({})|combine({item.0: item.1}) }}'
  with_together:
    - - target
      - source
      - fstype
      - options
    - - /var/tmp
      - ''
      - ''
      - defaults
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - ("--fstab" | length == 0)
    - (device_name.stdout | length == 0)
  tags:
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_var_tmp_nosuid
    - no_reboot_needed

- name: Make sure nosuid option is part of the to /var/tmp 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:
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_var_tmp_nosuid
    - no_reboot_needed

- name: Ensure /var/tmp is mounted with nosuid option
  mount:
    path: /var/tmp
    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:
    - configure_strategy
    - high_disruption
    - low_complexity
    - medium_severity
    - mount_option_var_tmp_nosuid
    - no_reboot_needed

Complexity:low
Disruption:high
Strategy:enable

part /var/tmp --mountoptions="nosuid"
Group   Restrict Programs from Dangerous Execution Patterns   Group contains 2 groups and 13 rules
[ref]   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.
Group   Disable Core Dumps   Group contains 4 rules
[ref]   A core dump file is the memory image of an executable program when it was terminated by the operating system due to errant behavior. In most cases, only software developers legitimately need to access these files. The core dump files may also contain sensitive information, or unnecessarily occupy large amounts of disk space.

Once a hard limit is set in /etc/security/limits.conf, or to a file within the /etc/security/limits.d/ directory, a user cannot increase that limit within his or her own session. If access to core dumps is required, consider restricting them to only certain users or groups. See the limits.conf man page for more information.

The core dumps of setuid programs are further protected. The sysctl variable fs.suid_dumpable controls whether the kernel allows core dumps from these programs at all. The default value of 0 is recommended.

Rule   Disable acquiring, saving, and processing core dumps   [ref]

The systemd-coredump.socket unit is a socket activation of the systemd-coredump@.service which processes core dumps. By masking the unit, core dump processing is disabled.
Rationale:
A core dump includes a memory image taken at the time the operating system terminates an application. The memory image could contain sensitive data and is generally useful only for developers trying to debug problems.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_service_systemd-coredump_disabled
Identifiers and References

References:  CCI-000366, SC-7(10), FMT_SMF_EXT.1, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:low
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

SYSTEMCTL_EXEC='/usr/bin/systemctl'
"$SYSTEMCTL_EXEC" stop 'systemd-coredump.service'
"$SYSTEMCTL_EXEC" disable 'systemd-coredump.service'
"$SYSTEMCTL_EXEC" mask 'systemd-coredump.service'
# Disable socket activation if we have a unit file for it
if "$SYSTEMCTL_EXEC" list-unit-files | grep -q '^systemd-coredump.socket'; then
    "$SYSTEMCTL_EXEC" stop 'systemd-coredump.socket'
    "$SYSTEMCTL_EXEC" mask 'systemd-coredump.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 'systemd-coredump.service' || true

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

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service systemd-coredump
  block:

    - name: Disable service systemd-coredump
      systemd:
        name: systemd-coredump.service
        enabled: 'no'
        state: stopped
        masked: 'yes'
      ignore_errors: 'yes'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-SC-7(10)
    - disable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_systemd-coredump_disabled

- name: Unit Socket Exists - systemd-coredump.socket
  command: systemctl list-unit-files systemd-coredump.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:
    - NIST-800-53-SC-7(10)
    - disable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_systemd-coredump_disabled

- name: Disable socket systemd-coredump
  systemd:
    name: systemd-coredump.socket
    enabled: 'no'
    state: stopped
    masked: 'yes'
  when:
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
    - '"systemd-coredump.socket" in socket_file_exists.stdout_lines[1]'
  tags:
    - NIST-800-53-SC-7(10)
    - disable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_systemd-coredump_disabled

Complexity:low
Disruption:low
Strategy:enable
include disable_systemd-coredump

class disable_systemd-coredump {
  service {'systemd-coredump':
    enable => false,
    ensure => 'stopped',
  }
}

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    systemd:
      units:
      - name: systemd-coredump.service
        enabled: false
        mask: true
      - name: systemd-coredump.socket
        enabled: false
        mask: true


[customizations.services]
disabled = ["systemd-coredump"]

Rule   Disable core dump backtraces   [ref]

The ProcessSizeMax option in [Coredump] section of /etc/systemd/coredump.conf specifies the maximum size in bytes of a core which will be processed. Core dumps exceeding this size may be stored, but the backtrace will not be generated.
Warning:  If the /etc/systemd/coredump.conf file does not already contain the [Coredump] section, the value will not be configured correctly.
Rationale:
A core dump includes a memory image taken at the time the operating system terminates an application. The memory image could contain sensitive data and is generally useful only for developers or system operators trying to debug problems. Enabling core dumps on production systems is not recommended, however there may be overriding operational requirements to enable advanced debuging. Permitting temporary enablement of core dumps during such situations should be reviewed through local needs and policy.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_coredump_disable_backtraces
Identifiers and References

References:  CCI-000366, CM-6, FMT_SMF_EXT.1, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:low
Strategy:restrict
if [ -e "/etc/systemd/coredump.conf" ] ; then
    
    LC_ALL=C sed -i "/^\s*ProcessSizeMax\s*=\s*/Id" "/etc/systemd/coredump.conf"
else
    touch "/etc/systemd/coredump.conf"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/systemd/coredump.conf"

cp "/etc/systemd/coredump.conf" "/etc/systemd/coredump.conf.bak"
# Insert at the end of the file
printf '%s\n' "ProcessSizeMax=0" >> "/etc/systemd/coredump.conf"
# Clean up after ourselves.
rm "/etc/systemd/coredump.conf.bak"

Complexity:low
Disruption:low
Strategy:restrict
- name: Disable core dump backtraces
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/systemd/coredump.conf
        create: false
        regexp: ^\s*ProcessSizeMax\s*=\s*
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/systemd/coredump.conf
      lineinfile:
        path: /etc/systemd/coredump.conf
        create: false
        regexp: ^\s*ProcessSizeMax\s*=\s*
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/systemd/coredump.conf
      lineinfile:
        path: /etc/systemd/coredump.conf
        create: false
        regexp: ^\s*ProcessSizeMax\s*=\s*
        line: ProcessSizeMax=0
        state: present
  tags:
    - NIST-800-53-CM-6
    - coredump_disable_backtraces
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,%23%20%20This%20file%20is%20part%20of%20systemd.%0A%23%0A%23%20%20systemd%20is%20free%20software%3B%20you%20can%20redistribute%20it%20and/or%20modify%20it%0A%23%20%20under%20the%20terms%20of%20the%20GNU%20Lesser%20General%20Public%20License%20as%20published%20by%0A%23%20%20the%20Free%20Software%20Foundation%3B%20either%20version%202.1%20of%20the%20License%2C%20or%0A%23%20%20%28at%20your%20option%29%20any%20later%20version.%0A%23%0A%23%20Entries%20in%20this%20file%20show%20the%20compile%20time%20defaults.%0A%23%20You%20can%20change%20settings%20by%20editing%20this%20file.%0A%23%20Defaults%20can%20be%20restored%20by%20simply%20deleting%20this%20file.%0A%23%0A%23%20See%20coredump.conf%285%29%20for%20details.%0A%0A%5BCoredump%5D%0A%23Storage%3Dexternal%0A%23Compress%3Dyes%0A%23ProcessSizeMax%3D2G%0A%23ExternalSizeMax%3D2G%0A%23JournalSizeMax%3D767M%0A%23MaxUse%3D%0A%23KeepFree%3D%0AStorage%3Dnone%0AProcessSizeMax%3D0%0A
        mode: 0644
        path: /etc/systemd/coredump.conf
        overwrite: true

Rule   Disable storing core dump   [ref]

The Storage option in [Coredump] section of /etc/systemd/coredump.conf can be set to none to disable storing core dumps permanently.
Warning:  If the /etc/systemd/coredump.conf file does not already contain the [Coredump] section, the value will not be configured correctly.
Rationale:
A core dump includes a memory image taken at the time the operating system terminates an application. The memory image could contain sensitive data and is generally useful only for developers or system operators trying to debug problems. Enabling core dumps on production systems is not recommended, however there may be overriding operational requirements to enable advanced debuging. Permitting temporary enablement of core dumps during such situations should be reviewed through local needs and policy.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_coredump_disable_storage
Identifiers and References

References:  CCI-000366, CM-6, FMT_SMF_EXT.1, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:low
Strategy:restrict
if [ -e "/etc/systemd/coredump.conf" ] ; then
    
    LC_ALL=C sed -i "/^\s*Storage\s*=\s*/Id" "/etc/systemd/coredump.conf"
else
    touch "/etc/systemd/coredump.conf"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/systemd/coredump.conf"

cp "/etc/systemd/coredump.conf" "/etc/systemd/coredump.conf.bak"
# Insert at the end of the file
printf '%s\n' "Storage=none" >> "/etc/systemd/coredump.conf"
# Clean up after ourselves.
rm "/etc/systemd/coredump.conf.bak"

Complexity:low
Disruption:low
Strategy:restrict
- name: Disable storing core dump
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/systemd/coredump.conf
        create: false
        regexp: ^\s*Storage\s*=\s*
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/systemd/coredump.conf
      lineinfile:
        path: /etc/systemd/coredump.conf
        create: false
        regexp: ^\s*Storage\s*=\s*
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/systemd/coredump.conf
      lineinfile:
        path: /etc/systemd/coredump.conf
        create: false
        regexp: ^\s*Storage\s*=\s*
        line: Storage=none
        state: present
  tags:
    - NIST-800-53-CM-6
    - coredump_disable_storage
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,%23%20%20This%20file%20is%20part%20of%20systemd.%0A%23%0A%23%20%20systemd%20is%20free%20software%3B%20you%20can%20redistribute%20it%20and/or%20modify%20it%0A%23%20%20under%20the%20terms%20of%20the%20GNU%20Lesser%20General%20Public%20License%20as%20published%20by%0A%23%20%20the%20Free%20Software%20Foundation%3B%20either%20version%202.1%20of%20the%20License%2C%20or%0A%23%20%20%28at%20your%20option%29%20any%20later%20version.%0A%23%0A%23%20Entries%20in%20this%20file%20show%20the%20compile%20time%20defaults.%0A%23%20You%20can%20change%20settings%20by%20editing%20this%20file.%0A%23%20Defaults%20can%20be%20restored%20by%20simply%20deleting%20this%20file.%0A%23%0A%23%20See%20coredump.conf%285%29%20for%20details.%0A%0A%5BCoredump%5D%0A%23Storage%3Dexternal%0A%23Compress%3Dyes%0A%23ProcessSizeMax%3D2G%0A%23ExternalSizeMax%3D2G%0A%23JournalSizeMax%3D767M%0A%23MaxUse%3D%0A%23KeepFree%3D%0AStorage%3Dnone%0AProcessSizeMax%3D0%0A
        mode: 0644
        path: /etc/systemd/coredump.conf
        overwrite: true

Rule   Disable Core Dumps for All Users   [ref]

To disable core dumps for all users, add the following line to /etc/security/limits.conf, or to a file within the /etc/security/limits.d/ directory:
*     hard   core    0
Rationale:
A core dump includes a memory image taken at the time the operating system terminates an application. The memory image could contain sensitive data and is generally useful only for developers trying to debug problems.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_disable_users_coredumps
Identifiers and References

References:  1, 12, 13, 15, 16, 2, 7, 8, APO13.01, BAI04.04, DSS01.03, DSS03.05, DSS05.07, CCI-000366, SR 6.2, SR 7.1, SR 7.2, A.12.1.3, A.17.2.1, CM-6, SC-7(10), DE.CM-1, PR.DS-4, SRG-OS-000480-GPOS-00227


# Remediation is applicable only in certain platforms
if rpm --quiet -q pam; then

SECURITY_LIMITS_FILE="/etc/security/limits.conf"

if grep -qE '\*\s+hard\s+core' $SECURITY_LIMITS_FILE; then
        sed -ri 's/(hard\s+core\s+)[[:digit:]]+/\1 0/' $SECURITY_LIMITS_FILE
else
        echo "*     hard   core    0" >> $SECURITY_LIMITS_FILE
fi

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - NIST-800-53-CM-6
    - NIST-800-53-SC-7(10)
    - disable_users_coredumps
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: disable core dumps with limits
  lineinfile:
    dest: /etc/security/limits.conf
    regexp: ^[^#].*core
    line: '*        hard       core      0'
    create: true
  when: '"pam" in ansible_facts.packages'
  tags:
    - NIST-800-53-CM-6
    - NIST-800-53-SC-7(10)
    - disable_users_coredumps
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,%2A%20%20%20%20%20hard%20%20%20core%20%20%20%200
        mode: 0644
        path: /etc/security/limits.d/75-disable_users_coredumps.conf
        overwrite: true
Group   Enable ExecShield   Group contains 1 rule
[ref]   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.

Rule   Restrict Exposed Kernel Pointer Addresses Access   [ref]

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.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_kernel_kptr_restrict
Identifiers and References

References:  BP28(R23), CCI-002824, CCI-000366, CIP-002-5 R1.1, CIP-002-5 R1.2, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 4.1, CIP-004-6 4.2, CIP-004-6 R2.2.3, CIP-004-6 R2.2.4, CIP-004-6 R2.3, CIP-004-6 R4, CIP-005-6 R1, CIP-005-6 R1.1, CIP-005-6 R1.2, CIP-007-3 R3, CIP-007-3 R3.1, CIP-007-3 R5.1, CIP-007-3 R5.1.2, CIP-007-3 R5.1.3, CIP-007-3 R5.2.1, CIP-007-3 R5.2.3, CIP-007-3 R8.4, CIP-009-6 R.1.1, CIP-009-6 R4, SC-30, SC-30(2), SC-30(5), CM-6(a), SRG-OS-000132-GPOS-00067, SRG-OS-000433-GPOS-00192, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of kernel.kptr_restrict from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+kernel.kptr_restrict.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "kernel.kptr_restrict" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done

#
# Set runtime for kernel.kptr_restrict
#
/sbin/sysctl -q -n -w kernel.kptr_restrict="1"

#
# If kernel.kptr_restrict present in /etc/sysctl.conf, change value to "1"
#	else, add "kernel.kptr_restrict = 1" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^kernel.kptr_restrict")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "1"

# 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 -i -e "^kernel.kptr_restrict\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^kernel.kptr_restrict\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*kernel.kptr_restrict.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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

- name: Comment out any occurrences of kernel.kptr_restrict from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*kernel.kptr_restrict
    replace: '#kernel.kptr_restrict'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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

- 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:
    - 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

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,kernel.kptr_restrict%3D1%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_kernel_kptr_restrict.conf
        overwrite: true

Rule   Disable storing core dumps   [ref]

To set the runtime status of the kernel.core_pattern kernel parameter, run the following command:
$ sudo sysctl -w kernel.core_pattern=|/bin/false
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
kernel.core_pattern = |/bin/false
Rationale:
A core dump includes a memory image taken at the time the operating system terminates an application. The memory image could contain sensitive data and is generally useful only for developers trying to debug problems.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_kernel_core_pattern
Identifiers and References

References:  CCI-000366, SC-7(10), FMT_SMF_EXT.1, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of kernel.core_pattern from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+kernel.core_pattern.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "kernel.core_pattern" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done

#
# Set runtime for kernel.core_pattern
#
/sbin/sysctl -q -n -w kernel.core_pattern="|/bin/false"

#
# If kernel.core_pattern present in /etc/sysctl.conf, change value to "|/bin/false"
#	else, add "kernel.core_pattern = |/bin/false" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^kernel.core_pattern")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "|/bin/false"

# 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 -i -e "^kernel.core_pattern\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^kernel.core_pattern\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*kernel.core_pattern.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-SC-7(10)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_core_pattern

- name: Comment out any occurrences of kernel.core_pattern from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*kernel.core_pattern
    replace: '#kernel.core_pattern'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-SC-7(10)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_core_pattern

- name: Ensure sysctl kernel.core_pattern is set to |/bin/false
  sysctl:
    name: kernel.core_pattern
    value: '|/bin/false'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-SC-7(10)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_core_pattern

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,kernel.core_pattern%20%3D%20%7C/bin/false%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_kernel_core_pattern.conf
        overwrite: true

Rule   Restrict Access to Kernel Message Buffer   [ref]

To set the runtime status of the kernel.dmesg_restrict kernel parameter, run the following command:
$ sudo sysctl -w kernel.dmesg_restrict=1
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
kernel.dmesg_restrict = 1
Rationale:
Unprivileged access to the kernel syslog can expose sensitive kernel address information.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_kernel_dmesg_restrict
Identifiers and References

References:  BP28(R23), 3.1.5, CCI-001314, 164.308(a)(1)(ii)(D), 164.308(a)(3), 164.308(a)(4), 164.310(b), 164.310(c), 164.312(a), 164.312(e), SI-11(a), SI-11(b), SRG-OS-000132-GPOS-00067, SRG-OS-000138-GPOS-00069


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of kernel.dmesg_restrict from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+kernel.dmesg_restrict.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "kernel.dmesg_restrict" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done

#
# Set runtime for kernel.dmesg_restrict
#
/sbin/sysctl -q -n -w kernel.dmesg_restrict="1"

#
# If kernel.dmesg_restrict present in /etc/sysctl.conf, change value to "1"
#	else, add "kernel.dmesg_restrict = 1" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^kernel.dmesg_restrict")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "1"

# 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 -i -e "^kernel.dmesg_restrict\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^kernel.dmesg_restrict\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*kernel.dmesg_restrict.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.5
    - NIST-800-53-SI-11(a)
    - NIST-800-53-SI-11(b)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_dmesg_restrict

- name: Comment out any occurrences of kernel.dmesg_restrict from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*kernel.dmesg_restrict
    replace: '#kernel.dmesg_restrict'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.5
    - NIST-800-53-SI-11(a)
    - NIST-800-53-SI-11(b)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_dmesg_restrict

- name: Ensure sysctl kernel.dmesg_restrict is set to 1
  sysctl:
    name: kernel.dmesg_restrict
    value: '1'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.5
    - NIST-800-53-SI-11(a)
    - NIST-800-53-SI-11(b)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_dmesg_restrict

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,kernel.dmesg_restrict%3D1%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_kernel_dmesg_restrict.conf
        overwrite: true

Rule   Disable Kernel Image Loading   [ref]

To set the runtime status of the kernel.kexec_load_disabled kernel parameter, run the following command:
$ sudo sysctl -w kernel.kexec_load_disabled=1
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
kernel.kexec_load_disabled = 1
Rationale:
Disabling kexec_load allows greater control of the kernel memory. It makes it impossible to load another kernel image after it has been disabled.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_kernel_kexec_load_disabled
Identifiers and References

References:  CCI-001749, CM-6, SRG-OS-000480-GPOS-00227, SRG-OS-000366-GPOS-00153


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of kernel.kexec_load_disabled from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+kernel.kexec_load_disabled.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "kernel.kexec_load_disabled" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done

#
# Set runtime for kernel.kexec_load_disabled
#
/sbin/sysctl -q -n -w kernel.kexec_load_disabled="1"

#
# If kernel.kexec_load_disabled present in /etc/sysctl.conf, change value to "1"
#	else, add "kernel.kexec_load_disabled = 1" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^kernel.kexec_load_disabled")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "1"

# 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 -i -e "^kernel.kexec_load_disabled\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^kernel.kexec_load_disabled\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*kernel.kexec_load_disabled.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-CM-6
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_kexec_load_disabled

- name: Comment out any occurrences of kernel.kexec_load_disabled from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*kernel.kexec_load_disabled
    replace: '#kernel.kexec_load_disabled'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-CM-6
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_kexec_load_disabled

- name: Ensure sysctl kernel.kexec_load_disabled is set to 1
  sysctl:
    name: kernel.kexec_load_disabled
    value: '1'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-CM-6
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_kexec_load_disabled

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,kernel.kexec_load_disabled%3D1%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_kernel_kexec_load_disabled.conf
        overwrite: true

Rule   Disallow kernel profiling by unprivileged users   [ref]

To set the runtime status of the kernel.perf_event_paranoid kernel parameter, run the following command:
$ sudo sysctl -w kernel.perf_event_paranoid=2
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
kernel.perf_event_paranoid = 2
Rationale:
Kernel profiling can reveal sensitive information about kernel behaviour.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_kernel_perf_event_paranoid
Identifiers and References

References:  BP28(R23), CCI-001090, AC-6, FMT_SMF_EXT.1, SRG-OS-000132-GPOS-00067, SRG-OS-000138-GPOS-00069


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of kernel.perf_event_paranoid from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+kernel.perf_event_paranoid.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "kernel.perf_event_paranoid" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done

#
# Set runtime for kernel.perf_event_paranoid
#
/sbin/sysctl -q -n -w kernel.perf_event_paranoid="2"

#
# If kernel.perf_event_paranoid present in /etc/sysctl.conf, change value to "2"
#	else, add "kernel.perf_event_paranoid = 2" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^kernel.perf_event_paranoid")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "2"

# 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 -i -e "^kernel.perf_event_paranoid\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^kernel.perf_event_paranoid\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*kernel.perf_event_paranoid.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AC-6
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_perf_event_paranoid

- name: Comment out any occurrences of kernel.perf_event_paranoid from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*kernel.perf_event_paranoid
    replace: '#kernel.perf_event_paranoid'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AC-6
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_perf_event_paranoid

- name: Ensure sysctl kernel.perf_event_paranoid is set to 2
  sysctl:
    name: kernel.perf_event_paranoid
    value: '2'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AC-6
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_perf_event_paranoid

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,kernel.perf_event_paranoid%3D2%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_kernel_perf_event_paranoid.conf
        overwrite: true

Rule   Disable Access to Network bpf() Syscall From Unprivileged Processes   [ref]

To set the runtime status of the kernel.unprivileged_bpf_disabled kernel parameter, run the following command:
$ sudo sysctl -w kernel.unprivileged_bpf_disabled=1
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
kernel.unprivileged_bpf_disabled = 1
Rationale:
Loading and accessing the packet filters programs and maps using the bpf() syscall has the potential of revealing sensitive information about the kernel state.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_kernel_unprivileged_bpf_disabled
Identifiers and References

References:  CCI-000366, AC-6, SC-7(10), FMT_SMF_EXT.1, SRG-OS-000132-GPOS-00067, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of kernel.unprivileged_bpf_disabled from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+kernel.unprivileged_bpf_disabled.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "kernel.unprivileged_bpf_disabled" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done

#
# Set runtime for kernel.unprivileged_bpf_disabled
#
/sbin/sysctl -q -n -w kernel.unprivileged_bpf_disabled="1"

#
# If kernel.unprivileged_bpf_disabled present in /etc/sysctl.conf, change value to "1"
#	else, add "kernel.unprivileged_bpf_disabled = 1" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^kernel.unprivileged_bpf_disabled")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "1"

# 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 -i -e "^kernel.unprivileged_bpf_disabled\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^kernel.unprivileged_bpf_disabled\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*kernel.unprivileged_bpf_disabled.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AC-6
    - NIST-800-53-SC-7(10)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_unprivileged_bpf_disabled

- name: Comment out any occurrences of kernel.unprivileged_bpf_disabled from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*kernel.unprivileged_bpf_disabled
    replace: '#kernel.unprivileged_bpf_disabled'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AC-6
    - NIST-800-53-SC-7(10)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_unprivileged_bpf_disabled

- name: Ensure sysctl kernel.unprivileged_bpf_disabled is set to 1
  sysctl:
    name: kernel.unprivileged_bpf_disabled
    value: '1'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-AC-6
    - NIST-800-53-SC-7(10)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_unprivileged_bpf_disabled

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,kernel.unprivileged_bpf_disabled%3D1%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_kernel_unprivileged_bpf_disabled.conf
        overwrite: true

Rule   Restrict usage of ptrace to descendant processes   [ref]

To set the runtime status of the kernel.yama.ptrace_scope kernel parameter, run the following command:
$ sudo sysctl -w kernel.yama.ptrace_scope=1
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
kernel.yama.ptrace_scope = 1
Rationale:
Unrestricted usage of ptrace allows compromised binaries to run ptrace on another processes of the user. Like this, the attacker can steal sensitive information from the target processes (e.g. SSH sessions, web browser, ...) without any additional assistance from the user (i.e. without resorting to phishing).
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_kernel_yama_ptrace_scope
Identifiers and References

References:  BP28(R25), CCI-000366, SC-7(10), SRG-OS-000132-GPOS-00067, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of kernel.yama.ptrace_scope from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+kernel.yama.ptrace_scope.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "kernel.yama.ptrace_scope" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done

#
# Set runtime for kernel.yama.ptrace_scope
#
/sbin/sysctl -q -n -w kernel.yama.ptrace_scope="1"

#
# If kernel.yama.ptrace_scope present in /etc/sysctl.conf, change value to "1"
#	else, add "kernel.yama.ptrace_scope = 1" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^kernel.yama.ptrace_scope")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "1"

# 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 -i -e "^kernel.yama.ptrace_scope\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^kernel.yama.ptrace_scope\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*kernel.yama.ptrace_scope.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-SC-7(10)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_yama_ptrace_scope

- name: Comment out any occurrences of kernel.yama.ptrace_scope from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*kernel.yama.ptrace_scope
    replace: '#kernel.yama.ptrace_scope'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-SC-7(10)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_yama_ptrace_scope

- name: Ensure sysctl kernel.yama.ptrace_scope is set to 1
  sysctl:
    name: kernel.yama.ptrace_scope
    value: '1'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-SC-7(10)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_kernel_yama_ptrace_scope

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,kernel.yama.ptrace_scope%3D1%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_kernel_yama_ptrace_scope.conf
        overwrite: true

Rule   Harden the operation of the BPF just-in-time compiler   [ref]

To set the runtime status of the net.core.bpf_jit_harden kernel parameter, run the following command:
$ sudo sysctl -w net.core.bpf_jit_harden=2
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
net.core.bpf_jit_harden = 2
Rationale:
When hardened, the extended Berkeley Packet Filter just-in-time compiler will randomize any kernel addresses in the BPF programs and maps, and will not expose the JIT addresses in /proc/kallsyms.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_net_core_bpf_jit_harden
Identifiers and References

References:  CCI-000366, CM-6, SC-7(10), FMT_SMF_EXT.1, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of net.core.bpf_jit_harden from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+net.core.bpf_jit_harden.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "net.core.bpf_jit_harden" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done

#
# Set runtime for net.core.bpf_jit_harden
#
/sbin/sysctl -q -n -w net.core.bpf_jit_harden="2"

#
# If net.core.bpf_jit_harden present in /etc/sysctl.conf, change value to "2"
#	else, add "net.core.bpf_jit_harden = 2" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^net.core.bpf_jit_harden")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "2"

# 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 -i -e "^net.core.bpf_jit_harden\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^net.core.bpf_jit_harden\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*net.core.bpf_jit_harden.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-CM-6
    - NIST-800-53-SC-7(10)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_net_core_bpf_jit_harden

- name: Comment out any occurrences of net.core.bpf_jit_harden from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*net.core.bpf_jit_harden
    replace: '#net.core.bpf_jit_harden'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-CM-6
    - NIST-800-53-SC-7(10)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_net_core_bpf_jit_harden

- name: Ensure sysctl net.core.bpf_jit_harden is set to 2
  sysctl:
    name: net.core.bpf_jit_harden
    value: '2'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-CM-6
    - NIST-800-53-SC-7(10)
    - disable_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - reboot_required
    - sysctl_net_core_bpf_jit_harden

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,net.core.bpf_jit_harden%3D2%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_net_core_bpf_jit_harden.conf
        overwrite: true

Rule   Disable the use of user namespaces   [ref]

To set the runtime status of the user.max_user_namespaces kernel parameter, run the following command:
$ sudo sysctl -w user.max_user_namespaces=0
To make sure that the setting is persistent, add the following line to a file in the directory /etc/sysctl.d:
user.max_user_namespaces = 0
When containers are deployed on the machine, the value should be set to large non-zero value.
Warning:  This configuration baseline was created to deploy the base operating system for general purpose workloads. When the operating system is configured for certain purposes, such as to host Linux Containers, it is expected that user.max_user_namespaces will be enabled.
Rationale:
User namespaces are used primarily for Linux containers. The value 0 disallows the use of user namespaces.
Severity: 
info
Rule ID:xccdf_org.ssgproject.content_rule_sysctl_user_max_user_namespaces
Identifiers and References

References:  CCI-000366, SC-39, CM-6(a), FMT_SMF_EXT.1, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# Comment out any occurrences of user.max_user_namespaces from /etc/sysctl.d/*.conf files
for f in /etc/sysctl.d/*.conf ; do
  matching_list=$(grep -P '^(?!#).*[\s]+user.max_user_namespaces.*$' $f | uniq )
  if ! test -z "$matching_list"; then
    while IFS= read -r entry; do
      # comment out "user.max_user_namespaces" matches to preserve user data
      sed -i "s/^${entry}$/# &/g" $f
    done <<< "$matching_list"
  fi
done

#
# Set runtime for user.max_user_namespaces
#
/sbin/sysctl -q -n -w user.max_user_namespaces="0"

#
# If user.max_user_namespaces present in /etc/sysctl.conf, change value to "0"
#	else, add "user.max_user_namespaces = 0" to /etc/sysctl.conf
#
# 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 "/etc/sysctl.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^user.max_user_namespaces")

# shellcheck disable=SC2059
printf -v formatted_output "%s = %s" "$stripped_key" "0"

# 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 -i -e "^user.max_user_namespaces\\>" "/etc/sysctl.conf"; then
    "${sed_command[@]}" "s/^user.max_user_namespaces\\>.*/$formatted_output/gi" "/etc/sysctl.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/sysctl.conf"
fi

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

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
- name: List /etc/sysctl.d/*.conf files
  find:
    paths: /etc/sysctl.d/
    contains: ^[\s]*user.max_user_namespaces.*$
    patterns: '*.conf'
  register: find_sysctl_d
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SC-39
    - disable_strategy
    - low_complexity
    - low_severity
    - medium_disruption
    - reboot_required
    - sysctl_user_max_user_namespaces

- name: Comment out any occurrences of user.max_user_namespaces from /etc/sysctl.d/*.conf
    files
  replace:
    path: '{{ item }}'
    regexp: ^[\s]*user.max_user_namespaces
    replace: '#user.max_user_namespaces'
  loop: '{{ find_sysctl_d.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SC-39
    - disable_strategy
    - low_complexity
    - low_severity
    - medium_disruption
    - reboot_required
    - sysctl_user_max_user_namespaces

- name: Ensure sysctl user.max_user_namespaces is set to 0
  sysctl:
    name: user.max_user_namespaces
    value: '0'
    state: present
    reload: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SC-39
    - disable_strategy
    - low_complexity
    - low_severity
    - medium_disruption
    - reboot_required
    - sysctl_user_max_user_namespaces

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,user.max_user_namespaces%20%3D%200%0A
        mode: 0644
        path: /etc/sysctl.d/75-sysctl_user_max_user_namespaces.conf
        overwrite: true
Group   SELinux   Group contains 4 rules
[ref]   SELinux is a feature of the Linux kernel which can be used to guard against misconfigured or compromised programs. SELinux enforces the idea that programs should be limited in what files they can access and what actions they can take.

The default SELinux policy, as configured on AlmaLinux 9, has been sufficiently developed and debugged that it should be usable on almost any system with minimal configuration and a small amount of system administrator training. This policy prevents system services - including most of the common network-visible services such as mail servers, FTP servers, and DNS servers - from accessing files which those services have no valid reason to access. This action alone prevents a huge amount of possible damage from network attacks against services, from trojaned software, and so forth.

This guide recommends that SELinux be enabled using the default (targeted) policy on every AlmaLinux 9 system, unless that system has unusual requirements which make a stronger policy appropriate.

Rule   Install policycoreutils-python-utils package   [ref]

The policycoreutils-python-utils package can be installed with the following command:
$ sudo dnf install policycoreutils-python-utils
Rationale:
This package is required to operate and manage an SELinux environment and its policies. It provides utilities such as semanage, audit2allow, audit2why, chcat and sandbox.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_policycoreutils-python-utils_installed
Identifiers and References

References:  SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:low
Strategy:enable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if ! rpm -q --quiet "policycoreutils-python-utils" ; then
    dnf install -y "policycoreutils-python-utils"
fi

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

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure policycoreutils-python-utils is installed
  package:
    name: policycoreutils-python-utils
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_policycoreutils-python-utils_installed

Complexity:low
Disruption:low
Strategy:enable
include install_policycoreutils-python-utils

class install_policycoreutils-python-utils {
  package { 'policycoreutils-python-utils':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=policycoreutils-python-utils


[[packages]]
name = "policycoreutils-python-utils"
version = "*"

Rule   Install policycoreutils Package   [ref]

The policycoreutils package can be installed with the following command:
$ sudo dnf install policycoreutils
Rationale:
Security-enhanced Linux is a feature of the Linux kernel and a number of utilities with enhanced security functionality designed to add mandatory access controls to Linux. The Security-enhanced Linux kernel contains new architectural components originally developed to improve security of the Flask operating system. These architectural components provide general support for the enforcement of many kinds of mandatory access control policies, including those based on the concepts of Type Enforcement, Role-based Access Control, and Multi-level Security. policycoreutils contains the policy core utilities that are required for basic operation of an SELinux-enabled system. These utilities include load_policy to load SELinux policies, setfiles to label filesystems, newrole to switch roles, and so on.
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_package_policycoreutils_installed
Identifiers and References

References:  CCI-001084, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:low
Strategy:enable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if ! rpm -q --quiet "policycoreutils" ; then
    dnf install -y "policycoreutils"
fi

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

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure policycoreutils is installed
  package:
    name: policycoreutils
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - enable_strategy
    - high_severity
    - low_complexity
    - low_disruption
    - no_reboot_needed
    - package_policycoreutils_installed

Complexity:low
Disruption:low
Strategy:enable
include install_policycoreutils

class install_policycoreutils {
  package { 'policycoreutils':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=policycoreutils


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

Rule   Configure SELinux Policy   [ref]

The SELinux targeted policy is appropriate for general-purpose desktops and servers, as well as systems in many other roles. To configure the system to use this policy, add or correct the following line in /etc/selinux/config:
SELINUXTYPE=targeted
Other policies, such as mls, provide additional security labeling and greater confinement but are not compatible with many general-purpose use cases.
Rationale:
Setting the SELinux policy to targeted or a more specialized policy ensures the system will confine processes that are likely to be targeted for exploitation, such as network or system services.

Note: During the development or debugging of SELinux modules, it is common to temporarily place non-production systems in permissive mode. In such temporary cases, SELinux policies should be developed, and once work is completed, the system should be reconfigured to targeted.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_selinux_policytype
Identifiers and References

References:  BP28(R66), 1, 11, 12, 13, 14, 15, 16, 18, 3, 4, 5, 6, 8, 9, APO01.06, APO11.04, APO13.01, BAI03.05, DSS01.05, DSS03.01, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.03, DSS06.06, MEA02.01, 3.1.2, 3.7.2, CCI-002165, CCI-002696, 164.308(a)(1)(ii)(D), 164.308(a)(3), 164.308(a)(4), 164.310(b), 164.310(c), 164.312(a), 164.312(e), 4.2.3.4, 4.3.3.2.2, 4.3.3.3.9, 4.3.3.4, 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.4.7, 4.4.2.1, 4.4.2.2, 4.4.2.4, 4.4.3.3, 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.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, 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.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.1, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.2, CIP-003-8 R5.3, CIP-004-6 R2.2.3, CIP-004-6 R2.3, CIP-004-6 R3.3, CIP-007-3 R5.1, CIP-007-3 R5.1.2, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, CIP-007-3 R6.5, AC-3, AC-3(3)(a), AU-9, SC-7(21), DE.AE-1, ID.AM-3, PR.AC-4, PR.AC-5, PR.AC-6, PR.DS-5, PR.PT-1, PR.PT-3, PR.PT-4, SRG-OS-000445-GPOS-00199, SRG-OS-000445-VMM-001780


Complexity:low
Disruption:low
Reboot:true
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

var_selinux_policy_name='targeted'


if [ -e "/etc/selinux/config" ] ; then
    
    LC_ALL=C sed -i "/^SELINUXTYPE=/Id" "/etc/selinux/config"
else
    touch "/etc/selinux/config"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/selinux/config"

cp "/etc/selinux/config" "/etc/selinux/config.bak"
# Insert at the end of the file
printf '%s\n' "SELINUXTYPE=$var_selinux_policy_name" >> "/etc/selinux/config"
# Clean up after ourselves.
rm "/etc/selinux/config.bak"

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

Complexity:low
Disruption:low
Reboot:true
Strategy:restrict
- name: XCCDF Value var_selinux_policy_name # promote to variable
  set_fact:
    var_selinux_policy_name: !!str targeted
  tags:
    - always

- name: Configure SELinux Policy
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/selinux/config
        create: false
        regexp: ^SELINUXTYPE=
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/selinux/config
      lineinfile:
        path: /etc/selinux/config
        create: false
        regexp: ^SELINUXTYPE=
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/selinux/config
      lineinfile:
        path: /etc/selinux/config
        create: true
        regexp: ^SELINUXTYPE=
        line: SELINUXTYPE={{ var_selinux_policy_name }}
        state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.2
    - NIST-800-171-3.7.2
    - NIST-800-53-AC-3
    - NIST-800-53-AC-3(3)(a)
    - NIST-800-53-AU-9
    - NIST-800-53-SC-7(21)
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy
    - selinux_policytype

Rule   Ensure SELinux State is Enforcing   [ref]

The SELinux state should be set to enforcing at system boot time. In the file /etc/selinux/config, add or correct the following line to configure the system to boot into enforcing mode:
SELINUX=enforcing
Rationale:
Setting the SELinux state to enforcing ensures SELinux is able to confine potentially compromised processes to the security policy, which is designed to prevent them from causing damage to the system or further elevating their privileges.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_selinux_state
Identifiers and References

References:  BP28(R4), BP28(R66), 1, 11, 12, 13, 14, 15, 16, 18, 3, 4, 5, 6, 8, 9, APO01.06, APO11.04, APO13.01, BAI03.05, DSS01.05, DSS03.01, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.03, DSS06.06, MEA02.01, 3.1.2, 3.7.2, CCI-002165, CCI-002696, 164.308(a)(1)(ii)(D), 164.308(a)(3), 164.308(a)(4), 164.310(b), 164.310(c), 164.312(a), 164.312(e), 4.2.3.4, 4.3.3.2.2, 4.3.3.3.9, 4.3.3.4, 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.4.7, 4.4.2.1, 4.4.2.2, 4.4.2.4, 4.4.3.3, 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.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.1, A.12.1.2, 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.1.2, A.13.1.3, A.13.2.1, A.13.2.2, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.1, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.2, CIP-003-8 R5.3, CIP-004-6 R2.2.3, CIP-004-6 R2.3, CIP-004-6 R3.3, CIP-007-3 R5.1, CIP-007-3 R5.1.2, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, CIP-007-3 R6.5, AC-3, AC-3(3)(a), AU-9, SC-7(21), DE.AE-1, ID.AM-3, PR.AC-4, PR.AC-5, PR.AC-6, PR.DS-5, PR.PT-1, PR.PT-3, PR.PT-4, SRG-OS-000445-GPOS-00199, SRG-OS-000445-VMM-001780


Complexity:low
Disruption:low
Reboot:true
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

var_selinux_state='enforcing'


if [ -e "/etc/selinux/config" ] ; then
    
    LC_ALL=C sed -i "/^SELINUX=/Id" "/etc/selinux/config"
else
    touch "/etc/selinux/config"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/selinux/config"

cp "/etc/selinux/config" "/etc/selinux/config.bak"
# Insert at the end of the file
printf '%s\n' "SELINUX=$var_selinux_state" >> "/etc/selinux/config"
# Clean up after ourselves.
rm "/etc/selinux/config.bak"

fixfiles onboot
fixfiles -f relabel

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

Complexity:low
Disruption:low
Strategy:restrict
- name: XCCDF Value var_selinux_state # promote to variable
  set_fact:
    var_selinux_state: !!str enforcing
  tags:
    - always

- name: Ensure SELinux State is Enforcing
  block:

    - name: Check for duplicate values
      lineinfile:
        path: /etc/selinux/config
        create: false
        regexp: ^SELINUX=
        state: absent
      check_mode: true
      changed_when: false
      register: dupes

    - name: Deduplicate values from /etc/selinux/config
      lineinfile:
        path: /etc/selinux/config
        create: false
        regexp: ^SELINUX=
        state: absent
      when: dupes.found is defined and dupes.found > 1

    - name: Insert correct line to /etc/selinux/config
      lineinfile:
        path: /etc/selinux/config
        create: true
        regexp: ^SELINUX=
        line: SELINUX={{ var_selinux_state }}
        state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-171-3.1.2
    - NIST-800-171-3.7.2
    - NIST-800-53-AC-3
    - NIST-800-53-AC-3(3)(a)
    - NIST-800-53-AU-9
    - NIST-800-53-SC-7(21)
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - selinux_state
Group   Services   Group contains 10 groups and 24 rules
[ref]   The best protection against vulnerable software is running less software. This section describes how to review the software which AlmaLinux 9 installs on a system and disable software which is not needed. It then enumerates the software packages installed on a default AlmaLinux 9 system and provides guidance about which ones can be safely disabled.

AlmaLinux 9 provides a convenient minimal install option that essentially installs the bare necessities for a functional system. When building AlmaLinux 9 systems, it is highly recommended to select the minimal packages and then build up the system from there.
Group   Base Services   Group contains 1 rule
[ref]   This section addresses the base services that are installed on a AlmaLinux 9 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.

Rule   Disable KDump Kernel Crash Analyzer (kdump)   [ref]

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.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_service_kdump_disabled
Identifiers and References

References:  11, 12, 14, 15, 3, 8, 9, APO13.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.04, DSS05.02, DSS05.03, DSS05.05, DSS06.06, CCI-000366, 164.308(a)(1)(ii)(D), 164.308(a)(3), 164.308(a)(4), 164.310(b), 164.310(c), 164.312(a), 164.312(e), 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, 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.5.1, A.12.6.2, 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.6.2.1, A.6.2.2, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.AC-3, PR.IP-1, PR.PT-3, PR.PT-4, FMT_SMF_EXT.1.1, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:low
Strategy:disable
# 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

Complexity:low
Disruption:low
Strategy:disable
- name: Disable service kdump
  block:

    - name: Disable service kdump
      systemd:
        name: kdump.service
        enabled: 'no'
        state: stopped
        masked: 'yes'
      ignore_errors: 'yes'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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:
    - 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:
    - 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

Complexity:low
Disruption:low
Strategy:enable
include disable_kdump

class disable_kdump {
  service {'kdump':
    enable => false,
    ensure => 'stopped',
  }
}


kdump --disable

Complexity:low
Disruption:medium
Reboot:true
Strategy:disable
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    systemd:
      units:
      - name: kdump.service
        enabled: false
        mask: true
      - name: kdump.socket
        enabled: false
        mask: true


[customizations.services]
disabled = ["kdump"]
Group   Application Whitelisting Daemon   Group contains 2 rules
[ref]   Fapolicyd (File Access Policy Daemon) implements application whitelisting to decide file access rights. Applications that are known via a reputation source are allowed access while unknown applications are not. The daemon makes use of the kernel's fanotify interface to determine file access rights.

Rule   Install fapolicyd Package   [ref]

The fapolicyd package can be installed with the following command:
$ sudo dnf install fapolicyd
Rationale:
fapolicyd (File Access Policy Daemon) implements application whitelisting to decide file access rights.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_fapolicyd_installed
Identifiers and References

References:  CCI-001764, CM-6(a), SI-4(22), SRG-OS-000370-GPOS-00155, SRG-OS-000368-GPOS-00154


Complexity:low
Disruption:low
Strategy:enable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if ! rpm -q --quiet "fapolicyd" ; then
    dnf install -y "fapolicyd"
fi

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

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure fapolicyd is installed
  package:
    name: fapolicyd
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SI-4(22)
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_fapolicyd_installed

Complexity:low
Disruption:low
Strategy:enable
include install_fapolicyd

class install_fapolicyd {
  package { 'fapolicyd':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=fapolicyd


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

Rule   Enable the File Access Policy Service   [ref]

The File Access Policy service should be enabled. The fapolicyd service can be enabled with the following command:
$ sudo systemctl enable fapolicyd.service
Rationale:
The fapolicyd service (File Access Policy Daemon) implements application whitelisting to decide file access rights.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_service_fapolicyd_enabled
Identifiers and References

References:  CCI-001764, CM-6(a), SI-4(22), FMT_SMF_EXT.1, SRG-OS-000370-GPOS-00155, SRG-OS-000368-GPOS-00154


Complexity:low
Disruption:low
Strategy:enable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

SYSTEMCTL_EXEC='/usr/bin/systemctl'
"$SYSTEMCTL_EXEC" unmask 'fapolicyd.service'
"$SYSTEMCTL_EXEC" start 'fapolicyd.service'
"$SYSTEMCTL_EXEC" enable 'fapolicyd.service'

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

Complexity:low
Disruption:low
Strategy:enable
- name: Enable service fapolicyd
  block:

    - name: Gather the package facts
      package_facts:
        manager: auto

    - name: Enable service fapolicyd
      service:
        name: fapolicyd
        enabled: 'yes'
        state: started
        masked: 'no'
      when:
        - '"fapolicyd" in ansible_facts.packages'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SI-4(22)
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_fapolicyd_enabled

Complexity:low
Disruption:low
Strategy:enable
include enable_fapolicyd

class enable_fapolicyd {
  service {'fapolicyd':
    enable => true,
    ensure => 'running',
  }
}


[customizations.services]
enabled = ["fapolicyd"]
Group   Kerberos   Group contains 1 rule
[ref]   The Kerberos protocol is used for authentication across non-secure network. Authentication can happen between various types of principals -- users, service, or hosts. Their identity and encryption keys can be stored in keytab files.

Rule   Disable Kerberos by removing host keytab   [ref]

Kerberos is not an approved key distribution method for Common Criteria. To prevent using Kerberos by system daemons, remove the Kerberos keytab files, especially /etc/krb5.keytab.
Rationale:
The key derivation function (KDF) in Kerberos is not FIPS compatible.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_kerberos_disable_no_keytab
Identifiers and References

References:  CCI-000803, 0418, 1055, 1402, FTP_ITC_EXT.1, SRG-OS-000120-GPOS-00061


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

rm -f /etc/*.keytab

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
Group   Mail Server Software   Group contains 1 rule
[ref]   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 AlmaLinux 9 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.

Rule   Uninstall Sendmail Package   [ref]

Sendmail is not the default mail transfer agent and is not installed by default. The sendmail package can be removed with the following command:
$ sudo dnf erase sendmail
Rationale:
The sendmail software was not developed with security in mind and its design prevents it from being effectively contained by SELinux. Postfix should be used instead.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_sendmail_removed
Identifiers and References

References:  BP28(R1), 11, 14, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.05, DSS06.06, CCI-000381, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.9.1.2, CM-7(a), CM-7(b), CM-6(a), PR.IP-1, PR.PT-3, SRG-OS-000480-GPOS-00227, SRG-OS-000095-GPOS-00049


Complexity:low
Disruption:low
Strategy:disable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

# CAUTION: This remediation script will remove sendmail
#	   from the system, and may remove any packages
#	   that depend on sendmail. Execute this
#	   remediation AFTER testing on a non-production
#	   system!

if rpm -q --quiet "sendmail" ; then

    dnf remove -y "sendmail"

fi

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

Complexity:low
Disruption:low
Strategy:disable
- name: Ensure sendmail is removed
  package:
    name: sendmail
    state: absent
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - 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
    - package_sendmail_removed

Complexity:low
Disruption:low
Strategy:disable
include remove_sendmail

class remove_sendmail {
  package { 'sendmail':
    ensure => 'purged',
  }
}

Complexity:low
Disruption:low
Strategy:disable

package --remove=sendmail
Group   NFS and RPC   Group contains 1 rule
[ref]   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.

Rule   Uninstall nfs-utils Package   [ref]

The nfs-utils package can be removed with the following command:
$ sudo dnf erase nfs-utils
Rationale:
nfs-utils provides a daemon for the kernel NFS server and related tools. This package also contains the showmount program. showmount queries the mount daemon on a remote host for information about the Network File System (NFS) server on the remote host. For example, showmount can display the clients which are mounted on that host.
Severity: 
low
Rule ID:xccdf_org.ssgproject.content_rule_package_nfs-utils_removed
Identifiers and References

References:  SRG-OS-000095-GPOS-00049


Complexity:low
Disruption:low
Strategy:disable

# CAUTION: This remediation script will remove nfs-utils
#	   from the system, and may remove any packages
#	   that depend on nfs-utils. Execute this
#	   remediation AFTER testing on a non-production
#	   system!

if rpm -q --quiet "nfs-utils" ; then

    dnf remove -y "nfs-utils"

fi

Complexity:low
Disruption:low
Strategy:disable
- name: Ensure nfs-utils is removed
  package:
    name: nfs-utils
    state: absent
  tags:
    - disable_strategy
    - low_complexity
    - low_disruption
    - low_severity
    - no_reboot_needed
    - package_nfs-utils_removed

Complexity:low
Disruption:low
Strategy:disable
include remove_nfs-utils

class remove_nfs-utils {
  package { 'nfs-utils':
    ensure => 'purged',
  }
}

Complexity:low
Disruption:low
Strategy:disable

package --remove=nfs-utils
Group   Network Time Protocol   Group contains 2 rules
[ref]   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.

Rule   The Chrony package is installed   [ref]

System time should be synchronized between all systems in an environment. This is typically done by establishing an authoritative time server or set of servers and having all systems synchronize their clocks to them. The chrony package can be installed with the following command:
$ sudo dnf install chrony
Rationale:
Time synchronization is important to support time sensitive security mechanisms like Kerberos and also ensures log files have consistent time records across the enterprise, which aids in forensic investigations.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_chrony_installed
Identifiers and References

References:  BP28(R43), 0988, 1405, FMT_SMF_EXT.1, SRG-OS-000355-GPOS-00143


Complexity:low
Disruption:low
Strategy:enable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if ! rpm -q --quiet "chrony" ; then
    dnf install -y "chrony"
fi

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

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure chrony is installed
  package:
    name: chrony
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_chrony_installed

Complexity:low
Disruption:low
Strategy:enable
include install_chrony

class install_chrony {
  package { 'chrony':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=chrony


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

Rule   Disable chrony daemon from acting as server   [ref]

The port option in /etc/chrony.conf can be set to 0 to make chrony daemon to never open any listening port for server operation and to operate strictly in a client-only mode.
Rationale:
Minimizing the exposure of the server functionality of the chrony daemon diminishes the attack surface.
Severity: 
low
Rule ID:xccdf_org.ssgproject.content_rule_chronyd_client_only
Identifiers and References

References:  CCI-000381, AU-8(1), FMT_SMF_EXT.1, SRG-OS-000096-GPOS-00050, SRG-OS-000095-GPOS-00049


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

# 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 "/etc/chrony.conf"; then
    sed_command+=('--follow-symlinks')
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' <<< "^port")

# shellcheck disable=SC2059
printf -v formatted_output "%s %s" "$stripped_key" "0"

# 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 -i -e "^port\\>" "/etc/chrony.conf"; then
    "${sed_command[@]}" "s/^port\\>.*/$formatted_output/gi" "/etc/chrony.conf"
else
    # \n is precaution for case where file ends without trailing newline
    
    printf '%s\n' "$formatted_output" >> "/etc/chrony.conf"
fi

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

Complexity:low
Disruption:low
Reboot:true
Strategy:restrict
---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,{{ %23%20Allow%20for%20extra%20configuration%20files.%20This%20is%20useful%0A%23%20for%20admins%20specifying%20their%20own%20NTP%20servers%0Ainclude%20/etc/chrony.d/%2A.conf%0A%0A%23%20Set%20chronyd%20as%20client-only.%0Aport%200%0A%0A%23%20Disable%20chronyc%20from%20the%20network%0Acmdport%200%0A%0A%23%20Record%20the%20rate%20at%20which%20the%20system%20clock%20gains/losses%20time.%0Adriftfile%20/var/lib/chrony/drift%0A%0A%23%20Allow%20the%20system%20clock%20to%20be%20stepped%20in%20the%20first%20three%20updates%0A%23%20if%20its%20offset%20is%20larger%20than%201%20second.%0Amakestep%201.0%203%0A%0A%23%20Enable%20kernel%20synchronization%20of%20the%20real-time%20clock%20%28RTC%29.%0Artcsync%0A%0A%23%20Enable%20hardware%20timestamping%20on%20all%20interfaces%20that%20support%20it.%0A%23hwtimestamp%20%2A%0A%0A%23%20Increase%20the%20minimum%20number%20of%20selectable%20sources%20required%20to%20adjust%0A%23%20the%20system%20clock.%0A%23minsources%202%0A%0A%23%20Allow%20NTP%20client%20access%20from%20local%20network.%0A%23allow%20192.168.0.0/16%0A%0A%23%20Serve%20time%20even%20if%20not%20synchronized%20to%20a%20time%20source.%0A%23local%20stratum%2010%0A%0A%23%20Require%20authentication%20%28nts%20or%20key%20option%29%20for%20all%20NTP%20sources.%0A%23authselectmode%20require%0A%0A%23%20Specify%20file%20containing%20keys%20for%20NTP%20authentication.%0Akeyfile%20/etc/chrony.keys%0A%0A%23%20Insert/delete%20leap%20seconds%20by%20slewing%20instead%20of%20stepping.%0A%23leapsecmode%20slew%0A%0A%23%20Get%20TAI-UTC%20offset%20and%20leap%20seconds%20from%20the%20system%20tz%20database.%0Aleapsectz%20right/UTC%0A%0A%23%20Specify%20directory%20for%20log%20files.%0Alogdir%20/var/log/chrony%0A%0A%23%20Select%20which%20information%20is%20logged.%0A%23log%20measurements%20statistics%20tracking }}
        mode: 420
        overwrite: true
        path: /etc/chrony.conf
      - contents:
          source: data:,
        mode: 420
        overwrite: true
        path: /etc/chrony.d/.mco-keep
      - contents:
          source: data:,{{ %23%0A%23%20This%20file%20controls%20the%20configuration%20of%20the%20ntp%20server%0A%23%20%7B%7B.var_multiple_time_servers%7D%7D%20we%20have%20to%20put%20variable%20array%20name%20here%20for%20mutilines%20remediation%20%0A%7B%7B%24var_time_service_set_maxpoll%3A%3D.var_time_service_set_maxpoll%7D%7D%0A%7B%7Brange%20%24element%3A%3D.var_multiple_time_servers%7CtoArrayByComma%7D%7Dserver%20%7B%7B%24element%7D%7D%20minpoll%204%20maxpoll%20%7B%7B%24var_time_service_set_maxpoll%7D%7D%0A%7B%7Bend%7D%7D }}
        mode: 420
        overwrite: true
        path: /etc/chrony.d/ntp-server.conf
Group   SSH Server   Group contains 2 groups and 12 rules
[ref]   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.
Group   Configure OpenSSH Client if Necessary   Group contains 1 rule
[ref]   The following configuration changes apply to the SSH client. They can improve security parameters relwevant to the client user, e.g. increasing entropy while generating initialization vectors. Note that these changes influence only the default SSH client configuration. Changes in this group can be overridden by the client user by modifying files within the
~/.ssh
directory or by supplying parameters on the command line.

Rule   Configure session renegotiation for SSH client   [ref]

The RekeyLimit parameter specifies how often the session key is renegotiated, both in terms of amount of data that may be transmitted and the time elapsed. To decrease the default limits, put line RekeyLimit 1G 1h to file /etc/ssh/ssh_config.d/02-rekey-limit.conf. Make sure that there is no other RekeyLimit configuration preceding the include directive in the main config file /etc/ssh/ssh_config. Check also other files in /etc/ssh/ssh_config.d directory. Files are processed according to lexicographical order of file names. Make sure that there is no file processed before 02-rekey-limit.conf containing definition of RekeyLimit.
Rationale:
By decreasing the limit based on the amount of data and enabling time-based limit, effects of potential attacks against encryption keys are limited.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_ssh_client_rekey_limit
Identifiers and References

References:  CCI-000068, FCS_SSHS_EXT.1, SRG-OS-000423-GPOS-00187, SRG-OS-000033-GPOS-00014


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

var_ssh_client_rekey_limit_size='1G'
var_ssh_client_rekey_limit_time='1h'


main_config="/etc/ssh/ssh_config"
include_directory="/etc/ssh/ssh_config.d"

if grep -q '^[\s]*RekeyLimit.*$' "$main_config"; then
  sed -i '/^[\s]*RekeyLimit.*/d' "$main_config"
fi

for file in "$include_directory"/*.conf; do
  if grep -q '^[\s]*RekeyLimit.*$' "$file"; then
    sed -i '/^[\s]*RekeyLimit.*/d' "$file"
  fi
done

if [ -e "/etc/ssh/ssh_config.d/02-rekey-limit.conf" ] ; then
    
    LC_ALL=C sed -i "/^\s*RekeyLimit\s\+/d" "/etc/ssh/ssh_config.d/02-rekey-limit.conf"
else
    touch "/etc/ssh/ssh_config.d/02-rekey-limit.conf"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/ssh/ssh_config.d/02-rekey-limit.conf"

cp "/etc/ssh/ssh_config.d/02-rekey-limit.conf" "/etc/ssh/ssh_config.d/02-rekey-limit.conf.bak"
# Insert at the end of the file
printf '%s\n' "RekeyLimit $var_ssh_client_rekey_limit_size $var_ssh_client_rekey_limit_time" >> "/etc/ssh/ssh_config.d/02-rekey-limit.conf"
# Clean up after ourselves.
rm "/etc/ssh/ssh_config.d/02-rekey-limit.conf.bak"

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

Complexity:low
Disruption:low
Strategy:configure
- name: XCCDF Value var_ssh_client_rekey_limit_size # promote to variable
  set_fact:
    var_ssh_client_rekey_limit_size: !!str 1G
  tags:
    - always
- name: XCCDF Value var_ssh_client_rekey_limit_time # promote to variable
  set_fact:
    var_ssh_client_rekey_limit_time: !!str 1h
  tags:
    - always

- name: Ensure RekeyLimit is not configured in /etc/ssh/ssh_config
  lineinfile:
    path: /etc/ssh/ssh_config
    create: false
    regexp: ^\s*RekeyLimit.*$
    state: absent
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - ssh_client_rekey_limit

- name: Collect all include config files for ssh client which configure RekeyLimit
  find:
    paths: /etc/ssh/ssh_config.d/
    contains: ^[\s]*RekeyLimit.*$
    patterns: '*.config'
  register: ssh_config_include_files
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - ssh_client_rekey_limit

- name: Remove all occurences of RekeyLimit configuration from include config files
    of ssh client
  lineinfile:
    path: '{{ item }}'
    regexp: ^[\s]*RekeyLimit.*$
    state: absent
  loop: '{{ ssh_config_include_files.files }}'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - ssh_client_rekey_limit

- name: Ensure that rekey limit is set to {{ var_ssh_client_rekey_limit_size }} {{
    var_ssh_client_rekey_limit_time }} in /etc/ssh/ssh_config.d/02-rekey-limit.conf
  lineinfile:
    path: /etc/ssh/ssh_config.d/02-rekey-limit.conf
    create: true
    regexp: ^\s*RekeyLimit.*$
    line: RekeyLimit {{ var_ssh_client_rekey_limit_size }} {{ var_ssh_client_rekey_limit_time
      }}
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - ssh_client_rekey_limit
Group   Configure OpenSSH Server if Necessary   Group contains 9 rules
[ref]   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.

Rule   Disable Host-Based Authentication   [ref]

SSH's cryptographic host-based authentication is more secure than .rhosts authentication. However, it is not recommended that hosts unilaterally trust one another, even within an organization.
The default SSH configuration disables host-based authentication. The appropriate configuration is used if no value is set for HostbasedAuthentication.
To explicitly disable host-based authentication, add or correct the following line in /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf:
HostbasedAuthentication no
Rationale:
SSH trust relationships mean a compromise on one host can allow an attacker to move trivially to other hosts.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_disable_host_auth
Identifiers and References

References:  11, 12, 14, 15, 16, 18, 3, 5, 9, 5.5.6, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.03, DSS06.06, 3.1.12, CCI-000366, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.3.2.2, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 7.6, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.6.1.2, A.7.1.1, A.9.1.2, A.9.2.1, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.2.3, CIP-004-6 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.2, CIP-007-3 R5.2, CIP-007-3 R5.3.1, CIP-007-3 R5.3.2, CIP-007-3 R5.3.3, AC-3, AC-17(a), CM-7(a), CM-7(b), CM-6(a), PR.AC-4, PR.AC-6, PR.IP-1, PR.PT-3, FIA_UAU.1, SRG-OS-000480-GPOS-00229, SRG-OS-000480-VMM-002000


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

mkdir -p /etc/ssh/sshd_config.d
touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf

LC_ALL=C sed -i "/^\s*HostbasedAuthentication\s\+/Id" "/etc/ssh/sshd_config"
LC_ALL=C sed -i "/^\s*HostbasedAuthentication\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf
if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then
    
    LC_ALL=C sed -i "/^\s*HostbasedAuthentication\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
else
    touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"

cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"
# Insert before the line matching the regex '^Match'.
line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.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' "HostbasedAuthentication no" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
else
    head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    printf '%s\n' "HostbasedAuthentication no" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
fi
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Disable Host-Based Authentication
  block:

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: ^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+
        state: absent

    - name: Check if /etc/ssh/sshd_config.d exists
      stat:
        path: /etc/ssh/sshd_config.d
      register: _etc_ssh_sshd_config_d_exists

    - name: Check if the parameter HostbasedAuthentication is present in /etc/ssh/sshd_config.d
      find:
        paths: /etc/ssh/sshd_config.d
        recurse: 'yes'
        follow: 'no'
        contains: ^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+
      register: _etc_ssh_sshd_config_d_has_parameter
      when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir

    - name: Remove parameter from files in /etc/ssh/sshd_config.d
      lineinfile:
        path: '{{ item.path }}'
        create: false
        regexp: ^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+
        state: absent
      with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}'
      when: _etc_ssh_sshd_config_d_has_parameter.matched

    - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
      lineinfile:
        path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
        create: true
        regexp: ^\s*{{ "HostbasedAuthentication"| regex_escape }}\s+
        line: HostbasedAuthentication 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:
    - CJIS-5.5.6
    - NIST-800-171-3.1.12
    - NIST-800-53-AC-17(a)
    - NIST-800-53-AC-3
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-7(a)
    - NIST-800-53-CM-7(b)
    - disable_host_auth
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,%23%09%24OpenBSD%3A%20sshd_config%2Cv%201.103%202018%2F04%2F09%2020%3A41%3A22%20tj%20Exp%20%24%0A%0A%23%20This%20is%20the%20sshd%20server%20system-wide%20configuration%20file.%20%20See%0A%23%20sshd_config%285%29%20for%20more%20information.%0A%0A%23%20This%20sshd%20was%20compiled%20with%20PATH%3D%2Fusr%2Flocal%2Fbin%3A%2Fusr%2Fbin%3A%2Fusr%2Flocal%2Fsbin%3A%2Fusr%2Fsbin%0A%0A%23%20The%20strategy%20used%20for%20options%20in%20the%20default%20sshd_config%20shipped%20with%0A%23%20OpenSSH%20is%20to%20specify%20options%20with%20their%20default%20value%20where%0A%23%20possible%2C%20but%20leave%20them%20commented.%20%20Uncommented%20options%20override%20the%0A%23%20default%20value.%0A%0A%23%20If%20you%20want%20to%20change%20the%20port%20on%20a%20SELinux%20system%2C%20you%20have%20to%20tell%0A%23%20SELinux%20about%20this%20change.%0A%23%20semanage%20port%20-a%20-t%20ssh_port_t%20-p%20tcp%20%23PORTNUMBER%0A%23%0A%23Port%2022%0A%23AddressFamily%20any%0A%23ListenAddress%200.0.0.0%0A%23ListenAddress%20%3A%3A%0A%0AHostKey%20%2Fetc%2Fssh%2Fssh_host_rsa_key%0AHostKey%20%2Fetc%2Fssh%2Fssh_host_ecdsa_key%0AHostKey%20%2Fetc%2Fssh%2Fssh_host_ed25519_key%0A%0A%23%20Ciphers%20and%20keying%0ARekeyLimit%20512M%201h%0A%0A%23%20System-wide%20Crypto%20policy%3A%0A%23%20This%20system%20is%20following%20system-wide%20crypto%20policy.%20The%20changes%20to%0A%23%20Ciphers%2C%20MACs%2C%20KexAlgoritms%20and%20GSSAPIKexAlgorithsm%20will%20not%20have%20any%0A%23%20effect%20here.%20They%20will%20be%20overridden%20by%20command-line%20options%20passed%20on%0A%23%20the%20server%20start%20up.%0A%23%20To%20opt%20out%2C%20uncomment%20a%20line%20with%20redefinition%20of%20%20CRYPTO_POLICY%3D%0A%23%20variable%20in%20%20%2Fetc%2Fsysconfig%2Fsshd%20%20to%20overwrite%20the%20policy.%0A%23%20For%20more%20information%2C%20see%20manual%20page%20for%20update-crypto-policies%288%29.%0A%0A%23%20Logging%0A%23SyslogFacility%20AUTH%0ASyslogFacility%20AUTHPRIV%0A%23LogLevel%20INFO%0A%0A%23%20Authentication%3A%0A%0A%23LoginGraceTime%202m%0APermitRootLogin%20no%0AStrictModes%20yes%0A%23MaxAuthTries%206%0A%23MaxSessions%2010%0A%0APubkeyAuthentication%20yes%0A%0A%23%20The%20default%20is%20to%20check%20both%20.ssh%2Fauthorized_keys%20and%20.ssh%2Fauthorized_keys2%0A%23%20but%20this%20is%20overridden%20so%20installations%20will%20only%20check%20.ssh%2Fauthorized_keys%0AAuthorizedKeysFile%09.ssh%2Fauthorized_keys%0A%0A%23AuthorizedPrincipalsFile%20none%0A%0A%23AuthorizedKeysCommand%20none%0A%23AuthorizedKeysCommandUser%20nobody%0A%0A%23%20For%20this%20to%20work%20you%20will%20also%20need%20host%20keys%20in%20%2Fetc%2Fssh%2Fssh_known_hosts%0AHostbasedAuthentication%20no%0A%23%20Change%20to%20yes%20if%20you%20don%27t%20trust%20~%2F.ssh%2Fknown_hosts%20for%0A%23%20HostbasedAuthentication%0AIgnoreUserKnownHosts%20yes%0A%23%20Don%27t%20read%20the%20user%27s%20~%2F.rhosts%20and%20~%2F.shosts%20files%0AIgnoreRhosts%20yes%0A%0A%23%20To%20disable%20tunneled%20clear%20text%20passwords%2C%20change%20to%20no%20here%21%0A%23PasswordAuthentication%20yes%0APermitEmptyPasswords%20no%0APasswordAuthentication%20no%0A%0A%23%20Change%20to%20no%20to%20disable%20s%2Fkey%20passwords%0A%23ChallengeResponseAuthentication%20yes%0AChallengeResponseAuthentication%20no%0A%0A%23%20Kerberos%20options%0AKerberosAuthentication%20no%0A%23KerberosOrLocalPasswd%20yes%0A%23KerberosTicketCleanup%20yes%0A%23KerberosGetAFSToken%20no%0A%23KerberosUseKuserok%20yes%0A%0A%23%20GSSAPI%20options%0AGSSAPIAuthentication%20no%0AGSSAPICleanupCredentials%20no%0A%23GSSAPIStrictAcceptorCheck%20yes%0A%23GSSAPIKeyExchange%20no%0A%23GSSAPIEnablek5users%20no%0A%0A%23%20Set%20this%20to%20%27yes%27%20to%20enable%20PAM%20authentication%2C%20account%20processing%2C%0A%23%20and%20session%20processing.%20If%20this%20is%20enabled%2C%20PAM%20authentication%20will%0A%23%20be%20allowed%20through%20the%20ChallengeResponseAuthentication%20and%0A%23%20PasswordAuthentication.%20%20Depending%20on%20your%20PAM%20configuration%2C%0A%23%20PAM%20authentication%20via%20ChallengeResponseAuthentication%20may%20bypass%0A%23%20the%20setting%20of%20%22PermitRootLogin%20without-password%22.%0A%23%20If%20you%20just%20want%20the%20PAM%20account%20and%20session%20checks%20to%20run%20without%0A%23%20PAM%20authentication%2C%20then%20enable%20this%20but%20set%20PasswordAuthentication%0A%23%20and%20ChallengeResponseAuthentication%20to%20%27no%27.%0A%23%20WARNING%3A%20%27UsePAM%20no%27%20is%20not%20supported%20in%20Fedora%20and%20may%20cause%20several%0A%23%20problems.%0AUsePAM%20yes%0A%0A%23AllowAgentForwarding%20yes%0A%23AllowTcpForwarding%20yes%0A%23GatewayPorts%20no%0AX11Forwarding%20yes%0A%23X11DisplayOffset%2010%0A%23X11UseLocalhost%20yes%0A%23PermitTTY%20yes%0A%0A%23%20It%20is%20recommended%20to%20use%20pam_motd%20in%20%2Fetc%2Fpam.d%2Fsshd%20instead%20of%20PrintMotd%2C%0A%23%20as%20it%20is%20more%20configurable%20and%20versatile%20than%20the%20built-in%20version.%0APrintMotd%20no%0A%0APrintLastLog%20yes%0A%23TCPKeepAlive%20yes%0APermitUserEnvironment%20no%0ACompression%20no%0AClientAliveInterval%20600%0AClientAliveCountMax%200%0A%23UseDNS%20no%0A%23PidFile%20%2Fvar%2Frun%2Fsshd.pid%0A%23MaxStartups%2010%3A30%3A100%0A%23PermitTunnel%20no%0A%23ChrootDirectory%20none%0A%23VersionAddendum%20none%0A%0A%23%20no%20default%20banner%20path%0ABanner%20%2Fetc%2Fissue%0A%0A%23%20Accept%20locale-related%20environment%20variables%0AAcceptEnv%20LANG%20LC_CTYPE%20LC_NUMERIC%20LC_TIME%20LC_COLLATE%20LC_MONETARY%20LC_MESSAGES%0AAcceptEnv%20LC_PAPER%20LC_NAME%20LC_ADDRESS%20LC_TELEPHONE%20LC_MEASUREMENT%0AAcceptEnv%20LC_IDENTIFICATION%20LC_ALL%20LANGUAGE%0AAcceptEnv%20XMODIFIERS%0A%0A%23%20override%20default%20of%20no%20subsystems%0ASubsystem%09sftp%09%2Fusr%2Flibexec%2Fopenssh%2Fsftp-server%0A%0A%23%20Example%20of%20overriding%20settings%20on%20a%20per-user%20basis%0A%23Match%20User%20anoncvs%0A%23%09X11Forwarding%20no%0A%23%09AllowTcpForwarding%20no%0A%23%09PermitTTY%20no%0A%23%09ForceCommand%20cvs%20server%0A%0AUsePrivilegeSeparation%20sandbox
        mode: 0600
        path: /etc/ssh/sshd_config
        overwrite: true

Rule   Disable SSH Access via Empty Passwords   [ref]

Disallow SSH login with empty passwords. The default SSH configuration disables logins with empty passwords. The appropriate configuration is used if no value is set for PermitEmptyPasswords.
To explicitly disallow SSH login from accounts with empty passwords, add or correct the following line in /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf:
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.
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_sshd_disable_empty_passwords
Identifiers and References

References:  NT007(R17), 11, 12, 13, 14, 15, 16, 18, 3, 5, 9, 5.5.6, APO01.06, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.02, DSS06.03, DSS06.06, 3.1.1, 3.1.5, CCI-000366, CCI-000766, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.3.2.2, 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, 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.2, SR 2.3, SR 2.4, SR 2.5, SR 2.6, SR 2.7, SR 5.2, SR 7.6, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.2, A.12.5.1, A.12.6.2, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.14.2.2, A.14.2.3, A.14.2.4, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.1, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, AC-17(a), CM-7(a), CM-7(b), CM-6(a), PR.AC-4, PR.AC-6, PR.DS-5, PR.IP-1, PR.PT-3, FIA_UAU.1, SRG-OS-000106-GPOS-00053, SRG-OS-000480-GPOS-00229, SRG-OS-000480-GPOS-00227, SRG-OS-000480-VMM-002000


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

mkdir -p /etc/ssh/sshd_config.d
touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf

LC_ALL=C sed -i "/^\s*PermitEmptyPasswords\s\+/Id" "/etc/ssh/sshd_config"
LC_ALL=C sed -i "/^\s*PermitEmptyPasswords\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf
if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then
    
    LC_ALL=C sed -i "/^\s*PermitEmptyPasswords\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
else
    touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"

cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"
# Insert before the line matching the regex '^Match'.
line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.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.d/00-complianceascode-hardening.conf"
else
    head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    printf '%s\n' "PermitEmptyPasswords no" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
fi
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Disable SSH Access via Empty Passwords
  block:

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: ^\s*{{ "PermitEmptyPasswords"| regex_escape }}\s+
        state: absent

    - name: Check if /etc/ssh/sshd_config.d exists
      stat:
        path: /etc/ssh/sshd_config.d
      register: _etc_ssh_sshd_config_d_exists

    - name: Check if the parameter PermitEmptyPasswords is present in /etc/ssh/sshd_config.d
      find:
        paths: /etc/ssh/sshd_config.d
        recurse: 'yes'
        follow: 'no'
        contains: ^\s*{{ "PermitEmptyPasswords"| regex_escape }}\s+
      register: _etc_ssh_sshd_config_d_has_parameter
      when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir

    - name: Remove parameter from files in /etc/ssh/sshd_config.d
      lineinfile:
        path: '{{ item.path }}'
        create: false
        regexp: ^\s*{{ "PermitEmptyPasswords"| regex_escape }}\s+
        state: absent
      with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}'
      when: _etc_ssh_sshd_config_d_has_parameter.matched

    - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
      lineinfile:
        path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
        create: true
        regexp: ^\s*{{ "PermitEmptyPasswords"| regex_escape }}\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:
    - CJIS-5.5.6
    - 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

Rule   Disable GSSAPI Authentication   [ref]

Unless needed, SSH should not permit extraneous or unnecessary authentication mechanisms like GSSAPI.
The default SSH configuration disallows authentications based on GSSAPI. The appropriate configuration is used if no value is set for GSSAPIAuthentication.
To explicitly disable GSSAPI authentication, add or correct the following line in /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf:
GSSAPIAuthentication no
Rationale:
GSSAPI authentication is used to provide additional authentication mechanisms to applications. Allowing GSSAPI authentication through SSH exposes the system's GSSAPI to remote hosts, increasing the attack surface of the system.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sshd_disable_gssapi_auth
Identifiers and References

References:  11, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, 3.1.12, CCI-000318, CCI-000368, CCI-001812, CCI-001813, CCI-001814, CCI-000366, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.4.3.2, 4.3.4.3.3, SR 7.6, 0418, 1055, 1402, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, CM-7(a), CM-7(b), CM-6(a), AC-17(a), PR.IP-1, FTP_ITC_EXT.1, SRG-OS-000364-GPOS-00151, SRG-OS-000480-GPOS-00227, SRG-OS-000480-VMM-002000


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

mkdir -p /etc/ssh/sshd_config.d
touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf

LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config"
LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf
if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then
    
    LC_ALL=C sed -i "/^\s*GSSAPIAuthentication\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
else
    touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"

cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"
# Insert before the line matching the regex '^Match'.
line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.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' "GSSAPIAuthentication no" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
else
    head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    printf '%s\n' "GSSAPIAuthentication no" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
fi
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Disable GSSAPI Authentication
  block:

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: ^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+
        state: absent

    - name: Check if /etc/ssh/sshd_config.d exists
      stat:
        path: /etc/ssh/sshd_config.d
      register: _etc_ssh_sshd_config_d_exists

    - name: Check if the parameter GSSAPIAuthentication is present in /etc/ssh/sshd_config.d
      find:
        paths: /etc/ssh/sshd_config.d
        recurse: 'yes'
        follow: 'no'
        contains: ^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+
      register: _etc_ssh_sshd_config_d_has_parameter
      when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir

    - name: Remove parameter from files in /etc/ssh/sshd_config.d
      lineinfile:
        path: '{{ item.path }}'
        create: false
        regexp: ^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+
        state: absent
      with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}'
      when: _etc_ssh_sshd_config_d_has_parameter.matched

    - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
      lineinfile:
        path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
        create: true
        regexp: ^\s*{{ "GSSAPIAuthentication"| regex_escape }}\s+
        line: GSSAPIAuthentication 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:
    - 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_gssapi_auth

Rule   Disable Kerberos Authentication   [ref]

Unless needed, SSH should not permit extraneous or unnecessary authentication mechanisms like Kerberos.
The default SSH configuration disallows authentication validation through Kerberos. The appropriate configuration is used if no value is set for KerberosAuthentication.
To explicitly disable Kerberos authentication, add or correct the following line in /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf:
KerberosAuthentication no
Rationale:
Kerberos authentication for SSH is often implemented using GSSAPI. If Kerberos is enabled through SSH, the SSH daemon provides a means of access to the system's Kerberos implementation. Vulnerabilities in the system's Kerberos implementations may be subject to exploitation.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sshd_disable_kerb_auth
Identifiers and References

References:  11, 3, 9, BAI10.01, BAI10.02, BAI10.03, BAI10.05, 3.1.12, CCI-000318, CCI-000368, CCI-001812, CCI-001813, CCI-001814, CCI-000366, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.4.3.2, 4.3.4.3.3, SR 7.6, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, AC-17(a), CM-7(a), CM-7(b), CM-6(a), PR.IP-1, FTP_ITC_EXT.1, SRG-OS-000364-GPOS-00151, SRG-OS-000480-GPOS-00227, SRG-OS-000480-VMM-002000


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

mkdir -p /etc/ssh/sshd_config.d
touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf

LC_ALL=C sed -i "/^\s*KerberosAuthentication\s\+/Id" "/etc/ssh/sshd_config"
LC_ALL=C sed -i "/^\s*KerberosAuthentication\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf
if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then
    
    LC_ALL=C sed -i "/^\s*KerberosAuthentication\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
else
    touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"

cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"
# Insert before the line matching the regex '^Match'.
line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.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' "KerberosAuthentication no" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
else
    head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    printf '%s\n' "KerberosAuthentication no" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
fi
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Disable Kerberos Authentication
  block:

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: ^\s*{{ "KerberosAuthentication"| regex_escape }}\s+
        state: absent

    - name: Check if /etc/ssh/sshd_config.d exists
      stat:
        path: /etc/ssh/sshd_config.d
      register: _etc_ssh_sshd_config_d_exists

    - name: Check if the parameter KerberosAuthentication is present in /etc/ssh/sshd_config.d
      find:
        paths: /etc/ssh/sshd_config.d
        recurse: 'yes'
        follow: 'no'
        contains: ^\s*{{ "KerberosAuthentication"| regex_escape }}\s+
      register: _etc_ssh_sshd_config_d_has_parameter
      when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir

    - name: Remove parameter from files in /etc/ssh/sshd_config.d
      lineinfile:
        path: '{{ item.path }}'
        create: false
        regexp: ^\s*{{ "KerberosAuthentication"| regex_escape }}\s+
        state: absent
      with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}'
      when: _etc_ssh_sshd_config_d_has_parameter.matched

    - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
      lineinfile:
        path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
        create: true
        regexp: ^\s*{{ "KerberosAuthentication"| regex_escape }}\s+
        line: KerberosAuthentication 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:
    - 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_kerb_auth

Rule   Enable Use of Strict Mode Checking   [ref]

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.
The default SSH configuration has StrictModes enabled. The appropriate configuration is used if no value is set for StrictModes.
To explicitly enable StrictModes in SSH, add or correct the following line in /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf:
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.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sshd_enable_strictmodes
Identifiers and References

References:  12, 13, 14, 15, 16, 18, 3, 5, APO01.06, DSS05.04, DSS05.07, DSS06.02, 3.1.12, CCI-000366, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 4.3.3.7.3, SR 2.1, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CIP-003-8 R5.1.1, CIP-003-8 R5.3, CIP-004-6 R2.3, CIP-007-3 R2.1, CIP-007-3 R2.2, CIP-007-3 R2.3, CIP-007-3 R5.1, CIP-007-3 R5.1.1, CIP-007-3 R5.1.2, AC-6, AC-17(a), CM-6(a), PR.AC-4, PR.DS-5, SRG-OS-000480-GPOS-00227, SRG-OS-000480-VMM-002000


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

mkdir -p /etc/ssh/sshd_config.d
touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf

LC_ALL=C sed -i "/^\s*StrictModes\s\+/Id" "/etc/ssh/sshd_config"
LC_ALL=C sed -i "/^\s*StrictModes\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf
if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then
    
    LC_ALL=C sed -i "/^\s*StrictModes\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
else
    touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"

cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"
# Insert before the line matching the regex '^Match'.
line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.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.d/00-complianceascode-hardening.conf"
else
    head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    printf '%s\n' "StrictModes yes" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
fi
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Enable Use of Strict Mode Checking
  block:

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: ^\s*{{ "StrictModes"| regex_escape }}\s+
        state: absent

    - name: Check if /etc/ssh/sshd_config.d exists
      stat:
        path: /etc/ssh/sshd_config.d
      register: _etc_ssh_sshd_config_d_exists

    - name: Check if the parameter StrictModes is present in /etc/ssh/sshd_config.d
      find:
        paths: /etc/ssh/sshd_config.d
        recurse: 'yes'
        follow: 'no'
        contains: ^\s*{{ "StrictModes"| regex_escape }}\s+
      register: _etc_ssh_sshd_config_d_has_parameter
      when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir

    - name: Remove parameter from files in /etc/ssh/sshd_config.d
      lineinfile:
        path: '{{ item.path }}'
        create: false
        regexp: ^\s*{{ "StrictModes"| regex_escape }}\s+
        state: absent
      with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}'
      when: _etc_ssh_sshd_config_d_has_parameter.matched

    - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
      lineinfile:
        path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
        create: true
        regexp: ^\s*{{ "StrictModes"| regex_escape }}\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:
    - 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

Rule   Enable SSH Warning Banner   [ref]

To enable the warning banner and ensure it is consistent across the system, add or correct the following line in /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf:
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.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sshd_enable_warning_banner
Identifiers and References

References:  1, 12, 15, 16, 5.5.6, DSS05.04, DSS05.10, DSS06.10, 3.1.9, CCI-000048, CCI-000050, CCI-001384, CCI-001385, CCI-001386, CCI-001387, CCI-001388, 164.308(a)(4)(i), 164.308(b)(1), 164.308(b)(3), 164.310(b), 164.312(e)(1), 164.312(e)(2)(ii), 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, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, AC-8(a), AC-8(c), AC-17(a), CM-6(a), PR.AC-7, FTA_TAB.1, SRG-OS-000023-GPOS-00006, SRG-OS-000024-GPOS-00007, SRG-OS-000228-GPOS-00088, SRG-OS-000023-VMM-000060, SRG-OS-000024-VMM-000070


Complexity:low
Disruption:low
Strategy:restrict
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

mkdir -p /etc/ssh/sshd_config.d
touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf

LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config"
LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf
if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then
    
    LC_ALL=C sed -i "/^\s*Banner\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
else
    touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"

cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"
# Insert before the line matching the regex '^Match'.
line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.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.d/00-complianceascode-hardening.conf"
else
    head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    printf '%s\n' "Banner /etc/issue" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
fi
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Enable SSH Warning Banner
  block:

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: ^\s*{{ "Banner"| regex_escape }}\s+
        state: absent

    - name: Check if /etc/ssh/sshd_config.d exists
      stat:
        path: /etc/ssh/sshd_config.d
      register: _etc_ssh_sshd_config_d_exists

    - name: Check if the parameter Banner is present in /etc/ssh/sshd_config.d
      find:
        paths: /etc/ssh/sshd_config.d
        recurse: 'yes'
        follow: 'no'
        contains: ^\s*{{ "Banner"| regex_escape }}\s+
      register: _etc_ssh_sshd_config_d_has_parameter
      when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir

    - name: Remove parameter from files in /etc/ssh/sshd_config.d
      lineinfile:
        path: '{{ item.path }}'
        create: false
        regexp: ^\s*{{ "Banner"| regex_escape }}\s+
        state: absent
      with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}'
      when: _etc_ssh_sshd_config_d_has_parameter.matched

    - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
      lineinfile:
        path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
        create: true
        regexp: ^\s*{{ "Banner"| regex_escape }}\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:
    - CJIS-5.5.6
    - 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

Rule   Force frequent session key renegotiation   [ref]

The RekeyLimit parameter specifies how often the session key of the is renegotiated, both in terms of amount of data that may be transmitted and the time elapsed.
To decrease the default limits, add or correct the following line in /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf:
RekeyLimit 1G 1h
Rationale:
By decreasing the limit based on the amount of data and enabling time-based limit, effects of potential attacks against encryption keys are limited.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sshd_rekey_limit
Identifiers and References

References:  CCI-000068, FCS_SSHS_EXT.1, SRG-OS-000480-GPOS-00227, SRG-OS-000033-GPOS-00014


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

var_rekey_limit_size='1G'
var_rekey_limit_time='1h'



mkdir -p /etc/ssh/sshd_config.d
touch /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf

LC_ALL=C sed -i "/^\s*RekeyLimit\s\+/Id" "/etc/ssh/sshd_config"
LC_ALL=C sed -i "/^\s*RekeyLimit\s\+/Id" "/etc/ssh/sshd_config.d"/*.conf
if [ -e "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" ] ; then
    
    LC_ALL=C sed -i "/^\s*RekeyLimit\s\+/Id" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
else
    touch "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"

cp "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"
# Insert before the line matching the regex '^Match'.
line_number="$(LC_ALL=C grep -n "^Match" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.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' "RekeyLimit $var_rekey_limit_size $var_rekey_limit_time" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
else
    head -n "$(( line_number - 1 ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" > "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    printf '%s\n' "RekeyLimit $var_rekey_limit_size $var_rekey_limit_time" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
    tail -n "+$(( line_number ))" "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak" >> "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf"
fi
# Clean up after ourselves.
rm "/etc/ssh/sshd_config.d/00-complianceascode-hardening.conf.bak"

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

Complexity:low
Disruption:low
Strategy:configure
- name: XCCDF Value var_rekey_limit_size # promote to variable
  set_fact:
    var_rekey_limit_size: !!str 1G
  tags:
    - always
- name: XCCDF Value var_rekey_limit_time # promote to variable
  set_fact:
    var_rekey_limit_time: !!str 1h
  tags:
    - always

- name: Force frequent session key renegotiation
  block:

    - name: Deduplicate values from /etc/ssh/sshd_config
      lineinfile:
        path: /etc/ssh/sshd_config
        create: false
        regexp: ^\s*{{ "RekeyLimit"| regex_escape }}\s+
        state: absent

    - name: Check if /etc/ssh/sshd_config.d exists
      stat:
        path: /etc/ssh/sshd_config.d
      register: _etc_ssh_sshd_config_d_exists

    - name: Check if the parameter RekeyLimit is present in /etc/ssh/sshd_config.d
      find:
        paths: /etc/ssh/sshd_config.d
        recurse: 'yes'
        follow: 'no'
        contains: ^\s*{{ "RekeyLimit"| regex_escape }}\s+
      register: _etc_ssh_sshd_config_d_has_parameter
      when: _etc_ssh_sshd_config_d_exists.stat.isdir is defined and _etc_ssh_sshd_config_d_exists.stat.isdir

    - name: Remove parameter from files in /etc/ssh/sshd_config.d
      lineinfile:
        path: '{{ item.path }}'
        create: false
        regexp: ^\s*{{ "RekeyLimit"| regex_escape }}\s+
        state: absent
      with_items: '{{ _etc_ssh_sshd_config_d_has_parameter.files }}'
      when: _etc_ssh_sshd_config_d_has_parameter.matched

    - name: Insert correct line to /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
      lineinfile:
        path: /etc/ssh/sshd_config.d/00-complianceascode-hardening.conf
        create: true
        regexp: ^\s*{{ "RekeyLimit"| regex_escape }}\s+
        line: RekeyLimit {{ var_rekey_limit_size }} {{ var_rekey_limit_time }}
        state: present
        insertbefore: ^[#\s]*Match
        validate: /usr/sbin/sshd -t -f %s
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - sshd_rekey_limit

Rule   Distribute the SSH Server configuration to multiple files in a config directory.   [ref]

Make sure to have the Include /etc/ssh/sshd_config.d/*.conf line in the /etc/ssh/sshd_config file. Ideally, don't have any active configuration directives in that file, and distribute the service configuration to several files in the /etc/ssh/sshd_config.d directory.
Rationale:
This form of distributed configuration is considered as a good practice, and as other sshd rules assume that directives in files in the /etc/ssh/sshd_config.d config directory are effective, there has to be a rule that ensures this. Aside from that, having multiple configuration files makes the SSH Server configuration changes easier to partition according to the reason that they were introduced, and therefore it should help to perform merges of hardening updates.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sshd_use_directory_configuration
Identifiers and References

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

if test -f /etc/ssh/sshd_config.d/sshd_config_original.conf; then
	printf '%s\n' "Remediation probably already happened, '/etc/ssh/sshd_config.d/sshd_config_original.conf' already exists, not doing anything." >&2
false 1
elif grep -Eq '^\s*Include\s+/etc/ssh/sshd_config\.d/\*\.conf' /etc/ssh/sshd_config && ! grep -Eq '^\s*Match\s' /etc/ssh/sshd_config; then
	printf '%s\n' "Remediation probably already happened, '/etc/ssh/sshd_config' already contains the include directive." >&2
false 1
else
	mkdir -p /etc/ssh/sshd_config.d
	mv /etc/ssh/sshd_config /etc/ssh/sshd_config.d/sshd_config_original.conf
cat > /etc/ssh/sshd_config << EOF
# To modify the system-wide sshd configuration, create a  *.conf  file under
#  /etc/ssh/sshd_config.d/  which will be automatically included below

Include /etc/ssh/sshd_config.d/*.conf
EOF
fi

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

Rule   Install OpenSSH client software   [ref]

The openssh-clients package can be installed with the following command:
$ sudo dnf install openssh-clients
Rationale:
This package includes utilities to make encrypted connections and transfer files securely to SSH servers.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_openssh-clients_installed
Identifiers and References

References:  FIA_UAU.5, FTP_ITC_EXT.1, SRG-OS-000480-GPOS-00227


Complexity:low
Disruption:low
Strategy:enable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if ! rpm -q --quiet "openssh-clients" ; then
    dnf install -y "openssh-clients"
fi

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

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure openssh-clients is installed
  package:
    name: openssh-clients
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_openssh-clients_installed

Complexity:low
Disruption:low
Strategy:enable
include install_openssh-clients

class install_openssh-clients {
  package { 'openssh-clients':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=openssh-clients


[[packages]]
name = "openssh-clients"
version = "*"

Rule   Install the OpenSSH Server Package   [ref]

The openssh-server package should be installed. The openssh-server package can be installed with the following command:
$ sudo dnf install openssh-server
Rationale:
Without protection of the transmitted information, confidentiality, and integrity may be compromised because unprotected communications can be intercepted and either read or altered.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_openssh-server_installed
Identifiers and References

References:  13, 14, APO01.06, DSS05.02, DSS05.04, DSS05.07, DSS06.02, DSS06.06, CCI-002418, CCI-002420, CCI-002421, CCI-002422, SR 3.1, SR 3.8, SR 4.1, SR 4.2, SR 5.2, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.13.1.1, A.13.1.3, A.13.2.1, A.13.2.3, A.13.2.4, A.14.1.2, A.14.1.3, A.6.1.2, A.7.1.1, A.7.1.2, A.7.3.1, A.8.2.2, A.8.2.3, A.9.1.1, A.9.1.2, A.9.2.3, A.9.4.1, A.9.4.4, A.9.4.5, CM-6(a), PR.DS-2, PR.DS-5, FIA_UAU.5, FTP_ITC_EXT.1, SRG-OS-000423-GPOS-00187, SRG-OS-000424-GPOS-00188, SRG-OS-000425-GPOS-00189, SRG-OS-000426-GPOS-00190


Complexity:low
Disruption:low
Strategy:enable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

if ! rpm -q --quiet "openssh-server" ; then
    dnf install -y "openssh-server"
fi

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

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure openssh-server is installed
  package:
    name: openssh-server
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-CM-6(a)
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_openssh-server_installed

Complexity:low
Disruption:low
Strategy:enable
include install_openssh-server

class install_openssh-server {
  package { 'openssh-server':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=openssh-server


[[packages]]
name = "openssh-server"
version = "*"
Group   USBGuard daemon   Group contains 4 rules
[ref]   The USBGuard daemon enforces the USB device authorization policy for all USB devices.

Rule   Install usbguard Package   [ref]

The usbguard package can be installed with the following command:
$ sudo dnf install usbguard
Rationale:
usbguard is a software framework that helps to protect against rogue USB devices by implementing basic whitelisting/blacklisting capabilities based on USB device attributes.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_usbguard_installed
Identifiers and References

References:  CCI-001958, 1418, CM-8(3), IA-3, SRG-OS-000378-GPOS-00163


Complexity:low
Disruption:low
Strategy:enable

if ! rpm -q --quiet "usbguard" ; then
    dnf install -y "usbguard"
fi

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure usbguard is installed
  package:
    name: usbguard
    state: present
  tags:
    - NIST-800-53-CM-8(3)
    - NIST-800-53-IA-3
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_usbguard_installed

Complexity:low
Disruption:low
Strategy:enable
include install_usbguard

class install_usbguard {
  package { 'usbguard':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=usbguard

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
spec:
  config:
    ignition:
      version: 3.1.0
  extensions:
    - usbguard


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

Rule   Enable the USBGuard Service   [ref]

The USBGuard service should be enabled. The usbguard service can be enabled with the following command:
$ sudo systemctl enable usbguard.service
Rationale:
The usbguard service must be running in order to enforce the USB device authorization policy for all USB devices.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_service_usbguard_enabled
Identifiers and References

References:  CCI-000416, CCI-001958, 1418, CM-8(3)(a), IA-3, FMT_SMF_EXT.1, SRG-OS-000378-GPOS-00163


Complexity:low
Disruption:low
Strategy:enable
# Remediation is applicable only in certain platforms
if [ ! -f /.dockerenv ] && [ ! -f /run/.containerenv ]; then

SYSTEMCTL_EXEC='/usr/bin/systemctl'
"$SYSTEMCTL_EXEC" unmask 'usbguard.service'
"$SYSTEMCTL_EXEC" start 'usbguard.service'
"$SYSTEMCTL_EXEC" enable 'usbguard.service'

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

Complexity:low
Disruption:low
Strategy:enable
- name: Enable service usbguard
  block:

    - name: Gather the package facts
      package_facts:
        manager: auto

    - name: Enable service usbguard
      service:
        name: usbguard
        enabled: 'yes'
        state: started
        masked: 'no'
      when:
        - '"usbguard" in ansible_facts.packages'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - NIST-800-53-CM-8(3)(a)
    - NIST-800-53-IA-3
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_usbguard_enabled

Complexity:low
Disruption:low
Strategy:enable
include enable_usbguard

class enable_usbguard {
  service {'usbguard':
    enable => true,
    ensure => 'running',
  }
}

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
metadata:
  annotations:
    complianceascode.io/depends-on: xccdf_org.ssgproject.content_rule_package_usbguard_installed
spec:
  config:
    ignition:
      version: 3.1.0
    systemd:
      units:
      - name: usbguard.service
        enabled: true


[customizations.services]
enabled = ["usbguard"]

Rule   Log USBGuard daemon audit events using Linux Audit   [ref]

To configure USBGuard daemon to log via Linux Audit (as opposed directly to a file), AuditBackend option in /etc/usbguard/usbguard-daemon.conf needs to be set to LinuxAudit.
Rationale:
Using the Linux Audit logging allows for centralized trace of events.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_configure_usbguard_auditbackend
Identifiers and References

References:  CCI-000169, AU-2, CM-8(3), IA-3, FMT_SMF_EXT.1, SRG-OS-000062-GPOS-00031


Complexity:low
Disruption:low
Strategy:restrict
if [ -e "/etc/usbguard/usbguard-daemon.conf" ] ; then
    
    LC_ALL=C sed -i "/^\s*AuditBackend=/d" "/etc/usbguard/usbguard-daemon.conf"
else
    touch "/etc/usbguard/usbguard-daemon.conf"
fi
# make sure file has newline at the end
sed -i -e '$a\' "/etc/usbguard/usbguard-daemon.conf"

cp "/etc/usbguard/usbguard-daemon.conf" "/etc/usbguard/usbguard-daemon.conf.bak"
# Insert at the end of the file
printf '%s\n' "AuditBackend=LinuxAudit" >> "/etc/usbguard/usbguard-daemon.conf"
# Clean up after ourselves.
rm "/etc/usbguard/usbguard-daemon.conf.bak"

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
metadata:
  annotations:
    complianceascode.io/depends-on: xccdf_org.ssgproject.content_rule_package_usbguard_installed
    complianceascode.io/ocp-version: '>=4.7.0'
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,{{ %0A%23%0A%23%20Rule%20set%20file%20path.%0A%23%0A%23%20The%20USBGuard%20daemon%20will%20use%20this%20file%20to%20load%20the%20policy%0A%23%20rule%20set%20from%20it%20and%20to%20write%20new%20rules%20received%20via%20the%0A%23%20IPC%20interface.%0A%23%0A%23%20RuleFile%3D/path/to/rules.conf%0A%23%0ARuleFile%3D/etc/usbguard/rules.conf%0A%0A%23%0A%23%20Rule%20set%20folder%20path.%0A%23%0A%23%20The%20USBGuard%20daemon%20will%20use%20this%20folder%20to%20load%20the%20policy%0A%23%20rule%20set%20from%20it%20and%20to%20write%20new%20rules%20received%20via%20the%0A%23%20IPC%20interface.%20Usually%2C%20we%20set%20the%20option%20to%0A%23%20/etc/usbguard/rules.d/.%20The%20USBGuard%20daemon%20is%20supposed%20to%0A%23%20behave%20like%20any%20other%20standard%20Linux%20daemon%20therefore%20it%0A%23%20loads%20rule%20files%20in%20alpha-numeric%20order.%20File%20names%20inside%0A%23%20RuleFolder%20directory%20should%20start%20with%20a%20two-digit%20number%0A%23%20prefix%20indicating%20the%20position%2C%20in%20which%20the%20rules%20are%0A%23%20scanned%20by%20the%20daemon.%0A%23%0A%23%20RuleFolder%3D/path/to/rulesfolder/%0A%23%0ARuleFolder%3D/etc/usbguard/rules.d/%0A%0A%23%0A%23%20Implicit%20policy%20target.%0A%23%0A%23%20How%20to%20treat%20devices%20that%20don%27t%20match%20any%20rule%20in%20the%0A%23%20policy.%20One%20of%3A%0A%23%0A%23%20%2A%20allow%20%20-%20authorize%20the%20device%0A%23%20%2A%20block%20%20-%20block%20the%20device%0A%23%20%2A%20reject%20-%20remove%20the%20device%0A%23%0AImplicitPolicyTarget%3Dblock%0A%0A%23%0A%23%20Present%20device%20policy.%0A%23%0A%23%20How%20to%20treat%20devices%20that%20are%20already%20connected%20when%20the%0A%23%20daemon%20starts.%20One%20of%3A%0A%23%0A%23%20%2A%20allow%20%20%20%20%20%20%20%20-%20authorize%20every%20present%20device%0A%23%20%2A%20block%20%20%20%20%20%20%20%20-%20deauthorize%20every%20present%20device%0A%23%20%2A%20reject%20%20%20%20%20%20%20-%20remove%20every%20present%20device%0A%23%20%2A%20keep%20%20%20%20%20%20%20%20%20-%20just%20sync%20the%20internal%20state%20and%20leave%20it%0A%23%20%2A%20apply-policy%20-%20evaluate%20the%20ruleset%20for%20every%20present%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20device%0A%23%0APresentDevicePolicy%3Dapply-policy%0A%0A%23%0A%23%20Present%20controller%20policy.%0A%23%0A%23%20How%20to%20treat%20USB%20controllers%20that%20are%20already%20connected%0A%23%20when%20the%20daemon%20starts.%20One%20of%3A%0A%23%0A%23%20%2A%20allow%20%20%20%20%20%20%20%20-%20authorize%20every%20present%20device%0A%23%20%2A%20block%20%20%20%20%20%20%20%20-%20deauthorize%20every%20present%20device%0A%23%20%2A%20reject%20%20%20%20%20%20%20-%20remove%20every%20present%20device%0A%23%20%2A%20keep%20%20%20%20%20%20%20%20%20-%20just%20sync%20the%20internal%20state%20and%20leave%20it%0A%23%20%2A%20apply-policy%20-%20evaluate%20the%20ruleset%20for%20every%20present%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20device%0A%23%0APresentControllerPolicy%3Dkeep%0A%0A%23%0A%23%20Inserted%20device%20policy.%0A%23%0A%23%20How%20to%20treat%20USB%20devices%20that%20are%20already%20connected%0A%23%20%2Aafter%2A%20the%20daemon%20starts.%20One%20of%3A%0A%23%0A%23%20%2A%20block%20%20%20%20%20%20%20%20-%20deauthorize%20every%20present%20device%0A%23%20%2A%20reject%20%20%20%20%20%20%20-%20remove%20every%20present%20device%0A%23%20%2A%20apply-policy%20-%20evaluate%20the%20ruleset%20for%20every%20present%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20device%0A%23%0AInsertedDevicePolicy%3Dapply-policy%0A%0A%23%0A%23%20Control%20which%20devices%20are%20authorized%20by%20default.%0A%23%0A%23%20The%20USBGuard%20daemon%20modifies%20some%20the%20default%20authorization%20state%20attributes%0A%23%20of%20controller%20devices.%20This%20setting%2C%20enables%20you%20to%20define%20what%20value%20the%0A%23%20default%20authorization%20is%20set%20to.%0A%23%0A%23%20%2A%20keep%20%20%20%20%20%20%20%20%20-%20do%20not%20change%20the%20authorization%20state%0A%23%20%2A%20none%20%20%20%20%20%20%20%20%20-%20every%20new%20device%20starts%20out%20deauthorized%0A%23%20%2A%20all%20%20%20%20%20%20%20%20%20%20-%20every%20new%20device%20starts%20out%20authorized%0A%23%20%2A%20internal%20%20%20%20%20-%20internal%20devices%20start%20out%20authorized%2C%20external%20devices%20start%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20out%20deauthorized%20%28this%20requires%20the%20ACPI%20tables%20to%20properly%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20label%20internal%20devices%2C%20and%20kernel%20support%29%0A%23%0A%23AuthorizedDefault%3Dnone%0A%0A%23%0A%23%20Restore%20controller%20device%20state.%0A%23%0A%23%20The%20USBGuard%20daemon%20modifies%20some%20attributes%20of%20controller%0A%23%20devices%20like%20the%20default%20authorization%20state%20of%20new%20child%20device%0A%23%20instances.%20Using%20this%20setting%2C%20you%20can%20control%20whether%20the%0A%23%20daemon%20will%20try%20to%20restore%20the%20attribute%20values%20to%20the%20state%0A%23%20before%20modification%20on%20shutdown.%0A%23%0A%23%20SECURITY%20CONSIDERATIONS%3A%20If%20set%20to%20true%2C%20the%20USB%20authorization%0A%23%20policy%20could%20be%20bypassed%20by%20performing%20some%20sort%20of%20attack%20on%20the%0A%23%20daemon%20%28via%20a%20local%20exploit%20or%20via%20a%20USB%20device%29%20to%20make%20it%20shutdown%0A%23%20and%20restore%20to%20the%20operating-system%20default%20state%20%28known%20to%20be%20permissive%29.%0A%23%0ARestoreControllerDeviceState%3Dfalse%0A%0A%23%0A%23%20Device%20manager%20backend%0A%23%0A%23%20Which%20device%20manager%20backend%20implementation%20to%20use.%20One%20of%3A%0A%23%0A%23%20%2A%20uevent%20%20%20-%20Netlink%20based%20implementation%20which%20uses%20sysfs%20to%20scan%20for%20present%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20devices%20and%20an%20uevent%20netlink%20socket%20for%20receiving%20USB%20device%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20related%20events.%0A%23%20%2A%20umockdev%20-%20umockdev%20based%20device%20manager%20capable%20of%20simulating%20devices%20based%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20on%20umockdev-record%20files.%20Useful%20for%20testing.%0A%23%0ADeviceManagerBackend%3Duevent%0A%0A%23%21%21%21%20WARNING%3A%20It%27s%20good%20practice%20to%20set%20at%20least%20one%20of%20the%20%21%21%21%0A%23%21%21%21%20%20%20%20%20%20%20%20%20%20two%20options%20bellow.%20If%20none%20of%20them%20are%20set%2C%20%20%21%21%21%0A%23%21%21%21%20%20%20%20%20%20%20%20%20%20the%20daemon%20will%20accept%20IPC%20connections%20from%20%20%20%21%21%21%0A%23%21%21%21%20%20%20%20%20%20%20%20%20%20anyone%2C%20thus%20allowing%20anyone%20to%20modify%20the%20%20%20%20%21%21%21%0A%23%21%21%21%20%20%20%20%20%20%20%20%20%20rule%20set%20and%20%28de%29authorize%20USB%20devices.%20%20%20%20%20%20%20%21%21%21%0A%0A%23%0A%23%20Users%20allowed%20to%20use%20the%20IPC%20interface.%0A%23%0A%23%20A%20space%20delimited%20list%20of%20usernames%20that%20the%20daemon%20will%0A%23%20accept%20IPC%20connections%20from.%0A%23%0A%23%20IPCAllowedUsers%3Dusername1%20username2%20...%0A%23%0AIPCAllowedUsers%3Droot%0A%0A%23%0A%23%20Groups%20allowed%20to%20use%20the%20IPC%20interface.%0A%23%0A%23%20A%20space%20delimited%20list%20of%20groupnames%20that%20the%20daemon%20will%0A%23%20accept%20IPC%20connections%20from.%0A%23%0A%23%20IPCAllowedGroups%3Dgroupname1%20groupname2%20...%0A%23%0AIPCAllowedGroups%3Dwheel%0A%0A%23%0A%23%20IPC%20access%20control%20definition%20files%20path.%0A%23%0A%23%20The%20files%20at%20this%20location%20will%20be%20interpreted%20by%20the%20daemon%0A%23%20as%20access%20control%20definition%20files.%20The%20%28base%29name%20of%20a%20file%0A%23%20should%20be%20in%20the%20form%3A%0A%23%0A%23%20%20%20%5Buser%5D%5B%3A%3Cgroup%3E%5D%0A%23%0A%23%20and%20should%20contain%20lines%20in%20the%20form%3A%0A%23%0A%23%20%20%20%3Csection%3E%3D%5Bprivilege%5D%20...%0A%23%0A%23%20This%20way%20each%20file%20defines%20who%20is%20able%20to%20connect%20to%20the%20IPC%0A%23%20bus%20and%20what%20privileges%20he%20has.%0A%23%0AIPCAccessControlFiles%3D/etc/usbguard/IPCAccessControl.d/%0A%0A%23%0A%23%20Generate%20device%20specific%20rules%20including%20the%20%22via-port%22%0A%23%20attribute.%0A%23%0A%23%20This%20option%20modifies%20the%20behavior%20of%20the%20allowDevice%0A%23%20action.%20When%20instructed%20to%20generate%20a%20permanent%20rule%2C%0A%23%20the%20action%20can%20generate%20a%20port%20specific%20rule.%20Because%0A%23%20some%20systems%20have%20unstable%20port%20numbering%2C%20the%20generated%0A%23%20rule%20might%20not%20match%20the%20device%20after%20rebooting%20the%20system.%0A%23%0A%23%20If%20set%20to%20false%2C%20the%20generated%20rule%20will%20still%20contain%0A%23%20the%20%22parent-hash%22%20attribute%20which%20also%20defines%20an%20association%0A%23%20to%20the%20parent%20device.%20See%20usbguard-rules.conf%285%29%20for%20more%0A%23%20details.%0A%23%0ADeviceRulesWithPort%3Dfalse%0A%0A%23%0A%23%20USBGuard%20Audit%20events%20log%20backend%0A%23%0A%23%20One%20of%3A%0A%23%0A%23%20%2A%20FileAudit%20-%20Log%20audit%20events%20into%20a%20file%20specified%20by%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20AuditFilePath%20setting%20%28see%20below%29%0A%23%20%2A%20LinuxAudit%20-%20Log%20audit%20events%20using%20the%20Linux%20Audit%0A%23%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20subsystem%20%28using%20audit_log_user_message%29%0A%23%0AAuditBackend%3DLinuxAudit%0A%0A%23%0A%23%20USBGuard%20audit%20events%20log%20file%20path.%0A%23%0A%23AuditFilePath%3D/var/log/usbguard/usbguard-audit.log%0A%0A%23%0A%23%20Hides%20personally%20identifiable%20information%20such%20as%20device%20serial%20numbers%20and%0A%23%20hashes%20of%20descriptors%20%28which%20include%20the%20serial%20number%29%20from%20audit%20entries.%0A%23%0A%23HidePII%3Dfalse }}
        mode: 0600
        path: /etc/usbguard/usbguard-daemon.conf
        overwrite: true

Rule   Authorize Human Interface Devices and USB hubs in USBGuard daemon   [ref]

To allow authorization of USB devices combining human interface device and hub capabilities by USBGuard daemon, add the line allow with-interface match-all { 03:*:* 09:00:* } to /etc/usbguard/rules.conf.
Warning:  This rule should be understood primarily as a convenience administration feature. This rule ensures that if the USBGuard default rules.conf file is present, it will alter it so that USB human interface devices and hubs are allowed. However, if the rules.conf file is altered by system administrator, the rule does not check if USB human interface devices and hubs are allowed. This assumes that an administrator modified the file with some purpose in mind.
Rationale:
Without allowing Human Interface Devices, it might not be possible to interact with the system. Without allowing hubs, it might not be possible to use any USB devices on the system.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_usbguard_allow_hid_and_hub
Identifiers and References

References:  CM-8(3), IA-3, FMT_SMF_EXT.1, SRG-OS-000114-GPOS-00059




echo "allow with-interface match-all { 03:*:* 09:00:* }" >> /etc/usbguard/rules.conf

---
apiVersion: machineconfiguration.openshift.io/v1
kind: MachineConfig
metadata:
  annotations:
    complianceascode.io/depends-on: xccdf_org.ssgproject.content_rule_package_usbguard_installed
spec:
  config:
    ignition:
      version: 3.1.0
    storage:
      files:
      - contents:
          source: data:,{{ %0Aallow%20with-interface%20match-all%20%7B%2003%3A%2A%3A%2A%2009%3A00%3A%2A%20%7D }}
        mode: 0600
        path: /etc/usbguard/rules.d/75-hid-and-hub.conf
        overwrite: true
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.