Guide to the Secure Configuration of Red Hat Enterprise Linux 7

with profile [DRAFT] DISA STIG for Red Hat Enterprise Linux Virtualization Host (RHELH)
This *draft* profile contains configuration checks that align to the DISA STIG for Red Hat Enterprise Linux Virtualization Host (RHELH).
This guide presents a catalog of security-relevant configuration settings for Red Hat Enterprise Linux 7. 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] DISA STIG for Red Hat Enterprise Linux Virtualization Host (RHELH)
Profile IDxccdf_org.ssgproject.content_profile_rhelh-stig

CPE Platforms

  • cpe:/o:redhat:enterprise_linux:7
  • cpe:/o:redhat:enterprise_linux:7::server
  • cpe:/o:redhat:enterprise_linux:7::client
  • cpe:/o:redhat:enterprise_linux:7::computenode
  • cpe:/o:redhat:enterprise_linux:7::workstation

Revision History

Current version: 0.1.55

  • draft (as of 2021-03-19)

Table of Contents

  1. System Settings
    1. Installing and Maintaining Software
    2. Account and Access Control
    3. System Accounting with auditd
    4. Network Configuration and Firewalls
    5. GRUB2 bootloader configuration
    6. Configure Syslog
    7. File Permissions and Masks
    8. SELinux
  2. Services
    1. Network Time Protocol
    2. Network Routing
    3. Obsolete Services
    4. NFS and RPC
    5. Cron and At Daemons
    6. SSH Server
    7. System Security Services Daemon
    8. FTP Server
    9. Base Services
    10. LDAP
    11. X Window System

Checklist

Group   Guide to the Secure Configuration of Red Hat Enterprise Linux 7   Group contains 100 groups and 378 rules
Group   System Settings   Group contains 72 groups and 314 rules
[ref]   Contains rules that check correct system settings.
Group   Installing and Maintaining Software   Group contains 11 groups and 30 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 6 groups and 16 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 2 groups and 10 rules
[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 RPM   Group contains 3 rules
[ref]   The RPM package management system includes the ability to verify the integrity of installed packages by comparing the installed files with information about the files taken from the package metadata stored in the RPM database. Although an attacker could corrupt the RPM database (analogous to attacking the AIDE database as described above), this check can still reveal modification of important files. To list which files on the system differ from what is expected by the RPM database:
$ rpm -qVa
See the man page for rpm to see a complete explanation of each column.

Rule   Verify and Correct File Permissions with RPM   [ref]

The RPM package management system can check file access permissions of installed software packages, including many that are important to system security. Verify that the file permissions of system files and commands match vendor values. Check the file permissions with the following command:
$ sudo rpm -Va | awk '{ if (substr($0,2,1)=="M") print $NF }'
Output indicates files that do not match vendor defaults. After locating a file with incorrect permissions, run the following command to determine which package owns it:
$ rpm -qf FILENAME

Next, run the following command to reset its permissions to the correct values:
$ sudo rpm --setperms PACKAGENAME
Warning:  Profiles may require that specific files have stricter file permissions than defined by the vendor. Such files will be reported as a finding and need to be evaluated according to your policy and deployment environment.
Rationale:
Permissions on system binaries and configuration files that are too generous could allow an unauthorized user to gain privileges that they should not have. The permissions set by the vendor should be maintained. Any deviations from this baseline should be investigated.
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_rpm_verify_permissions
Identifiers and References

Identifiers:  CCE-27209-6

References:  1.7.1.4, 1.7.1.5, 1.7.1.6, 6.1.1, 6.1.2, 6.1.3, 6.1.4, 6.1.5, 6.1.6, 6.1.7, 6.1.8, 6.1.9, 5.10.4.1, 3.3.8, 3.4.1, CCI-001493, CCI-001494, CCI-001495, CCI-001496, 164.308(a)(1)(ii)(D), 164.312(b), 164.312(c)(1), 164.312(c)(2), 164.312(e)(2)(i), CM-6(d), CM-6(c), SI-7, SI-7(1), SI-7(6), AU-9(3), CM-6(a), PR.AC-4, PR.DS-5, PR.IP-1, PR.PT-1, Req-11.5, SRG-OS-000256-GPOS-00097, SRG-OS-000257-GPOS-00098, SRG-OS-000258-GPOS-00099, SRG-OS-000278-GPOS-00108, SR 2.1, SR 2.10, SR 2.11, SR 2.12, SR 2.8, SR 2.9, SR 5.2, SR 7.6, 4.3.3.3.9, 4.3.3.5.8, 4.3.3.7.3, 4.3.4.3.2, 4.3.4.3.3, 4.3.4.4.7, 4.4.2.1, 4.4.2.2, 4.4.2.4, APO01.06, APO11.04, BAI03.05, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.04, DSS05.07, DSS06.02, MEA02.01, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.2, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.5.1, A.12.6.2, A.12.7.1, A.13.1.1, A.13.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.3, A.9.4.1, A.9.4.4, A.9.4.5, 1, 11, 12, 13, 14, 15, 16, 18, 3, 5, 6, 9, RHEL-07-010010, SV-204392r603261_rule


Complexity:high
Disruption:medium
Strategy:restrict

# Declare array to hold set of RPM packages we need to correct permissions for
declare -A SETPERMS_RPM_DICT

# Create a list of files on the system having permissions different from what
# is expected by the RPM database
readarray -t FILES_WITH_INCORRECT_PERMS < <(rpm -Va --nofiledigest | awk '{ if (substr($0,2,1)=="M") print $NF }')

for FILE_PATH in "${FILES_WITH_INCORRECT_PERMS[@]}"
do
        # NOTE: some files maybe controlled by more then one package
        readarray -t RPM_PACKAGES < <(rpm -qf "${FILE_PATH}")
        for RPM_PACKAGE in "${RPM_PACKAGES[@]}"
        do
                # Use an associative array to store packages as it's keys, not having to care about duplicates.
                SETPERMS_RPM_DICT["$RPM_PACKAGE"]=1
        done
done

# For each of the RPM packages left in the list -- reset its permissions to the
# correct values
for RPM_PACKAGE in "${!SETPERMS_RPM_DICT[@]}"
do
	rpm --restore "${RPM_PACKAGE}"
done

Complexity:high
Disruption:medium
Strategy:restrict
- name: Read list of files with incorrect permissions
  command: rpm -Va --nodeps --nosignature --nofiledigest --nosize --nomtime --nordev
    --nocaps --nolinkto --nouser --nogroup
  args:
    warn: false
  register: files_with_incorrect_permissions
  failed_when: files_with_incorrect_permissions.rc > 1
  changed_when: false
  check_mode: false
  tags:
    - CCE-27209-6
    - CJIS-5.10.4.1
    - DISA-STIG-RHEL-07-010010
    - NIST-800-171-3.3.8
    - NIST-800-171-3.4.1
    - NIST-800-53-AU-9(3)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-6(c)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-SI-7
    - NIST-800-53-SI-7(1)
    - NIST-800-53-SI-7(6)
    - PCI-DSS-Req-11.5
    - high_complexity
    - high_severity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy
    - rpm_verify_permissions

- name: Create list of packages
  command: rpm -qf "{{ item }}"
  args:
    warn: false
  with_items: '{{ files_with_incorrect_permissions.stdout_lines | map(''regex_findall'',
    ''^[.]+[M]+.* (\/.*)'', ''\1'') | map(''join'') | select(''match'', ''(\/.*)'')
    | list | unique }}'
  register: list_of_packages
  changed_when: false
  check_mode: false
  when: (files_with_incorrect_permissions.stdout_lines | length > 0)
  tags:
    - CCE-27209-6
    - CJIS-5.10.4.1
    - DISA-STIG-RHEL-07-010010
    - NIST-800-171-3.3.8
    - NIST-800-171-3.4.1
    - NIST-800-53-AU-9(3)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-6(c)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-SI-7
    - NIST-800-53-SI-7(1)
    - NIST-800-53-SI-7(6)
    - PCI-DSS-Req-11.5
    - high_complexity
    - high_severity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy
    - rpm_verify_permissions

- name: Correct file permissions with RPM
  command: rpm --setperms '{{ item }}'
  args:
    warn: false
  with_items: '{{ list_of_packages.results | map(attribute=''stdout_lines'') | list
    | unique }}'
  when: (files_with_incorrect_permissions.stdout_lines | length > 0)
  tags:
    - CCE-27209-6
    - CJIS-5.10.4.1
    - DISA-STIG-RHEL-07-010010
    - NIST-800-171-3.3.8
    - NIST-800-171-3.4.1
    - NIST-800-53-AU-9(3)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-6(c)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-SI-7
    - NIST-800-53-SI-7(1)
    - NIST-800-53-SI-7(6)
    - PCI-DSS-Req-11.5
    - high_complexity
    - high_severity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy
    - rpm_verify_permissions

Rule   Verify File Hashes with RPM   [ref]

Without cryptographic integrity protections, system executables and files can be altered by unauthorized users without detection. The RPM package management system can check the hashes of installed software packages, including many that are important to system security. To verify that the cryptographic hash of system files and commands matches vendor values, run the following command to list which files on the system have hashes that differ from what is expected by the RPM database:
$ rpm -Va --noconfig | grep '^..5'
A "c" in the second column indicates that a file is a configuration file, which may appropriately be expected to change. If the file was not expected to change, investigate the cause of the change using audit logs or other means. The package can then be reinstalled to restore the file. Run the following command to determine which package owns the file:
$ rpm -qf FILENAME
The package can be reinstalled from a yum repository using the command:
$ sudo yum reinstall PACKAGENAME
Alternatively, the package can be reinstalled from trusted media using the command:
$ sudo rpm -Uvh PACKAGENAME
Rationale:
The hashes of important files like system executables should match the information given by the RPM database. Executables with erroneous hashes could be a sign of nefarious activity on the system.
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_rpm_verify_hashes
Identifiers and References

Identifiers:  CCE-27157-7

References:  1.2.6, 5.10.4.1, 3.3.8, 3.4.1, CCI-000366, CCI-001749, 164.308(a)(1)(ii)(D), 164.312(b), 164.312(c)(1), 164.312(c)(2), 164.312(e)(2)(i), CM-6(d), CM-6(c), SI-7, SI-7(1), SI-7(6), AU-9(3), PR.DS-6, PR.DS-8, PR.IP-1, Req-11.5, SRG-OS-000480-GPOS-00227, 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, RHEL-07-010020, SV-214799r603261_rule



# Find which files have incorrect hash (not in /etc, because of the system related config files) and then get files names
files_with_incorrect_hash="$(rpm -Va --noconfig | grep -E '^..5' | awk '{print $NF}' )"

# From files names get package names and change newline to space, because rpm writes each package to new line
packages_to_reinstall="$(rpm -qf $files_with_incorrect_hash | tr '\n' ' ')"

yum reinstall -y $packages_to_reinstall

Complexity:high
Disruption:medium
Strategy:restrict
- name: 'Set fact: Package manager reinstall command (dnf)'
  set_fact:
    package_manager_reinstall_cmd: dnf reinstall -y
  when: ansible_distribution == "Fedora"
  tags:
    - CCE-27157-7
    - CJIS-5.10.4.1
    - DISA-STIG-RHEL-07-010020
    - NIST-800-171-3.3.8
    - NIST-800-171-3.4.1
    - NIST-800-53-AU-9(3)
    - NIST-800-53-CM-6(c)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-SI-7
    - NIST-800-53-SI-7(1)
    - NIST-800-53-SI-7(6)
    - PCI-DSS-Req-11.5
    - high_complexity
    - high_severity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy
    - rpm_verify_hashes

- name: 'Set fact: Package manager reinstall command (yum)'
  set_fact:
    package_manager_reinstall_cmd: yum reinstall -y
  when: (ansible_distribution == "RedHat" or ansible_distribution == "OracleLinux")
  tags:
    - CCE-27157-7
    - CJIS-5.10.4.1
    - DISA-STIG-RHEL-07-010020
    - NIST-800-171-3.3.8
    - NIST-800-171-3.4.1
    - NIST-800-53-AU-9(3)
    - NIST-800-53-CM-6(c)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-SI-7
    - NIST-800-53-SI-7(1)
    - NIST-800-53-SI-7(6)
    - PCI-DSS-Req-11.5
    - high_complexity
    - high_severity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy
    - rpm_verify_hashes

- name: Read files with incorrect hash
  command: rpm -Va --nodeps --nosize --nomtime --nordev --nocaps --nolinkto --nouser
    --nogroup --nomode --noghost --noconfig
  args:
    warn: false
  register: files_with_incorrect_hash
  changed_when: false
  failed_when: files_with_incorrect_hash.rc > 1
  check_mode: false
  when: (package_manager_reinstall_cmd is defined)
  tags:
    - CCE-27157-7
    - CJIS-5.10.4.1
    - DISA-STIG-RHEL-07-010020
    - NIST-800-171-3.3.8
    - NIST-800-171-3.4.1
    - NIST-800-53-AU-9(3)
    - NIST-800-53-CM-6(c)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-SI-7
    - NIST-800-53-SI-7(1)
    - NIST-800-53-SI-7(6)
    - PCI-DSS-Req-11.5
    - high_complexity
    - high_severity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy
    - rpm_verify_hashes

- name: Create list of packages
  command: rpm -qf "{{ item }}"
  args:
    warn: false
  with_items: '{{ files_with_incorrect_hash.stdout_lines | map(''regex_findall'',
    ''^[.]+[5]+.* (\/.*)'', ''\1'') | map(''join'') | select(''match'', ''(\/.*)'')
    | list | unique }}'
  register: list_of_packages
  changed_when: false
  check_mode: false
  when:
    - files_with_incorrect_hash.stdout_lines is defined
    - (files_with_incorrect_hash.stdout_lines | length > 0)
  tags:
    - CCE-27157-7
    - CJIS-5.10.4.1
    - DISA-STIG-RHEL-07-010020
    - NIST-800-171-3.3.8
    - NIST-800-171-3.4.1
    - NIST-800-53-AU-9(3)
    - NIST-800-53-CM-6(c)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-SI-7
    - NIST-800-53-SI-7(1)
    - NIST-800-53-SI-7(6)
    - PCI-DSS-Req-11.5
    - high_complexity
    - high_severity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy
    - rpm_verify_hashes

- name: Reinstall packages of files with incorrect hash
  command: '{{ package_manager_reinstall_cmd }} ''{{ item }}'''
  args:
    warn: false
  with_items: '{{ list_of_packages.results | map(attribute=''stdout_lines'') | list
    | unique }}'
  when:
    - files_with_incorrect_hash.stdout_lines is defined
    - (package_manager_reinstall_cmd is defined and (files_with_incorrect_hash.stdout_lines
      | length > 0))
  tags:
    - CCE-27157-7
    - CJIS-5.10.4.1
    - DISA-STIG-RHEL-07-010020
    - NIST-800-171-3.3.8
    - NIST-800-171-3.4.1
    - NIST-800-53-AU-9(3)
    - NIST-800-53-CM-6(c)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-SI-7
    - NIST-800-53-SI-7(1)
    - NIST-800-53-SI-7(6)
    - PCI-DSS-Req-11.5
    - high_complexity
    - high_severity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy
    - rpm_verify_hashes

Rule   Verify and Correct Ownership with RPM   [ref]

The RPM package management system can check file ownership permissions of installed software packages, including many that are important to system security. After locating a file with incorrect permissions, which can be found with
rpm -Va | awk '{ if (substr($0,6,1)=="U" || substr($0,7,1)=="G") print $NF }'
run the following command to determine which package owns it:
$ rpm -qf FILENAME
Next, run the following command to reset its permissions to the correct values:
$ sudo rpm --setugids PACKAGENAME
Warning:  Profiles may require that specific files be owned by root while the default owner defined by the vendor is different. Such files will be reported as a finding and need to be evaluated according to your policy and deployment environment.
Rationale:
Ownership of binaries and configuration files that is incorrect could allow an unauthorized user to gain privileges that they should not have. The ownership set by the vendor should be maintained. Any deviations from this baseline should be investigated.
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_rpm_verify_ownership
Identifiers and References

Identifiers:  CCE-80545-7

References:  1.7.1.4, 1.7.1.5, 1.7.1.6, 6.1.1, 6.1.2, 6.1.3, 6.1.4, 6.1.5, 6.1.6, 6.1.7, 6.1.8, 6.1.9, 5.10.4.1, 3.3.8, 3.4.1, CCI-001494, CCI-001496, CM-6(d), CM-6(c), SI-7, SI-7(1), SI-7(6), AU-9(3), PR.AC-4, PR.DS-5, PR.IP-1, PR.PT-1, Req-11.5, SRG-OS-000256-GPOS-00097, SRG-OS-000257-GPOS-00098, SRG-OS-000278-GPOS-00108, SR 2.1, SR 2.10, SR 2.11, SR 2.12, SR 2.8, SR 2.9, SR 5.2, SR 7.6, 4.3.3.3.9, 4.3.3.5.8, 4.3.3.7.3, 4.3.4.3.2, 4.3.4.3.3, 4.3.4.4.7, 4.4.2.1, 4.4.2.2, 4.4.2.4, APO01.06, APO11.04, BAI03.05, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.04, DSS05.07, DSS06.02, MEA02.01, A.10.1.1, A.11.1.4, A.11.1.5, A.11.2.1, A.12.1.2, A.12.4.1, A.12.4.2, A.12.4.3, A.12.4.4, A.12.5.1, A.12.6.2, A.12.7.1, A.13.1.1, A.13.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.3, A.9.4.1, A.9.4.4, A.9.4.5, 1, 11, 12, 13, 14, 15, 16, 18, 3, 5, 6, 9, RHEL-07-010010, SV-204392r603261_rule


Complexity:high
Disruption:medium
Strategy:restrict

# Declare array to hold set of RPM packages we need to correct permissions for
declare -A SETPERMS_RPM_DICT

# Create a list of files on the system having permissions different from what
# is expected by the RPM database
readarray -t FILES_WITH_INCORRECT_PERMS < <(rpm -Va --nofiledigest | awk '{ if (substr($0,6,1)=="U" || substr($0,7,1)=="G") print $NF }')

for FILE_PATH in "${FILES_WITH_INCORRECT_PERMS[@]}"
do
        RPM_PACKAGE=$(rpm -qf "$FILE_PATH")
	# Use an associative array to store packages as it's keys, not having to care about duplicates.
	SETPERMS_RPM_DICT["$RPM_PACKAGE"]=1
done

# For each of the RPM packages left in the list -- reset its permissions to the
# correct values
for RPM_PACKAGE in "${!SETPERMS_RPM_DICT[@]}"
do
        rpm --setugids "${RPM_PACKAGE}"
done

Complexity:high
Disruption:medium
Strategy:restrict
- name: Read list of files with incorrect ownership
  command: rpm -Va --nodeps --nosignature --nofiledigest --nosize --nomtime --nordev
    --nocaps --nolinkto --nomode
  args:
    warn: false
  register: files_with_incorrect_ownership
  failed_when: files_with_incorrect_ownership.rc > 1
  changed_when: false
  check_mode: false
  tags:
    - CCE-80545-7
    - CJIS-5.10.4.1
    - DISA-STIG-RHEL-07-010010
    - NIST-800-171-3.3.8
    - NIST-800-171-3.4.1
    - NIST-800-53-AU-9(3)
    - NIST-800-53-CM-6(c)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-SI-7
    - NIST-800-53-SI-7(1)
    - NIST-800-53-SI-7(6)
    - PCI-DSS-Req-11.5
    - high_complexity
    - high_severity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy
    - rpm_verify_ownership

- name: Create list of packages
  command: rpm -qf "{{ item }}"
  args:
    warn: false
  with_items: '{{ files_with_incorrect_ownership.stdout_lines | map(''regex_findall'',
    ''^[.]+[U|G]+.* (\/.*)'', ''\1'') | map(''join'') | select(''match'', ''(\/.*)'')
    | list | unique }}'
  register: list_of_packages
  changed_when: false
  check_mode: false
  when: (files_with_incorrect_ownership.stdout_lines | length > 0)
  tags:
    - CCE-80545-7
    - CJIS-5.10.4.1
    - DISA-STIG-RHEL-07-010010
    - NIST-800-171-3.3.8
    - NIST-800-171-3.4.1
    - NIST-800-53-AU-9(3)
    - NIST-800-53-CM-6(c)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-SI-7
    - NIST-800-53-SI-7(1)
    - NIST-800-53-SI-7(6)
    - PCI-DSS-Req-11.5
    - high_complexity
    - high_severity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy
    - rpm_verify_ownership

- name: Correct file ownership with RPM
  command: rpm --quiet --setugids '{{ item }}'
  args:
    warn: false
  with_items: '{{ list_of_packages.results | map(attribute=''stdout_lines'') | list
    | unique }}'
  when: (files_with_incorrect_ownership.stdout_lines | length > 0)
  tags:
    - CCE-80545-7
    - CJIS-5.10.4.1
    - DISA-STIG-RHEL-07-010010
    - NIST-800-171-3.3.8
    - NIST-800-171-3.4.1
    - NIST-800-53-AU-9(3)
    - NIST-800-53-CM-6(c)
    - NIST-800-53-CM-6(d)
    - NIST-800-53-SI-7
    - NIST-800-53-SI-7(1)
    - NIST-800-53-SI-7(6)
    - PCI-DSS-Req-11.5
    - high_complexity
    - high_severity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy
    - rpm_verify_ownership
Group   Verify Integrity with AIDE   Group contains 7 rules
[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 yum 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

Identifiers:  CCE-27096-7

References:  1.3.1, 5.10.1.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, SR 3.1, SR 3.3, SR 3.4, SR 3.8, SR 4.1, SR 6.2, SR 7.6, 4.3.4.3.2, 4.3.4.3.3, 4.3.4.4.4, 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, 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, 1, 11, 12, 13, 14, 15, 16, 2, 3, 5, 7, 8, 9, BP28(R51), SRG-OS-000363-GPOS-00150, 1034, 1288, 1341, 1417


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
    yum 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:
    - CCE-27096-7
    - 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

Rule   Configure Notification of Post-AIDE Scan Details   [ref]

AIDE should notify appropriate personnel of the details of a scan after the scan has been run. If AIDE has already been configured for periodic execution in /etc/crontab, append the following line to the existing AIDE line:
 | /bin/mail -s "$(hostname) - AIDE Integrity Check" root@localhost
Otherwise, add the following line to /etc/crontab:
05 4 * * * root /usr/sbin/aide --check | /bin/mail -s "$(hostname) - AIDE Integrity Check" root@localhost
AIDE can be executed periodically through other means; this is merely one example.
Rationale:
Unauthorized changes to the baseline configuration could make the system vulnerable to various attacks or allow unauthorized access to the operating system. Changes to operating system configurations can have unintended side effects, some of which may be relevant to security.

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

Identifiers:  CCE-80374-2

References:  BP28(R51), CCI-001744, CM-6(a), CM-3(5), DE.CM-1, DE.CM-7, PR.IP-1, PR.IP-3, SRG-OS-000363-GPOS-00150, SR 6.2, SR 7.6, 4.3.4.3.2, 4.3.4.3.3, BAI01.06, BAI06.01, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS01.03, DSS03.05, DSS05.02, DSS05.05, DSS05.07, A.12.1.2, A.12.4.1, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, A.14.2.7, A.15.2.1, 1, 11, 12, 13, 15, 16, 2, 3, 5, 7, 8, 9, RHEL-07-020040, SV-204446r603261_rule


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

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

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

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

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

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

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

fi

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

Rule   Build and Test AIDE Database   [ref]

Run the following command to generate a new database:
$ sudo /usr/sbin/aide --init
By default, the database will be written to the file /var/lib/aide/aide.db.new.gz. Storing the database, the configuration file /etc/aide.conf, and the binary /usr/sbin/aide (or hashes of these files), in a secure location (such as on read-only media) provides additional assurance about their integrity. The newly-generated database can be installed as follows:
$ sudo cp /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz
To initiate a manual check, run the following command:
$ sudo /usr/sbin/aide --check
If this check produces any unexpected output, investigate.
Rationale:
For AIDE to be effective, an initial database of "known-good" information about files must be captured and it should be able to be verified against the installed files.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_aide_build_database
Identifiers and References

Identifiers:  CCE-27220-3

References:  BP28(R51), 5.10.1.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, SR 3.1, SR 3.3, SR 3.4, SR 3.8, SR 4.1, SR 6.2, SR 7.6, 4.3.4.3.2, 4.3.4.3.3, 4.3.4.4.4, 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, 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, 1, 11, 12, 13, 14, 15, 16, 2, 3, 5, 7, 8, 9


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

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

/usr/sbin/aide --init
/bin/cp -p /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Ensure AIDE is installed
  package:
    name: '{{ item }}'
    state: present
  with_items:
    - aide
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-27220-3
    - CJIS-5.10.1.3
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-11.5
    - aide_build_database
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Build and Test AIDE Database
  command: /usr/sbin/aide --init
  changed_when: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-27220-3
    - CJIS-5.10.1.3
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-11.5
    - aide_build_database
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Check whether the stock AIDE Database exists
  stat:
    path: /var/lib/aide/aide.db.new.gz
  register: aide_database_stat
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-27220-3
    - CJIS-5.10.1.3
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-11.5
    - aide_build_database
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Stage AIDE Database
  copy:
    src: /var/lib/aide/aide.db.new.gz
    dest: /var/lib/aide/aide.db.gz
    backup: true
    remote_src: true
  when:
    - (aide_database_stat.stat.exists is defined and aide_database_stat.stat.exists)
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-27220-3
    - CJIS-5.10.1.3
    - NIST-800-53-CM-6(a)
    - PCI-DSS-Req-11.5
    - aide_build_database
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Configure AIDE to Verify Access Control Lists (ACLs)   [ref]

By default, the acl option is added to the FIPSR ruleset in AIDE. If using a custom ruleset or the acl option is missing, add acl to the appropriate ruleset. For example, add acl to the following line in /etc/aide.conf:
FIPSR = p+i+n+u+g+s+m+c+acl+selinux+xattrs+sha256
AIDE rules can be configured in multiple ways; this is merely one example that is already configured by default.
Rationale:
ACLs can provide permissions beyond those permitted through the file mode and must be verified by the file integrity tools.
Severity: 
low
Rule ID:xccdf_org.ssgproject.content_rule_aide_verify_acls
Identifiers and References

Identifiers:  CCE-80375-9

References:  BP28(R51), CCI-000366, SI-7, SI-7(1), CM-6(a), PR.DS-6, PR.DS-8, SRG-OS-000480-GPOS-00227, SR 3.1, SR 3.3, SR 3.4, SR 3.8, 4.3.4.4.4, APO01.06, BAI03.05, BAI06.01, DSS06.02, A.11.2.4, A.12.2.1, A.12.5.1, A.14.1.2, A.14.1.3, A.14.2.4, 2, 3, RHEL-07-021600, SV-204498r603261_rule


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

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

aide_conf="/etc/aide.conf"

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

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

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

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

Rule   Configure AIDE to Verify Extended Attributes   [ref]

By default, the xattrs option is added to the FIPSR ruleset in AIDE. If using a custom ruleset or the xattrs option is missing, add xattrs to the appropriate ruleset. For example, add xattrs to the following line in /etc/aide.conf:
FIPSR = p+i+n+u+g+s+m+c+acl+selinux+xattrs+sha256
AIDE rules can be configured in multiple ways; this is merely one example that is already configured by default.
Rationale:
Extended attributes in file systems are used to contain arbitrary data and file metadata with security implications.
Severity: 
low
Rule ID:xccdf_org.ssgproject.content_rule_aide_verify_ext_attributes
Identifiers and References

Identifiers:  CCE-80376-7

References:  BP28(R51), CCI-000366, SI-7, SI-7(1), CM-6(a), PR.DS-6, PR.DS-8, SRG-OS-000480-GPOS-00227, SR 3.1, SR 3.3, SR 3.4, SR 3.8, 4.3.4.4.4, APO01.06, BAI03.05, BAI06.01, DSS06.02, A.11.2.4, A.12.2.1, A.12.5.1, A.14.1.2, A.14.1.3, A.14.2.4, 2, 3, RHEL-07-021610, SV-204499r603261_rule


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

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

aide_conf="/etc/aide.conf"

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

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

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

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

Rule   Configure Periodic Execution of AIDE   [ref]

At a minimum, AIDE should be configured to run a weekly scan. To implement a daily execution of AIDE at 4:05am using cron, add the following line to /etc/crontab:
05 4 * * * root /usr/sbin/aide --check
To implement a weekly execution of AIDE at 4:05am using cron, add the following line to /etc/crontab:
05 4 * * 0 root /usr/sbin/aide --check
AIDE can be executed periodically through other means; this is merely one example. The usage of cron's special time codes, such as @daily and @weekly is acceptable.
Rationale:
By default, AIDE does not install itself for periodic execution. Periodically running AIDE is necessary to reveal unexpected changes in installed files.

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

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

Identifiers:  CCE-26952-2

References:  BP28(R51), 1.3.2, 5.10.1.3, CCI-001744, CCI-002699, SI-7, SI-7(1), 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-000446-GPOS-00200, SR 3.1, SR 3.3, SR 3.4, SR 3.8, SR 4.1, SR 6.2, SR 7.6, 4.3.4.3.2, 4.3.4.3.3, 4.3.4.4.4, 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, 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, 1, 11, 12, 13, 14, 15, 16, 2, 3, 5, 7, 8, 9, RHEL-07-020030, SV-204445r603261_rule


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

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

if ! grep -q "/usr/sbin/aide --check" /etc/crontab ; then
    echo "05 4 * * * root /usr/sbin/aide --check" >> /etc/crontab
else
    sed -i '/^.*\/usr\/sbin\/aide --check.*$/d' /etc/crontab
    echo "05 4 * * * root /usr/sbin/aide --check" >> /etc/crontab
fi

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

Complexity:low
Disruption:low
Strategy:restrict
- name: Ensure AIDE is installed
  package:
    name: '{{ item }}'
    state: present
  with_items:
    - aide
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-26952-2
    - CJIS-5.10.1.3
    - DISA-STIG-RHEL-07-020030
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SI-7
    - NIST-800-53-SI-7(1)
    - PCI-DSS-Req-11.5
    - aide_periodic_cron_checking
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Configure Periodic Execution of AIDE
  cron:
    name: run AIDE check
    minute: 5
    hour: 4
    weekday: 0
    user: root
    job: /usr/sbin/aide --check
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-26952-2
    - CJIS-5.10.1.3
    - DISA-STIG-RHEL-07-020030
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SI-7
    - NIST-800-53-SI-7(1)
    - PCI-DSS-Req-11.5
    - aide_periodic_cron_checking
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Configure AIDE to Use FIPS 140-2 for Validating Hashes   [ref]

By default, the sha512 option is added to the NORMAL ruleset in AIDE. If using a custom ruleset or the sha512 option is missing, add sha512 to the appropriate ruleset. For example, add sha512 to the following line in /etc/aide.conf:
NORMAL = FIPSR+sha512
AIDE rules can be configured in multiple ways; this is merely one example that is already configured by default.
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:
File integrity tools use cryptographic hashes for verifying file contents and directories have not been altered. These hashes must be FIPS 140-2 approved cryptographic hashes.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_aide_use_fips_hashes
Identifiers and References

Identifiers:  CCE-80377-5

References:  3.13.11, CCI-000366, SI-7, SI-7(1), CM-6(a), PR.DS-6, PR.DS-8, SRG-OS-000480-GPOS-00227, SR 3.1, SR 3.3, SR 3.4, SR 3.8, 4.3.4.4.4, APO01.06, BAI03.05, BAI06.01, DSS06.02, A.11.2.4, A.12.2.1, A.12.5.1, A.14.1.2, A.14.1.3, A.14.2.4, 2, 3, RHEL-07-021620, SV-204500r603261_rule


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

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

aide_conf="/etc/aide.conf"
forbidden_hashes=(sha1 rmd160 sha256 whirlpool tiger haval gost crc32)

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

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

	if ! [[ $config = *sha512* ]]
	then
		config=$config"+sha512"
	fi

	for hash in ${forbidden_hashes[@]}
	do
		config=$(echo $config | sed "s/$hash//")
	done

	config=$(echo $config | sed "s/^\+*//")
	config=$(echo $config | sed "s/\+\++/+/")
	config=$(echo $config | sed "s/\+$//")

	sed -i "s/^$group\s*=.*/$group = $config/g" $aide_conf
done

else
    >&2 echo 'Remediation is not applicable, nothing was done'
fi
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 Red Hat Enterprise Linux 7.

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

Rule   Install the dracut-fips Package   [ref]

To enable FIPS, the system requires that the dracut-fips package be installed. The dracut-fips package can be installed with the following command:
$ sudo yum install dracut-fips
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_package_dracut-fips_installed
Identifiers and References

Identifiers:  CCE-80358-5

References:  5.10.1.2, 3.13.11, 3.13.8, CCI-000068, CCI-000803, CCI-002450, SC-12(2), SC-12(3), IA-7, SC-13, CM-6(a), SC-12, PR.AC-3, PR.PT-4, SRG-OS-000033-GPOS-00014, SRG-OS-000396-GPOS-00176, SRG-OS-000478-GPOS-00223, SRG-OS-000120-VMM-000600, SRG-OS-000478-VMM-001980, SRG-OS-000396-VMM-001590, SR 1.13, SR 2.6, 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, 4.3.3.6.6, APO13.01, DSS01.04, DSS05.02, DSS05.03, A.11.2.6, A.13.1.1, A.13.2.1, A.14.1.3, A.6.2.1, A.6.2.2, 12, 15, 8


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

if ! rpm -q --quiet "dracut-fips" ; then
    yum install -y "dracut-fips"
fi

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

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure dracut-fips is installed
  package:
    name: dracut-fips
    state: present
  when:
    - ansible_distribution == 'RedHat'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80358-5
    - CJIS-5.10.1.2
    - NIST-800-171-3.13.11
    - NIST-800-171-3.13.8
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-7
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(2)
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SC-13
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_dracut-fips_installed


package --add=dracut-fips

Rule   Enable FIPS Mode in GRUB2   [ref]

To ensure FIPS mode is enabled, install package dracut-fips, and rebuild initramfs by running the following commands:
$ sudo yum install dracut-fips
dracut -f
After the dracut command has been run, add the argument fips=1 to the default GRUB 2 command line for the Linux operating system in /etc/default/grub, in the manner below:
GRUB_CMDLINE_LINUX="crashkernel=auto rd.lvm.lv=VolGroup/LogVol06 rd.lvm.lv=VolGroup/lv_swap rhgb quiet rd.shell=0 fips=1"
Finally, rebuild the grub.cfg file by using the
grub2-mkconfig -o
command as follows:
  • On BIOS-based machines, issue the following command as root:
    ~]# grub2-mkconfig -o /boot/grub2/grub.cfg
  • On UEFI-based machines, issue the following command as root:
    ~]# grub2-mkconfig -o /boot/efi/EFI/redhat/grub.cfg
Warning:  Running
dracut -f
will overwrite the existing initramfs file.
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: 
high
Rule ID:xccdf_org.ssgproject.content_rule_grub2_enable_fips_mode
Identifiers and References

Identifiers:  CCE-80359-3

References:  5.10.1.2, 3.13.8, 3.13.11, CCI-000068, CCI-000803, CCI-001199, CCI-002450, CCI-002476, SC-12(2), SC-12(3), IA-7, SC-13, CM-6(a), SC-12, PR.AC-3, PR.PT-4, SRG-OS-000033-GPOS-00014, SRG-OS-000185-GPOS-00079, SRG-OS-000396-GPOS-00176, SRG-OS-000405-GPOS-00184, SRG-OS-000478-GPOS-00223, SRG-OS-000120-VMM-000600, SRG-OS-000478-VMM-001980, SRG-OS-000396-VMM-001590, SR 1.13, SR 2.6, 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, 4.3.3.6.6, APO13.01, DSS01.04, DSS05.02, DSS05.03, A.11.2.6, A.13.1.1, A.13.2.1, A.14.1.3, A.6.2.1, A.6.2.2, 12, 15, 8, RHEL-07-021350, SV-204497r603261_rule


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

# include remediation functions library


# prelink not installed
if test -e /etc/sysconfig/prelink -o -e /usr/sbin/prelink; then
    if grep -q ^PRELINKING /etc/sysconfig/prelink
    then
        sed -i 's/^PRELINKING[:blank:]*=[:blank:]*[:alpha:]*/PRELINKING=no/' /etc/sysconfig/prelink
    else
        printf '\n' >> /etc/sysconfig/prelink
        printf '%s\n' '# Set PRELINKING=no per security requirements' 'PRELINKING=no' >> /etc/sysconfig/prelink
    fi

    # Undo previous prelink changes to binaries if prelink is available.
    if test -x /usr/sbin/prelink; then
        /usr/sbin/prelink -ua
    fi
fi

if grep -q -m1 -o aes /proc/cpuinfo; then
	if ! rpm -q --quiet "dracut-fips-aesni" ; then
    yum install -y "dracut-fips-aesni"
fi
fi
if ! rpm -q --quiet "dracut-fips" ; then
    yum install -y "dracut-fips"
fi

dracut -f

# Correct the form of default kernel command line in  grub
if grep -q '^GRUB_CMDLINE_LINUX=.*fips=.*"'  /etc/default/grub; then
	# modify the GRUB command-line if a fips= arg already exists
	sed -i 's/\(^GRUB_CMDLINE_LINUX=".*\)fips=[^[:space:]]*\(.*"\)/\1 fips=1 \2/'  /etc/default/grub
else
	# no existing fips=arg is present, append it
	sed -i 's/\(^GRUB_CMDLINE_LINUX=".*\)"/\1 fips=1"/'  /etc/default/grub
fi

# Get the UUID of the device mounted at root (/).
ROOT_UUID=$(findmnt --noheadings --output uuid --target /)

# Get the UUID of the device mounted at /boot.
BOOT_UUID=$(findmnt --noheadings --output uuid --target /boot)

if [ "${ROOT_UUID}" == "${BOOT_UUID}" ]; then
	# root UUID same as boot UUID, so do not modify the GRUB command-line or add boot arg to kernel command line
	# Correct the form of kernel command line for each installed kernel in the bootloader
	/sbin/grubby --update-kernel=ALL --args="fips=1"
else
	# root UUID different from boot UUID, so modify the GRUB command-line and add boot arg to kernel command line
	if grep -q '^GRUB_CMDLINE_LINUX=".*boot=.*"'  /etc/default/grub; then
		# modify the GRUB command-line if a boot= arg already exists
		sed -i 's/\(^GRUB_CMDLINE_LINUX=".*\)boot=[^[:space:]]*\(.*"\)/\1 boot=UUID='"${BOOT_UUID} \2/" /etc/default/grub
	else
		# no existing boot=arg is present, append it
		sed -i 's/\(^GRUB_CMDLINE_LINUX=".*\)"/\1 boot=UUID='${BOOT_UUID}'"/'  /etc/default/grub
	fi
	# Correct the form of kernel command line for each installed kernel in the bootloader
	/sbin/grubby --update-kernel=ALL --args="fips=1 boot=UUID=${BOOT_UUID}"
fi

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

Complexity:high
Disruption:medium
Reboot:true
Strategy:restrict
- name: check prelink binary installed
  stat:
    path: /usr/sbin/prelink
  register: prelink_exists
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80359-3
    - CJIS-5.10.1.2
    - DISA-STIG-RHEL-07-021350
    - NIST-800-171-3.13.11
    - NIST-800-171-3.13.8
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-7
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(2)
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SC-13
    - grub2_enable_fips_mode
    - high_complexity
    - high_severity
    - medium_disruption
    - reboot_required
    - restrict_strategy

- name: disable prelink
  lineinfile:
    dest: /etc/sysconfig/prelink
    regexp: ^#?PRELINKING
    line: PRELINKING=no
  when:
    - prelink_exists.stat.exists
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80359-3
    - CJIS-5.10.1.2
    - DISA-STIG-RHEL-07-021350
    - NIST-800-171-3.13.11
    - NIST-800-171-3.13.8
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-7
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(2)
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SC-13
    - grub2_enable_fips_mode
    - high_complexity
    - high_severity
    - medium_disruption
    - reboot_required
    - restrict_strategy

- name: revert prelinking binaries
  command: /usr/sbin/prelink -ua
  when:
    - prelink_exists.stat.exists
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80359-3
    - CJIS-5.10.1.2
    - DISA-STIG-RHEL-07-021350
    - NIST-800-171-3.13.11
    - NIST-800-171-3.13.8
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-7
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(2)
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SC-13
    - grub2_enable_fips_mode
    - high_complexity
    - high_severity
    - medium_disruption
    - reboot_required
    - restrict_strategy

- name: Check if system supports AES-NI
  command: grep -q -m1 -o aes /proc/cpuinfo
  failed_when: aesni_supported.rc > 1
  register: aesni_supported
  check_mode: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80359-3
    - CJIS-5.10.1.2
    - DISA-STIG-RHEL-07-021350
    - NIST-800-171-3.13.11
    - NIST-800-171-3.13.8
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-7
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(2)
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SC-13
    - grub2_enable_fips_mode
    - high_complexity
    - high_severity
    - medium_disruption
    - reboot_required
    - restrict_strategy

- name: Ensure dracut-fips-aesni is installed
  package:
    name: dracut-fips-aesni
    state: present
  when:
    - aesni_supported.rc == 0
    - ansible_distribution == 'RedHat'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80359-3
    - CJIS-5.10.1.2
    - DISA-STIG-RHEL-07-021350
    - NIST-800-171-3.13.11
    - NIST-800-171-3.13.8
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-7
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(2)
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SC-13
    - grub2_enable_fips_mode
    - high_complexity
    - high_severity
    - medium_disruption
    - reboot_required
    - restrict_strategy

- name: install dracut-fips
  package:
    name: dracut-fips
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80359-3
    - CJIS-5.10.1.2
    - DISA-STIG-RHEL-07-021350
    - NIST-800-171-3.13.11
    - NIST-800-171-3.13.8
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-7
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(2)
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SC-13
    - grub2_enable_fips_mode
    - high_complexity
    - high_severity
    - medium_disruption
    - reboot_required
    - restrict_strategy

- name: Rebuild initramfs
  command: dracut -f
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80359-3
    - CJIS-5.10.1.2
    - DISA-STIG-RHEL-07-021350
    - NIST-800-171-3.13.11
    - NIST-800-171-3.13.8
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-7
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(2)
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SC-13
    - grub2_enable_fips_mode
    - high_complexity
    - high_severity
    - medium_disruption
    - reboot_required
    - restrict_strategy

- name: check fips argument exists
  command: grep 'GRUB_CMDLINE_LINUX.*fips=' /etc/default/grub
  failed_when: false
  register: fipsargcheck
  check_mode: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80359-3
    - CJIS-5.10.1.2
    - DISA-STIG-RHEL-07-021350
    - NIST-800-171-3.13.11
    - NIST-800-171-3.13.8
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-7
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(2)
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SC-13
    - grub2_enable_fips_mode
    - high_complexity
    - high_severity
    - medium_disruption
    - reboot_required
    - restrict_strategy

- name: replace existing fips argument
  replace:
    path: /etc/default/grub
    regexp: fips=.
    replace: fips=1
  when:
    - fipsargcheck.rc == 0
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80359-3
    - CJIS-5.10.1.2
    - DISA-STIG-RHEL-07-021350
    - NIST-800-171-3.13.11
    - NIST-800-171-3.13.8
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-7
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(2)
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SC-13
    - grub2_enable_fips_mode
    - high_complexity
    - high_severity
    - medium_disruption
    - reboot_required
    - restrict_strategy

- name: add fips argument
  replace:
    path: /etc/default/grub
    regexp: (GRUB_CMDLINE_LINUX=.*)"
    replace: \1 fips=1"
  when:
    - fipsargcheck.rc != 0
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80359-3
    - CJIS-5.10.1.2
    - DISA-STIG-RHEL-07-021350
    - NIST-800-171-3.13.11
    - NIST-800-171-3.13.8
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-7
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(2)
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SC-13
    - grub2_enable_fips_mode
    - high_complexity
    - high_severity
    - medium_disruption
    - reboot_required
    - restrict_strategy

- name: get boot device uuid
  command: findmnt --noheadings --output uuid --target /boot
  register: bootuuid
  check_mode: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80359-3
    - CJIS-5.10.1.2
    - DISA-STIG-RHEL-07-021350
    - NIST-800-171-3.13.11
    - NIST-800-171-3.13.8
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-7
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(2)
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SC-13
    - grub2_enable_fips_mode
    - high_complexity
    - high_severity
    - medium_disruption
    - reboot_required
    - restrict_strategy

- name: check boot argument exists
  command: grep 'GRUB_CMDLINE_LINUX.*boot=' /etc/default/grub
  failed_when: false
  register: bootargcheck
  check_mode: false
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80359-3
    - CJIS-5.10.1.2
    - DISA-STIG-RHEL-07-021350
    - NIST-800-171-3.13.11
    - NIST-800-171-3.13.8
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-7
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(2)
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SC-13
    - grub2_enable_fips_mode
    - high_complexity
    - high_severity
    - medium_disruption
    - reboot_required
    - restrict_strategy

- name: replace existing boot argument
  replace:
    path: /etc/default/grub
    regexp: boot=\w*-\w*-\w*-\w*-\w*
    replace: boot={{ bootuuid.stdout }}
  when:
    - bootargcheck.rc == 0
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80359-3
    - CJIS-5.10.1.2
    - DISA-STIG-RHEL-07-021350
    - NIST-800-171-3.13.11
    - NIST-800-171-3.13.8
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-7
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(2)
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SC-13
    - grub2_enable_fips_mode
    - high_complexity
    - high_severity
    - medium_disruption
    - reboot_required
    - restrict_strategy

- name: add boot argument
  replace:
    path: /etc/default/grub
    regexp: (GRUB_CMDLINE_LINUX=.*)"
    replace: \1 boot=UUID={{ bootuuid.stdout }}"
  when:
    - bootargcheck.rc != 0
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80359-3
    - CJIS-5.10.1.2
    - DISA-STIG-RHEL-07-021350
    - NIST-800-171-3.13.11
    - NIST-800-171-3.13.8
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-7
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(2)
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SC-13
    - grub2_enable_fips_mode
    - high_complexity
    - high_severity
    - medium_disruption
    - reboot_required
    - restrict_strategy

- name: update bootloader menu
  command: /sbin/grubby --update-kernel=ALL --args="fips=1 boot=UUID={{ bootuuid.stdout
    }}"
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80359-3
    - CJIS-5.10.1.2
    - DISA-STIG-RHEL-07-021350
    - NIST-800-171-3.13.11
    - NIST-800-171-3.13.8
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-7
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(2)
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SC-13
    - grub2_enable_fips_mode
    - high_complexity
    - high_severity
    - medium_disruption
    - reboot_required
    - restrict_strategy


package --add=dracut-fips --add=dracut-fips-aesni
Group   Operating System Vendor Support and Certification   Group contains 1 rule
[ref]   The assurance of a vendor to provide operating system support and maintenance for their product is an important criterion to ensure product stability and security over the life of the product. A certified product that follows the necessary standards and government certification requirements guarantees that known software vulnerabilities will be remediated, and proper guidance for protecting and securing the operating system will be given.

Rule   The Installed Operating System Is FIPS 140-2 Certified   [ref]

To enable processing of sensitive information the operating system must provide certified cryptographic modules compliant with FIPS 140-2 standard. Red Hat Enterprise Linux is supported by Red Hat, Inc. As the Red Hat Enterprise Linux vendor, Red Hat, Inc. is responsible for maintaining government certifications and standards.
Warning:  There is no remediation besides switching to a different operating system.
Warning:  System Crypto Modules must be provided by a vendor that undergoes FIPS-140 certifications. FIPS-140 is applicable to all Federal agencies that use cryptographic-based security systems to protect sensitive information in computer and telecommunication systems (including voice systems) as defined in Section 5131 of the Information Technology Management Reform Act of 1996, Public Law 104-106. This standard shall be used in designing and implementing cryptographic modules that Federal departments and agencies operate or are operated for them under contract. See https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.140-2.pdf To meet this, the system has to have cryptographic software provided by a vendor that has undergone this certification. This means providing documentation, test results, design information, and independent third party review by an accredited lab. While open source software is capable of meeting this, it does not meet FIPS-140 unless the vendor submits to this process.
Rationale:
The Federal Information Processing Standard (FIPS) Publication 140-2, (FIPS PUB 140-2) is a computer security standard. The standard specifies security requirements for cryptographic modules used to protect sensitive unclassified information. Refer to the full FIPS 140-2 standard at http://csrc.nist.gov/publications/fips/fips140-2/fips1402.pdf for further details on the requirements. FIPS 140-2 validation is required by U.S. law when information systems use cryptography to protect sensitive government information. In order to achieve FIPS 140-2 certification, cryptographic modules are subject to extensive testing by independent laboratories, accredited by National Institute of Standards and Technology (NIST).
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_installed_OS_is_FIPS_certified
Identifiers and References

Identifiers:  CCE-80657-0

References:  CCI-000803, CCI-002450, SC-12(2), SC-12(3), IA-7, SC-13, CM-6(a), SC-12, SRG-OS-000120-VMM-000600, SRG-OS-000478-VMM-001980, SRG-OS-000396-VMM-001590

Group   Endpoint Protection Software   Group contains 2 rules
[ref]   Endpoint protection security software that is not provided or supported by Red Hat can be installed to provide complementary or duplicative security capabilities to those provided by the base platform. Add-on software may not be appropriate for some specialized systems.

Rule   Install Intrusion Detection Software   [ref]

The base Red Hat Enterprise Linux 7 platform already includes a sophisticated auditing system that can detect intruder activity, as well as SELinux, which provides host-based intrusion prevention capabilities by confining privileged programs and user sessions which may become compromised.
Warning:  In DoD environments, supplemental intrusion detection and antivirus tools, such as the McAfee Host-based Security System, are available to integrate with existing infrastructure. Per DISA guidance, when these supplemental tools interfere with proper functioning of SELinux, SELinux takes precedence. Should further clarification be required, DISA contact information is published publicly at https://public.cyber.mil/stigs/
Rationale:
Host-based intrusion detection tools provide a system-level defense when an intruder gains access to a system or network.
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_install_hids
Identifiers and References

Identifiers:  CCE-26818-5

References:  CCI-001263, CM-6(a), DE.CM-1, PR.AC-5, PR.DS-5, PR.PT-4, Req-11.4, 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.6, 4.3.3.4, APO01.06, APO13.01, DSS01.03, DSS01.05, DSS03.05, DSS05.02, DSS05.04, DSS05.07, DSS06.02, 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, 1, 12, 13, 14, 15, 16, 18, 7, 8, 9

Rule   Install Virus Scanning Software   [ref]

Virus scanning software can be used to protect a system from penetration from computer viruses and to limit their spread through intermediate systems. The virus scanning software should be configured to perform scans dynamically on accessed files. If this capability is not available, the system must be configured to scan, at a minimum, all altered files on the system on a daily basis. If the system processes inbound SMTP mail, the virus scanner must be configured to scan all received mail.
Rationale:
Virus scanning software can be used to detect if a system has been compromised by computer viruses, as well as to limit their spread to other systems.
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_install_antivirus
Identifiers and References

Identifiers:  CCE-27140-3

References:  CCI-000366, CCI-001239, CCI-001668, CM-6(a), DE.CM-4, DE.DP-3, PR.DS-1, SRG-OS-000480-GPOS-00227, SR 3.2, SR 3.3, SR 3.4, SR 4.1, 4.3.4.3.8, 4.4.3.2, APO01.06, APO13.02, BAI02.01, BAI06.01, DSS04.07, DSS05.01, DSS05.02, DSS05.03, DSS06.06, A.12.2.1, A.14.2.8, A.8.2.3, 12, 13, 14, 4, 7, 8, RHEL-07-032000, SV-214801r603261_rule

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 /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

Identifiers:  CCE-82014-2

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


Complexity:low
Disruption:high
Strategy:enable

part /var

Rule   Ensure /tmp Located On Separate Partition   [ref]

The /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 /tmp partition is used as temporary storage by many programs. Placing /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_tmp
Identifiers and References

Identifiers:  CCE-82053-0

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


Complexity:low
Disruption:high
Strategy:enable

part /tmp

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

Audit logs are stored in the /var/log/audit directory. Ensure that it has its own partition or logical volume at installation time, or migrate it later using LVM. Make absolutely certain that it is large enough to store all audit logs that will be created by the auditing daemon.
Rationale:
Placing /var/log/audit in its own partition enables better separation between audit files and other files, and helps ensure that auditing cannot be halted due to the partition running out of space.
Severity: 
low
Rule ID:xccdf_org.ssgproject.content_rule_partition_for_var_log_audit
Identifiers and References

Identifiers:  CCE-82035-7

References:  1.1.12, CCI-000366, CCI-001849, 164.312(a)(2)(ii), 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, 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, 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, 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, APO11.04, APO13.01, BAI03.05, BAI04.04, DSS05.02, DSS05.04, DSS05.07, MEA02.01, 1, 12, 13, 14, 15, 16, 2, 3, 5, 6, 8, BP28(R43), RHEL-07-021330, SV-204495r603261_rule


Complexity:low
Disruption:high
Strategy:enable

part /var/log/audit

Rule   Encrypt Partitions   [ref]

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

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

For automated/unattended installations, it is possible to use Kickstart by adding the --encrypted and --passphrase= options to the definition of each partition to be encrypted. For example, the following line would encrypt the root partition:
part / --fstype=ext4 --size=100 --onpart=hda1 --encrypted --passphrase=PASSPHRASE
Any PASSPHRASE is stored in the Kickstart in plaintext, and the Kickstart must then be protected accordingly. Omitting the --passphrase= option from the partition definition will cause the installer to pause and interactively ask for the passphrase during installation.

By default, the Anaconda installer uses aes-xts-plain64 cipher with a minimum 512 bit key size which should be compatible with FIPS enabled.

Detailed information on encrypting partitions using LUKS or LUKS ciphers can be found on the Red Hat Enterprise Linux 7 Documentation web site:
https://access.redhat.com/documentation/en-US/Red_Hat_Enterprise_Linux/7/html/Security_Guide/sec-Encryption.html.
Rationale:
The risk of a system's physical compromise, particularly mobile systems such as laptops, places its data at risk of compromise. Encrypting this data mitigates the risk of its loss if the system is lost.
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_encrypt_partitions
Identifiers and References

Identifiers:  CCE-27128-8

References:  3.13.16, CCI-001199, CCI-002475, CCI-002476, 164.308(a)(1)(ii)(D), 164.308(b)(1), 164.310(d), 164.312(a)(1), 164.312(a)(2)(iii), 164.312(a)(2)(iv), 164.312(b), 164.312(c), 164.314(b)(2)(i), 164.312(d), 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), SC-28, SC-28(1), SC-13, AU-9(3), PR.DS-1, PR.DS-5, SRG-OS-000405-GPOS-00184, SRG-OS-000185-GPOS-00079, SRG-OS-000404-GPOS-00183, SRG-OS-000404-VMM-001650, SRG-OS-000405-VMM-001660, SR 3.4, SR 4.1, SR 5.2, APO01.06, BAI02.01, BAI06.01, DSS04.07, DSS05.03, DSS05.04, DSS05.07, DSS06.02, DSS06.06, 13, 14

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

Identifiers:  CCE-80144-9

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


Complexity:low
Disruption:high
Strategy:enable

part /home
Group   Updating Software   Group contains 6 rules
[ref]   The yum 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.

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

Rule   Ensure yum Removes Previous Package Versions   [ref]

yum should be configured to remove previous software components after new versions have been installed. To configure yum to remove the previous software components after updating, set the clean_requirements_on_remove to 1 in /etc/yum.conf.
Rationale:
Previous versions of software components that are not removed from the information system after updates have been installed may be exploited by some adversaries.
Severity: 
low
Rule ID:xccdf_org.ssgproject.content_rule_clean_components_post_updating
Identifiers and References

Identifiers:  CCE-80346-0

References:  3.4.8, CCI-002617, SI-2(6), CM-11(a), CM-11(b), CM-6(a), ID.RA-1, PR.IP-12, SRG-OS-000437-GPOS-00194, SRG-OS-000437-VMM-001760, 4.2.3, 4.2.3.12, 4.2.3.7, 4.2.3.9, APO12.01, APO12.02, APO12.03, APO12.04, BAI03.10, DSS05.01, DSS05.02, A.12.6.1, A.14.2.3, A.16.1.3, A.18.2.2, A.18.2.3, 18, 20, 4, RHEL-07-020200, SV-204452r603261_rule


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

if grep --silent ^clean_requirements_on_remove /etc/yum.conf ; then
        sed -i "s/^clean_requirements_on_remove.*/clean_requirements_on_remove=1/g" /etc/yum.conf
else
        echo -e "\n# Set clean_requirements_on_remove to 1 per security requirements" >> /etc/yum.conf
        echo "clean_requirements_on_remove=1" >> /etc/yum.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:
    - CCE-80346-0
    - DISA-STIG-RHEL-07-020200
    - NIST-800-171-3.4.8
    - NIST-800-53-CM-11(a)
    - NIST-800-53-CM-11(b)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SI-2(6)
    - clean_components_post_updating
    - low_complexity
    - low_disruption
    - low_severity
    - no_reboot_needed
    - restrict_strategy

- name: Ensure YUM Removes Previous Package Versions
  lineinfile:
    dest: /etc/yum.conf
    regexp: ^#?clean_requirements_on_remove
    line: clean_requirements_on_remove=1
    insertafter: \[main\]
    create: true
  when: '"yum" in ansible_facts.packages'
  tags:
    - CCE-80346-0
    - DISA-STIG-RHEL-07-020200
    - NIST-800-171-3.4.8
    - NIST-800-53-CM-11(a)
    - NIST-800-53-CM-11(b)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SI-2(6)
    - clean_components_post_updating
    - low_complexity
    - low_disruption
    - low_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Ensure gpgcheck Enabled for All yum 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

Identifiers:  CCE-26876-3

References:  SRG-OS-000366-GPOS-00153, SRG-OS-000366-VMM-001430, SRG-OS-000370-VMM-001460, SRG-OS-000404-VMM-001650, 5.10.4.1, 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), 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, 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, BP28(R15)


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

Complexity:low
Disruption:medium
Strategy:enable
- name: Grep for yum repo section names
  shell: grep -HEr '^\[.+\]' -r /etc/yum.repos.d/
  register: repo_grep_results
  ignore_errors: true
  changed_when: false
  tags:
    - CCE-26876-3
    - 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 yum 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:
    - CCE-26876-3
    - 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   Ensure Software Patches Installed   [ref]

If the system is joined to the Red Hat Network, a Red Hat Satellite Server, or a yum server, run the following command to install updates:
$ sudo yum update
If the system is not configured to use one of these sources, updates (in the form of RPM packages) can be manually downloaded from the Red Hat Network and installed using rpm.

NOTE: U.S. Defense systems are required to be patched within 30 days or sooner as local policy dictates.
Rationale:
Installing software updates is a fundamental mitigation against the exploitation of publicly-known vulnerabilities. If the most recent security patches and updates are not installed, unauthorized users may take advantage of weaknesses in the unpatched software. The lack of prompt attention to patching could result in a system compromise.
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_security_patches_up_to_date
Identifiers and References

Identifiers:  CCE-26895-3

References:  1.8, 5.10.4.1, CCI-000366, SI-2(5), SI-2(c), CM-6(a), ID.RA-1, PR.IP-12, FMT_MOF_EXT.1, Req-6.2, SRG-OS-000480-GPOS-00227, SRG-OS-000480-VMM-002000, 4.2.3, 4.2.3.12, 4.2.3.7, 4.2.3.9, APO12.01, APO12.02, APO12.03, APO12.04, BAI03.10, DSS05.01, DSS05.02, A.12.6.1, A.14.2.3, A.16.1.3, A.18.2.2, A.18.2.3, 18, 20, 4, BP28(R08), RHEL-07-020260, SV-204459r603261_rule


Complexity:low
Disruption:high
Reboot:true
Strategy:patch


yum -y update

Complexity:low
Disruption:high
Reboot:true
Strategy:patch
- name: Security patches are up to date
  package:
    name: '*'
    state: latest
  tags:
    - CCE-26895-3
    - CJIS-5.10.4.1
    - DISA-STIG-RHEL-07-020260
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SI-2(5)
    - NIST-800-53-SI-2(c)
    - PCI-DSS-Req-6.2
    - high_disruption
    - high_severity
    - low_complexity
    - patch_strategy
    - reboot_required
    - security_patches_up_to_date
    - skip_ansible_lint

Rule   Ensure gpgcheck Enabled for Local Packages   [ref]

yum should be configured to verify the signature(s) of local packages prior to installation. To configure yum to verify signatures of local packages, set the localpkg_gpgcheck to 1 in /etc/yum.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

Identifiers:  CCE-80347-8

References:  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), 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, SR 7.6, 4.3.4.3.2, 4.3.4.3.3, BAI10.01, BAI10.02, BAI10.03, BAI10.05, A.12.1.2, A.12.5.1, A.12.6.2, A.14.2.2, A.14.2.3, A.14.2.4, 11, 3, 9, BP28(R15), RHEL-07-020060, SV-204448r603261_rule


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

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

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

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

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

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

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

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

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:
    - CCE-80347-8
    - DISA-STIG-RHEL-07-020060
    - 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: Check existence of yum on Fedora
  stat:
    path: /etc/yum.conf
  register: yum_config_file
  check_mode: false
  when:
    - ansible_distribution == "Fedora"
    - '"yum" in ansible_facts.packages'
  tags:
    - CCE-80347-8
    - DISA-STIG-RHEL-07-020060
    - 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/yum.conf
    section: main
    option: localpkg_gpgcheck
    value: 1
    create: true
  when:
    - (ansible_distribution == "RedHat" or ansible_distribution == "CentOS" or ansible_distribution
      == "Scientific" or yum_config_file.stat.exists)
    - '"yum" in ansible_facts.packages'
  tags:
    - CCE-80347-8
    - DISA-STIG-RHEL-07-020060
    - 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 (DNF)
  ini_file:
    dest: /etc/dnf/dnf.conf
    section: main
    option: localpkg_gpgcheck
    value: 1
    create: true
  when:
    - ansible_distribution == "Fedora"
    - '"yum" in ansible_facts.packages'
  tags:
    - CCE-80347-8
    - DISA-STIG-RHEL-07-020060
    - 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 Red Hat GPG Key Installed   [ref]

To ensure the system can cryptographically verify base software packages come from Red Hat (and to connect to the Red Hat Network to receive them), the Red Hat GPG key must properly be installed. To install the Red Hat GPG key, run:
$ sudo subscription-manager register
If the system is not connected to the Internet or an RHN Satellite, then install the Red Hat GPG key from trusted media such as the Red Hat 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
Alternatively, the key may be pre-loaded during the RHEL installation. In such cases, the key can be installed by running the following command:
sudo rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release
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 Red Hat GPG key is necessary to cryptographically verify packages are from Red Hat.
Severity: 
high
Rule ID:xccdf_org.ssgproject.content_rule_ensure_redhat_gpgkey_installed
Identifiers and References

Identifiers:  CCE-26957-1

References:  SRG-OS-000366-GPOS-00153, SRG-OS-000366-VMM-001430, SRG-OS-000370-VMM-001460, SRG-OS-000404-VMM-001650, 1.2.3, 5.10.4.1, 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), CM-5(3), SI-7, SC-12, SC-12(3), CM-6(a), PR.DS-6, PR.DS-8, PR.IP-1, FPT_TUD_EXT.1, FPT_TUD_EXT.2, 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, BP28(R15)


# The two fingerprints below are retrieved from https://access.redhat.com/security/team/key
readonly REDHAT_RELEASE_FINGERPRINT="567E347AD0044ADE55BA8A5F199E2F91FD431D51"
readonly REDHAT_AUXILIARY_FINGERPRINT="43A6E49C4A38F4BE9ABF2A5345689C882FA658E0"

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

RPM_GPG_DIR_PERMS=$(stat -c %a "$(dirname "$REDHAT_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 "$REDHAT_RELEASE_KEY" | grep "^fpr" | cut -d ":" -f 10)

  GPG_RESULT=$?
  # No CRC error, safe to proceed
  if [ "${GPG_RESULT}" -eq "0" ]
  then
    echo "${GPG_OUT[*]}" | grep -vE "${REDHAT_RELEASE_FINGERPRINT}|${REDHAT_AUXILIARY_FINGERPRINT}" || {
      # If $REDHAT_RELEASE_KEY file doesn't contain any keys with unknown fingerprint, import it
      rpm --import "${REDHAT_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:
    - CCE-26957-1
    - CJIS-5.10.4.1
    - NIST-800-171-3.4.8
    - 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_redhat_gpgkey_installed
    - high_severity
    - medium_complexity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy

- name: Read signatures in GPG key
  command: gpg --with-fingerprint --with-colons "/etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release"
  args:
    warn: false
  changed_when: false
  register: gpg_fingerprints
  check_mode: false
  tags:
    - CCE-26957-1
    - CJIS-5.10.4.1
    - NIST-800-171-3.4.8
    - 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_redhat_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:
    - CCE-26957-1
    - CJIS-5.10.4.1
    - NIST-800-171-3.4.8
    - 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_redhat_gpgkey_installed
    - high_severity
    - medium_complexity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy

- name: Set Fact - Valid fingerprints
  set_fact:
    gpg_valid_fingerprints: ("567E347AD0044ADE55BA8A5F199E2F91FD431D51" "43A6E49C4A38F4BE9ABF2A5345689C882FA658E0")
  tags:
    - CCE-26957-1
    - CJIS-5.10.4.1
    - NIST-800-171-3.4.8
    - 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_redhat_gpgkey_installed
    - high_severity
    - medium_complexity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy

- name: Import RedHat GPG key
  rpm_key:
    state: present
    key: /etc/pki/rpm-gpg/RPM-GPG-KEY-redhat-release
  when:
    - gpg_key_directory_permission.stat.mode <= '0755'
    - (gpg_installed_fingerprints | difference(gpg_valid_fingerprints)) | length ==
      0
    - gpg_installed_fingerprints | length > 0
    - ansible_distribution == "RedHat"
  tags:
    - CCE-26957-1
    - CJIS-5.10.4.1
    - NIST-800-171-3.4.8
    - 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_redhat_gpgkey_installed
    - high_severity
    - medium_complexity
    - medium_disruption
    - no_reboot_needed
    - restrict_strategy

Rule   Ensure gpgcheck Enabled In Main yum Configuration   [ref]

The gpgcheck option controls whether RPM packages' signatures are always checked prior to installation. To configure yum to check package signatures before installing them, ensure the following line appears in /etc/yum.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

Identifiers:  CCE-26989-4

References:  1.2.2, 5.10.4.1, 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), 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, 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, BP28(R15), RHEL-07-020050, SV-204447r603261_rule


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

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

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

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

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

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

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

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

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:
    - CCE-26989-4
    - CJIS-5.10.4.1
    - DISA-STIG-RHEL-07-020050
    - NIST-800-171-3.4.8
    - NIST-800-53-CM-11(a)
    - NIST-800-53-CM-11(b)
    - NIST-800-53-CM-5(3)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SA-12
    - NIST-800-53-SA-12(10)
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SI-7
    - PCI-DSS-Req-6.2
    - ensure_gpgcheck_globally_activated
    - high_severity
    - low_complexity
    - medium_disruption
    - no_reboot_needed
    - unknown_strategy

- name: Check existence of yum on Fedora
  stat:
    path: /etc/yum.conf
  register: yum_config_file
  check_mode: false
  when:
    - ansible_distribution == "Fedora"
    - '"yum" in ansible_facts.packages'
  tags:
    - CCE-26989-4
    - CJIS-5.10.4.1
    - DISA-STIG-RHEL-07-020050
    - NIST-800-171-3.4.8
    - NIST-800-53-CM-11(a)
    - NIST-800-53-CM-11(b)
    - NIST-800-53-CM-5(3)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SA-12
    - NIST-800-53-SA-12(10)
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SI-7
    - PCI-DSS-Req-6.2
    - ensure_gpgcheck_globally_activated
    - high_severity
    - low_complexity
    - medium_disruption
    - no_reboot_needed
    - unknown_strategy

- name: Ensure GPG check is globally activated (yum)
  ini_file:
    dest: /etc/yum.conf
    section: main
    option: gpgcheck
    value: 1
    no_extra_spaces: true
    create: false
  when:
    - (ansible_distribution == "RedHat" or ansible_distribution == "CentOS" or ansible_distribution
      == "Scientific" or yum_config_file.stat.exists)
    - '"yum" in ansible_facts.packages'
  tags:
    - CCE-26989-4
    - CJIS-5.10.4.1
    - DISA-STIG-RHEL-07-020050
    - NIST-800-171-3.4.8
    - NIST-800-53-CM-11(a)
    - NIST-800-53-CM-11(b)
    - NIST-800-53-CM-5(3)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SA-12
    - NIST-800-53-SA-12(10)
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SI-7
    - PCI-DSS-Req-6.2
    - ensure_gpgcheck_globally_activated
    - high_severity
    - low_complexity
    - medium_disruption
    - no_reboot_needed
    - unknown_strategy

- name: Ensure GPG check is globally activated (dnf)
  ini_file:
    dest: /etc/dnf/dnf.conf
    section: main
    option: gpgcheck
    value: 1
    no_extra_spaces: true
    create: false
  when:
    - ansible_distribution == "Fedora"
    - '"yum" in ansible_facts.packages'
  tags:
    - CCE-26989-4
    - CJIS-5.10.4.1
    - DISA-STIG-RHEL-07-020050
    - NIST-800-171-3.4.8
    - NIST-800-53-CM-11(a)
    - NIST-800-53-CM-11(b)
    - NIST-800-53-CM-5(3)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SA-12
    - NIST-800-53-SA-12(10)
    - NIST-800-53-SC-12
    - NIST-800-53-SC-12(3)
    - NIST-800-53-SI-7
    - PCI-DSS-Req-6.2
    - ensure_gpgcheck_globally_activated
    - high_severity
    - low_complexity
    - medium_disruption
    - no_reboot_needed
    - unknown_strategy
Group   GNOME Desktop Environment   Group contains 1 rule
[ref]   GNOME is a graphical desktop environment bundled with many Linux distributions that allow users to easily interact with the operating system graphically rather than textually. The GNOME Graphical Display Manager (GDM) provides login, logout, and user switching contexts as well as display server management.

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

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

Rule   Remove the GDM Package Group   [ref]

By removing the gdm package, the system no longer has GNOME installed installed. If X Windows is not installed then the system cannot boot into graphical user mode. This prevents the system from being accidentally or maliciously booted into a graphical.target mode. To do so, run the following command:
$ sudo yum remove gdm
Rationale:
Unnecessary service packages must not be installed to decrease the attack surface of the system. A graphical environment is unnecessary for certain types of systems including a virtualization hypervisor.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_gdm_removed
Identifiers and References

Identifiers:  CCE-82348-4

References:  CM-7(a), CM-7(b), CM-6(a), SRG-OS-000480-GPOS-00227


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

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

if rpm -q --quiet "gdm" ; then
    yum remove -y "gdm"
fi

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

Complexity:low
Disruption:low
Strategy:disable
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CCE-82348-4
    - 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_gdm_removed

- name: Ensure gdm is removed
  package:
    name: gdm
    state: absent
  when: '"gdm" in ansible_facts.packages'
  tags:
    - CCE-82348-4
    - 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_gdm_removed

Complexity:low
Disruption:low
Strategy:disable
include remove_gdm

class remove_gdm {
  package { 'gdm':
    ensure => 'purged',
  }
}

Complexity:low
Disruption:low
Strategy:disable

package --remove=gdm
Group   Sudo   Group contains 2 rules
[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   Ensure Users Re-Authenticate for Privilege Escalation - sudo !authenticate   [ref]

The sudo !authenticate option, when specified, allows a user to execute commands using sudo without having to authenticate. This should be disabled by making sure that the !authenticate option does not exist in /etc/sudoers configuration file or any sudo configuration snippets in /etc/sudoers.d/.
Rationale:
Without re-authentication, users may access resources or perform tasks for which they do not have authorization.

When operating systems provide the capability to escalate a functional capability, it is critical that the user re-authenticate.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sudo_remove_no_authenticate
Identifiers and References

Identifiers:  CCE-80350-2

References:  BP28(R5), BP28(R59), CCI-002038, IA-11, CM-6(a), PR.AC-1, PR.AC-7, SRG-OS-000373-GPOS-00156, SRG-OS-000373-GPOS-00157, SRG-OS-000373-GPOS-00158, SRG-OS-000373-VMM-001470, SRG-OS-000373-VMM-001480, SRG-OS-000373-VMM-001490, 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, 4.3.3.5.1, 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, DSS05.04, DSS05.10, DSS06.03, DSS06.10, A.18.1.4, 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, 1, 12, 15, 16, 5, RHEL-07-010350, SV-204430r603261_rule


Complexity:low
Disruption:low
Strategy:restrict

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

    /usr/sbin/visudo -cf $f &> /dev/null || echo "Fail to validate $f with visudo"
  fi
done

Complexity:low
Disruption:low
Strategy:restrict
- name: Find /etc/sudoers.d/ files
  find:
    paths:
      - /etc/sudoers.d/
  register: sudoers
  tags:
    - CCE-80350-2
    - DISA-STIG-RHEL-07-010350
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-11
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - sudo_remove_no_authenticate

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

Rule   Only the VDSM User Can Use sudo NOPASSWD   [ref]

The sudo NOPASSWD tag, when specified, allows a user to execute commands using sudo without having to authenticate. Only the vdsm user should have this capability in any sudo configuration snippets in /etc/sudoers.d/.
Rationale:
Without re-authentication, users may access resources or perform tasks for which they do not have authorization.

When operating systems provide the capability to escalate a functional capability, it is critical that the user re-authenticate.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_sudo_vdsm_nopasswd
Identifiers and References

Identifiers:  CCE-82349-2

Group   Account and Access Control   Group contains 17 groups and 65 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 Red Hat Enterprise Linux 7.
Group   Warning Banners for System Accesses   Group contains 1 rule
[ref]   Each system should expose as little information about itself as possible.

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

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

Rule   Modify the System Login Banner   [ref]

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

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


OR:

I've read & consent to terms in IS user agreem't.
Rationale:
Display of a standardized and approved use notification before granting access to the operating system ensures privacy and security notification verbiage used is consistent with applicable federal laws, Executive Orders, directives, policies, regulations, standards, and guidance.

System use notifications are required only for access via login interfaces with human users and are not required when such human interfaces do not exist.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_banner_etc_issue
Identifiers and References

Identifiers:  CCE-27303-7

References:  1.7.1.2, 3.1.9, CCI-000048, CCI-000050, AC-8(a), AC-8(c), PR.AC-7, FMT_MOF_EXT.1, SRG-OS-000023-GPOS-00006, SRG-OS-000024-GPOS-00007, SRG-OS-000023-VMM-000060, SRG-OS-000024-VMM-000070, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, 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, DSS05.04, DSS05.10, DSS06.10, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, 1, 12, 15, 16, RHEL-07-010050, SV-204395r603261_rule


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


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



# Multiple regexes transform the banner regex into a usable banner
# 0 - Remove anchors around the banner text
login_banner_text=$(echo "$login_banner_text" | sed 's/^\^\(.*\)\$$/\1/g')
# 1 - Keep only the first banners if there are multiple
#    (dod_banners contains the long and short banner)
login_banner_text=$(echo "$login_banner_text" | sed 's/^(\(.*\)|.*)$/\1/g')
# 2 - Add spaces ' '. (Transforms regex for "space or newline" into a " ")
login_banner_text=$(echo "$login_banner_text" | sed 's/\[\\s\\n\]+/ /g')
# 3 - Adds newlines. (Transforms "(?:\[\\n\]+|(?:\\n)+)" into "\n")
login_banner_text=$(echo "$login_banner_text" | sed 's/(?:\[\\n\]+|(?:\\n)+)/\n/g')
# 4 - Remove any leftover backslash. (From any parethesis in the banner, for example).
login_banner_text=$(echo "$login_banner_text" | sed 's/\\//g')
formatted=$(echo "$login_banner_text" | fold -sw 80)

cat <<EOF >/etc/issue
$formatted
EOF

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

Complexity:low
Disruption:medium
- name: XCCDF Value login_banner_text # promote to variable
  set_fact:
    login_banner_text: !!str ^(You[\s\n]+are[\s\n]+accessing[\s\n]+a[\s\n]+U\.S\.[\s\n]+Government[\s\n]+\(USG\)[\s\n]+Information[\s\n]+System[\s\n]+\(IS\)[\s\n]+that[\s\n]+is[\s\n]+provided[\s\n]+for[\s\n]+USG\-authorized[\s\n]+use[\s\n]+only\.[\s\n]+By[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+\(which[\s\n]+includes[\s\n]+any[\s\n]+device[\s\n]+attached[\s\n]+to[\s\n]+this[\s\n]+IS\)\,[\s\n]+you[\s\n]+consent[\s\n]+to[\s\n]+the[\s\n]+following[\s\n]+conditions\:(?:[\n]+|(?:\\n)+)\-The[\s\n]+USG[\s\n]+routinely[\s\n]+intercepts[\s\n]+and[\s\n]+monitors[\s\n]+communications[\s\n]+on[\s\n]+this[\s\n]+IS[\s\n]+for[\s\n]+purposes[\s\n]+including\,[\s\n]+but[\s\n]+not[\s\n]+limited[\s\n]+to\,[\s\n]+penetration[\s\n]+testing\,[\s\n]+COMSEC[\s\n]+monitoring\,[\s\n]+network[\s\n]+operations[\s\n]+and[\s\n]+defense\,[\s\n]+personnel[\s\n]+misconduct[\s\n]+\(PM\)\,[\s\n]+law[\s\n]+enforcement[\s\n]+\(LE\)\,[\s\n]+and[\s\n]+counterintelligence[\s\n]+\(CI\)[\s\n]+investigations\.(?:[\n]+|(?:\\n)+)\-At[\s\n]+any[\s\n]+time\,[\s\n]+the[\s\n]+USG[\s\n]+may[\s\n]+inspect[\s\n]+and[\s\n]+seize[\s\n]+data[\s\n]+stored[\s\n]+on[\s\n]+this[\s\n]+IS\.(?:[\n]+|(?:\\n)+)\-Communications[\s\n]+using\,[\s\n]+or[\s\n]+data[\s\n]+stored[\s\n]+on\,[\s\n]+this[\s\n]+IS[\s\n]+are[\s\n]+not[\s\n]+private\,[\s\n]+are[\s\n]+subject[\s\n]+to[\s\n]+routine[\s\n]+monitoring\,[\s\n]+interception\,[\s\n]+and[\s\n]+search\,[\s\n]+and[\s\n]+may[\s\n]+be[\s\n]+disclosed[\s\n]+or[\s\n]+used[\s\n]+for[\s\n]+any[\s\n]+USG\-authorized[\s\n]+purpose\.(?:[\n]+|(?:\\n)+)\-This[\s\n]+IS[\s\n]+includes[\s\n]+security[\s\n]+measures[\s\n]+\(e\.g\.\,[\s\n]+authentication[\s\n]+and[\s\n]+access[\s\n]+controls\)[\s\n]+to[\s\n]+protect[\s\n]+USG[\s\n]+interests\-\-not[\s\n]+for[\s\n]+your[\s\n]+personal[\s\n]+benefit[\s\n]+or[\s\n]+privacy\.(?:[\n]+|(?:\\n)+)\-Notwithstanding[\s\n]+the[\s\n]+above\,[\s\n]+using[\s\n]+this[\s\n]+IS[\s\n]+does[\s\n]+not[\s\n]+constitute[\s\n]+consent[\s\n]+to[\s\n]+PM\,[\s\n]+LE[\s\n]+or[\s\n]+CI[\s\n]+investigative[\s\n]+searching[\s\n]+or[\s\n]+monitoring[\s\n]+of[\s\n]+the[\s\n]+content[\s\n]+of[\s\n]+privileged[\s\n]+communications\,[\s\n]+or[\s\n]+work[\s\n]+product\,[\s\n]+related[\s\n]+to[\s\n]+personal[\s\n]+representation[\s\n]+or[\s\n]+services[\s\n]+by[\s\n]+attorneys\,[\s\n]+psychotherapists\,[\s\n]+or[\s\n]+clergy\,[\s\n]+and[\s\n]+their[\s\n]+assistants\.[\s\n]+Such[\s\n]+communications[\s\n]+and[\s\n]+work[\s\n]+product[\s\n]+are[\s\n]+private[\s\n]+and[\s\n]+confidential\.[\s\n]+See[\s\n]+User[\s\n]+Agreement[\s\n]+for[\s\n]+details\.|I've[\s\n]+read[\s\n]+\&[\s\n]+consent[\s\n]+to[\s\n]+terms[\s\n]+in[\s\n]+IS[\s\n]+user[\s\n]+agreem't\.)$
  tags:
    - always

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

- name: Modify the System Login Banner - add correct banner
  lineinfile:
    dest: /etc/issue
    line: '{{ login_banner_text | regex_replace("^\^(.*)\$$", "\1") | regex_replace("^\((.*)\|.*\)$",
      "\1") | regex_replace("\[\\s\\n\]\+"," ") | regex_replace("\(\?:\[\\n\]\+\|\(\?:\\\\n\)\+\)",
      "\n") | regex_replace("\\", "") | wordwrap() }}'
    create: true
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-27303-7
    - DISA-STIG-RHEL-07-010050
    - NIST-800-171-3.1.9
    - NIST-800-53-AC-8(a)
    - NIST-800-53-AC-8(c)
    - banner_etc_issue
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
    - unknown_strategy
Group   Protect Accounts by Configuring PAM   Group contains 4 groups and 19 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 5 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   Configure the root Account for Failed Password Attempts   [ref]

To configure the system to lock out the root account after a number of incorrect login attempts using pam_faillock.so, modify the content of both /etc/pam.d/system-auth and /etc/pam.d/password-auth as follows:

  • Modify the following line in the AUTH section to add even_deny_root:
    auth required pam_faillock.so preauth silent even_deny_root deny=3 unlock_time=0 fail_interval=900
  • Modify the following line in the AUTH section to add even_deny_root:
    auth [default=die] pam_faillock.so authfail even_deny_root deny=3 unlock_time=0 fail_interval=900
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_deny_root
Identifiers and References

Identifiers:  CCE-80353-6

References:  CCI-002238, CM-6(a), AC-7(b), IA-5(c), PR.AC-7, FMT_MOF_EXT.1, SRG-OS-000329-GPOS-00128, SRG-OS-000021-GPOS-00005, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, 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, DSS05.04, DSS05.10, DSS06.10, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, 1, 12, 15, 16, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, BP28(R18), RHEL-07-010330, SV-204428r603261_rule


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

AUTH_FILES[0]="/etc/pam.d/system-auth"
AUTH_FILES[1]="/etc/pam.d/password-auth"

# This script fixes absence of pam_faillock.so in PAM stack or the
# absense of even_deny_root in pam_faillock.so arguments
# When inserting auth pam_faillock.so entries,
# the entry with preauth argument will be added before pam_unix.so module
# and entry with authfail argument will be added before pam_deny.so module.

# The placement of pam_faillock.so entries will not be changed
# if they are already present

for pamFile in "${AUTH_FILES[@]}"
do
	# if PAM file is missing, system is not using PAM or broken
	if [ ! -f $pamFile ]; then
		continue
	fi

	# is 'auth required' here?
	if grep -q "^auth.*required.*pam_faillock.so.*" $pamFile; then
		# has 'auth required' even_deny_root option?
		if ! grep -q "^auth.*required.*pam_faillock.so.*preauth.*even_deny_root" $pamFile; then
			# even_deny_root is not present
			sed -i --follow-symlinks "s/\(^auth.*required.*pam_faillock.so.*preauth.*\).*/\1 even_deny_root/" $pamFile
		fi
	else
		# no 'auth required', add it
		sed -i --follow-symlinks "/^auth.*pam_unix.so.*/i auth required pam_faillock.so preauth silent even_deny_root" $pamFile
	fi

	# is 'auth [default=die]' here?
	if grep -q "^auth.*\[default=die\].*pam_faillock.so.*" $pamFile; then
		# has 'auth [default=die]' even_deny_root option?
		if ! grep -q "^auth.*\[default=die\].*pam_faillock.so.*authfail.*even_deny_root" $pamFile; then
			# even_deny_root is not present
			sed -i --follow-symlinks "s/\(^auth.*\[default=die\].*pam_faillock.so.*authfail.*\).*/\1 even_deny_root/" $pamFile
		fi
	else
		# no 'auth [default=die]', add it
		sed -i --follow-symlinks "/^auth.*pam_unix.so.*/a auth [default=die] pam_faillock.so authfail silent even_deny_root" $pamFile
	fi
done

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:
    - CCE-80353-6
    - DISA-STIG-RHEL-07-010330
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(c)
    - accounts_passwords_pam_faillock_deny_root
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Add auth pam_faillock preauth even_deny_root before pam_unix.so
  pamd:
    name: '{{ item }}'
    type: auth
    control: sufficient
    module_path: pam_unix.so
    new_type: auth
    new_control: required
    new_module_path: pam_faillock.so
    module_arguments: preauth silent even_deny_root
    state: before
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-80353-6
    - DISA-STIG-RHEL-07-010330
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(c)
    - accounts_passwords_pam_faillock_deny_root
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Add even_deny_root argument to auth pam_faillock preauth
  pamd:
    name: '{{ item }}'
    type: auth
    control: required
    module_path: pam_faillock.so
    module_arguments: preauth silent even_deny_root
    state: args_present
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-80353-6
    - DISA-STIG-RHEL-07-010330
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(c)
    - accounts_passwords_pam_faillock_deny_root
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Add auth pam_faillock authfail even_deny_root after pam_unix.so
  pamd:
    name: '{{ item }}'
    type: auth
    control: sufficient
    module_path: pam_unix.so
    new_type: auth
    new_control: '[default=die]'
    new_module_path: pam_faillock.so
    module_arguments: authfail even_deny_root
    state: after
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-80353-6
    - DISA-STIG-RHEL-07-010330
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(c)
    - accounts_passwords_pam_faillock_deny_root
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Add even_deny_root argument to auth pam_faillock authfail
  pamd:
    name: '{{ item }}'
    type: auth
    control: '[default=die]'
    module_path: pam_faillock.so
    module_arguments: authfail even_deny_root
    state: args_present
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-80353-6
    - DISA-STIG-RHEL-07-010330
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(c)
    - accounts_passwords_pam_faillock_deny_root
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

- name: Add account pam_faillock before pam_unix.so
  pamd:
    name: '{{ item }}'
    type: account
    control: required
    module_path: pam_unix.so
    new_type: account
    new_control: required
    new_module_path: pam_faillock.so
    state: before
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-80353-6
    - DISA-STIG-RHEL-07-010330
    - NIST-800-53-AC-7(b)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(c)
    - accounts_passwords_pam_faillock_deny_root
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy

Rule   Set Deny For Failed Password Attempts   [ref]

To configure the system to lock out accounts after a number of incorrect login attempts using pam_faillock.so, modify the content of both /etc/pam.d/system-auth and /etc/pam.d/password-auth as follows:

  • add the following line immediately before the pam_unix.so statement in the AUTH section:
    auth required pam_faillock.so preauth silent deny=3 unlock_time=0 fail_interval=900
  • add the following line immediately after the pam_unix.so statement in the AUTH section:
    auth [default=die] pam_faillock.so authfail deny=3 unlock_time=0 fail_interval=900
  • add the following line immediately before the pam_unix.so statement in the ACCOUNT section:
    account required pam_faillock.so
Rationale:
Locking out user accounts after a number of incorrect attempts prevents direct password guessing attacks.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_deny
Identifiers and References

Identifiers:  CCE-27350-8

References:  5.3.2, 5.5.3, 3.1.8, CCI-000044, CCI-002236, CCI-002237, CCI-002238, 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, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, 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, DSS05.04, DSS05.10, DSS06.10, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, 1, 12, 15, 16, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, BP28(R18), RHEL-07-010320, SV-204427r603824_rule


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


var_accounts_passwords_pam_faillock_deny="3"



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

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:
    - CCE-27350-8
    - CJIS-5.5.3
    - DISA-STIG-RHEL-07-010320
    - 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: Add auth pam_faillock preauth deny before pam_unix.so
  pamd:
    name: '{{ item }}'
    type: auth
    control: sufficient
    module_path: pam_unix.so
    new_type: auth
    new_control: required
    new_module_path: pam_faillock.so
    module_arguments: preauth silent deny={{ var_accounts_passwords_pam_faillock_deny
      }}
    state: before
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-27350-8
    - CJIS-5.5.3
    - DISA-STIG-RHEL-07-010320
    - 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: Add deny argument to auth pam_faillock preauth
  pamd:
    name: '{{ item }}'
    type: auth
    control: required
    module_path: pam_faillock.so
    module_arguments: preauth silent deny={{ var_accounts_passwords_pam_faillock_deny
      }}
    state: args_present
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-27350-8
    - CJIS-5.5.3
    - DISA-STIG-RHEL-07-010320
    - 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: Add auth pam_faillock authfail deny after pam_unix.so
  pamd:
    name: '{{ item }}'
    type: auth
    control: sufficient
    module_path: pam_unix.so
    new_type: auth
    new_control: '[default=die]'
    new_module_path: pam_faillock.so
    module_arguments: authfail deny={{ var_accounts_passwords_pam_faillock_deny }}
    state: after
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-27350-8
    - CJIS-5.5.3
    - DISA-STIG-RHEL-07-010320
    - 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: Add deny argument to auth pam_faillock authfail
  pamd:
    name: '{{ item }}'
    type: auth
    new_type: auth
    control: '[default=die]'
    module_path: pam_faillock.so
    module_arguments: authfail deny={{ var_accounts_passwords_pam_faillock_deny }}
    state: args_present
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-27350-8
    - CJIS-5.5.3
    - DISA-STIG-RHEL-07-010320
    - 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: Add account pam_faillock before pam_unix.so
  pamd:
    name: '{{ item }}'
    type: account
    control: required
    module_path: pam_unix.so
    new_type: account
    new_control: required
    new_module_path: pam_faillock.so
    state: before
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-27350-8
    - CJIS-5.5.3
    - DISA-STIG-RHEL-07-010320
    - 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. Modify the content of both /etc/pam.d/system-auth and /etc/pam.d/password-auth as follows:

  • Add the following line immediately before the pam_unix.so statement in the AUTH section:
    auth required pam_faillock.so preauth silent deny=3 unlock_time=0 fail_interval=900
  • Add the following line immediately after the pam_unix.so statement in the AUTH section:
    auth [default=die] pam_faillock.so authfail deny=3 unlock_time=0 fail_interval=900
    
  • Add the following line immediately before the pam_unix.so statement in the ACCOUNT section:
    account required pam_faillock.so
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

Identifiers:  CCE-27297-1

References:  CCI-000044, CCI-002236, CCI-002237, CCI-002238, 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, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, 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, DSS05.04, DSS05.10, DSS06.10, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, 1, 12, 15, 16, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, BP28(R18), RHEL-07-010320, SV-204427r603824_rule


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

# include our remediation functions library

var_accounts_passwords_pam_faillock_fail_interval="900"



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

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:
    - CCE-27297-1
    - DISA-STIG-RHEL-07-010320
    - 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: Add auth pam_faillock preauth fail_interval before pam_unix.so
  pamd:
    name: '{{ item }}'
    type: auth
    control: sufficient
    module_path: pam_unix.so
    new_type: auth
    new_control: required
    new_module_path: pam_faillock.so
    module_arguments: preauth silent fail_interval={{ var_accounts_passwords_pam_faillock_fail_interval
      }}
    state: before
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-27297-1
    - DISA-STIG-RHEL-07-010320
    - 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: Add fail_interval argument to auth pam_faillock preauth
  pamd:
    name: '{{ item }}'
    type: auth
    control: required
    module_path: pam_faillock.so
    module_arguments: preauth silent fail_interval={{ var_accounts_passwords_pam_faillock_fail_interval
      }}
    state: args_present
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-27297-1
    - DISA-STIG-RHEL-07-010320
    - 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: Add auth pam_faillock aufthfail fail_interval after pam_unix.so
  pamd:
    name: '{{ item }}'
    type: auth
    control: sufficient
    module_path: pam_unix.so
    new_type: auth
    new_control: '[default=die]'
    new_module_path: pam_faillock.so
    module_arguments: authfail fail_interval={{ var_accounts_passwords_pam_faillock_fail_interval
      }}
    state: after
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-27297-1
    - DISA-STIG-RHEL-07-010320
    - 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: Add fail_interval argument to auth pam_faillock authfail
  pamd:
    name: '{{ item }}'
    type: auth
    control: '[default=die]'
    module_path: pam_faillock.so
    module_arguments: authfail fail_interval={{ var_accounts_passwords_pam_faillock_fail_interval
      }}
    state: args_present
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-27297-1
    - DISA-STIG-RHEL-07-010320
    - 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: Add account pam_faillock before pam_unix.so
  pamd:
    name: '{{ item }}'
    type: account
    control: required
    module_path: pam_unix.so
    new_type: account
    new_control: required
    new_module_path: pam_faillock.so
    state: before
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-27297-1
    - DISA-STIG-RHEL-07-010320
    - 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   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.
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

Identifiers:  CCE-82030-8

References:  5.3.3, 5.6.2.1.1, 3.5.8, CCI-000200, 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, 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, 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, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 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, 1, 12, 15, 16, 5, BP28(R18), RHEL-07-010270, SV-204422r603261_rule


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


var_password_pam_unix_remember="5"



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 "remember=" $pamFile; then
		sed -i --follow-symlinks "s/\(^password.*sufficient.*pam_unix.so.*\)\(\(remember *= *\)[^ $]*\)/\1remember=$var_password_pam_unix_remember/" $pamFile
	else
		sed -i --follow-symlinks "/^password[[:space:]]\+sufficient[[:space:]]\+pam_unix.so/ s/$/ remember=$var_password_pam_unix_remember/" $pamFile
	fi
done

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:
    - CCE-82030-8
    - CJIS-5.6.2.1.1
    - DISA-STIG-RHEL-07-010270
    - 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: 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'
  tags:
    - CCE-82030-8
    - CJIS-5.6.2.1.1
    - DISA-STIG-RHEL-07-010270
    - 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'
  tags:
    - CCE-82030-8
    - CJIS-5.6.2.1.1
    - DISA-STIG-RHEL-07-010270
    - 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   Set Lockout Time for Failed Password Attempts   [ref]

To configure the system to lock out accounts after a number of incorrect login attempts and require an administrator to unlock the account using pam_faillock.so, modify the content of both /etc/pam.d/system-auth and /etc/pam.d/password-auth as follows:

  • add the following line immediately before the pam_unix.so statement in the AUTH section:
    auth required pam_faillock.so preauth silent deny=3 unlock_time=0 fail_interval=900
  • add the following line immediately after the pam_unix.so statement in the AUTH section:
    auth [default=die] pam_faillock.so authfail deny=3 unlock_time=0 fail_interval=900
  • add the following line immediately before the pam_unix.so statement in the ACCOUNT section:
    account required pam_faillock.so
If unlock_time is set to 0, manual intervention by an administrator is required to unlock a user.
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

Identifiers:  CCE-26884-7

References:  5.3.2, 5.5.3, 3.1.8, CCI-000044, CCI-002236, CCI-002237, CCI-002238, 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, SR 1.1, SR 1.10, SR 1.2, SR 1.5, SR 1.7, SR 1.8, SR 1.9, 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, DSS05.04, DSS05.10, DSS06.10, A.18.1.4, A.9.2.1, A.9.2.4, A.9.3.1, A.9.4.2, A.9.4.3, 1, 12, 15, 16, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, BP28(R18), RHEL-07-010320, SV-204427r603824_rule


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


var_accounts_passwords_pam_faillock_unlock_time="0"



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

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:
    - CCE-26884-7
    - CJIS-5.5.3
    - DISA-STIG-RHEL-07-010320
    - 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: Add auth pam_faillock preauth unlock_time before pam_unix.so
  pamd:
    name: '{{ item }}'
    type: auth
    control: sufficient
    module_path: pam_unix.so
    new_type: auth
    new_control: required
    new_module_path: pam_faillock.so
    module_arguments: preauth silent unlock_time={{ var_accounts_passwords_pam_faillock_unlock_time
      }}
    state: before
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-26884-7
    - CJIS-5.5.3
    - DISA-STIG-RHEL-07-010320
    - 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: Add unlock_time argument to pam_faillock preauth
  pamd:
    name: '{{ item }}'
    type: auth
    control: required
    module_path: pam_faillock.so
    module_arguments: preauth silent unlock_time={{ var_accounts_passwords_pam_faillock_unlock_time
      }}
    state: args_present
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-26884-7
    - CJIS-5.5.3
    - DISA-STIG-RHEL-07-010320
    - 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: Add auth pam_faillock authfail unlock_interval after pam_unix.so
  pamd:
    name: '{{ item }}'
    type: auth
    control: sufficient
    module_path: pam_unix.so
    new_type: auth
    new_control: '[default=die]'
    new_module_path: pam_faillock.so
    module_arguments: authfail unlock_time={{ var_accounts_passwords_pam_faillock_unlock_time
      }}
    state: after
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-26884-7
    - CJIS-5.5.3
    - DISA-STIG-RHEL-07-010320
    - 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: Add unlock_time argument to auth pam_faillock authfail
  pamd:
    name: '{{ item }}'
    type: auth
    control: '[default=die]'
    module_path: pam_faillock.so
    module_arguments: authfail unlock_time={{ var_accounts_passwords_pam_faillock_unlock_time
      }}
    state: args_present
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-26884-7
    - CJIS-5.5.3
    - DISA-STIG-RHEL-07-010320
    - 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: Add account pam_faillock before pam_unix.so
  pamd:
    name: '{{ item }}'
    type: account
    control: required
    module_path: pam_unix.so
    new_type: account
    new_control: required
    new_module_path: pam_faillock.so
    state: before
  loop:
    - system-auth
    - password-auth
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-26884-7
    - CJIS-5.5.3
    - DISA-STIG-RHEL-07-010320
    - 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 10 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 10 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 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

Identifiers:  CCE-27345-8

References:  CCI-000193, 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, 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, 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, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 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, 1, 12, 15, 16, 5, 5.3.1, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, BP28(R18), RHEL-07-010130, SV-204408r603261_rule


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


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

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

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

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

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

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

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

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:
    - CCE-27345-8
    - DISA-STIG-RHEL-07-010130
    - 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:
    - CCE-27345-8
    - DISA-STIG-RHEL-07-010130
    - 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 - Minimum Different Categories   [ref]

The pam_pwquality module's minclass parameter controls requirements for usage of different character classes, or types, of character that must exist in a password before it is considered valid. For example, setting this value to three (3) requires that any password must have characters from at least three different categories in order to be approved. The default value is zero (0), meaning there are no required classes. There are four categories available:
* Upper-case characters
* Lower-case characters
* Digits
* Special characters (for example, punctuation)
Modify the minclass setting in /etc/security/pwquality.conf entry to require 4 differing categories of 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 character categories makes password guessing attacks more difficult by ensuring a larger search space.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_password_pam_minclass
Identifiers and References

Identifiers:  CCE-82045-6

References:  CCI-000195, 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, 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, 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, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 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, 1, 12, 15, 16, 5, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, RHEL-07-010170, SV-204412r603261_rule


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


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

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

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

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

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

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

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

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:
    - CCE-82045-6
    - DISA-STIG-RHEL-07-010170
    - 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_minclass
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
- name: XCCDF Value var_password_pam_minclass # promote to variable
  set_fact:
    var_password_pam_minclass: !!str 4
  tags:
    - always

- name: Ensure PAM variable minclass is set accordingly
  lineinfile:
    create: true
    dest: /etc/security/pwquality.conf
    regexp: ^#?\s*minclass
    line: minclass = {{ var_password_pam_minclass }}
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-82045-6
    - DISA-STIG-RHEL-07-010170
    - 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_minclass
    - 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 8 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

Identifiers:  CCE-82020-9

References:  5.6.2.1.1, CCI-000195, 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, 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, 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, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 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, 1, 12, 15, 16, 5, RHEL-07-010160, SV-204411r603261_rule


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


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

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

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

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

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

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

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

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:
    - CCE-82020-9
    - CJIS-5.6.2.1.1
    - DISA-STIG-RHEL-07-010160
    - 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 8
  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:
    - CCE-82020-9
    - CJIS-5.6.2.1.1
    - DISA-STIG-RHEL-07-010160
    - 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   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

Identifiers:  CCE-82055-5

References:  CCI-000195, IA-5(c), CM-6(a), IA-5(4), PR.AC-1, PR.AC-6, PR.AC-7, SRG-OS-000072-GPOS-00040, 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, 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, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 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, 1, 12, 15, 16, 5, RHEL-07-010180, SV-204413r603261_rule


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


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

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

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

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

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

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

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

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:
    - CCE-82055-5
    - DISA-STIG-RHEL-07-010180
    - 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:
    - CCE-82055-5
    - DISA-STIG-RHEL-07-010180
    - 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 - Authentication Retry Prompts Permitted Per-Session   [ref]

To configure the number of retry prompts that are permitted per-session: Edit the pam_pwquality.so statement in /etc/pam.d/system-auth to show retry=3, or a lower value if site policy is more restrictive. The DoD requirement is a maximum of 3 prompts per session.
Rationale:
Setting the password retry prompts that are permitted on a per-session basis to a low value requires some software, such as SSH, to re-connect. This can slow down and draw additional attention to some types of password-guessing attacks. Note that this is different from account lockout, which is provided by the pam_faillock module.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_password_pam_retry
Identifiers and References

Identifiers:  CCE-27160-1

References:  6.3.2, 5.5.3, CCI-000192, CCI-000366, CM-6(a), AC-7(a), IA-5(4), PR.AC-1, PR.AC-6, PR.AC-7, PR.IP-1, FMT_MOF_EXT.1, SRG-OS-000480-GPOS-00225, 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 7.6, 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, 4.3.4.3.2, 4.3.4.3.3, BAI10.01, BAI10.02, BAI10.03, BAI10.05, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 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.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, 1, 11, 12, 15, 16, 3, 5, 9, RHEL-07-010119, SV-204406r603261_rule


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


var_password_pam_retry="3"



if grep -q "retry=" /etc/pam.d/system-auth ; then
	sed -i --follow-symlinks "s/\(retry *= *\).*/\1$var_password_pam_retry/" /etc/pam.d/system-auth
else
	sed -i --follow-symlinks "/pam_pwquality.so/ s/$/ retry=$var_password_pam_retry/" /etc/pam.d/system-auth
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:
    - CCE-27160-1
    - CJIS-5.5.3
    - DISA-STIG-RHEL-07-010119
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(4)
    - accounts_password_pam_retry
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed
- name: XCCDF Value var_password_pam_retry # promote to variable
  set_fact:
    var_password_pam_retry: !!str 3
  tags:
    - always

- name: Set Password Retry Prompts Permitted Per-Session - system-auth (change)
  replace:
    dest: /etc/pam.d/system-auth
    regexp: (^.*\spam_pwquality.so\s.*retry\s*=\s*)(\S+)(.*$)
    replace: \g<1>{{ var_password_pam_retry }}\g<3>
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-27160-1
    - CJIS-5.5.3
    - DISA-STIG-RHEL-07-010119
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(4)
    - accounts_password_pam_retry
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

- name: Set Password Retry Prompts Permitted Per-Session - system-auth (add)
  replace:
    dest: /etc/pam.d/system-auth
    regexp: ^.*\spam_pwquality.so\s(?!.*retry\s*=\s*).*$
    replace: \g<0> retry={{ var_password_pam_retry }}
  when: '"pam" in ansible_facts.packages'
  tags:
    - CCE-27160-1
    - CJIS-5.5.3
    - DISA-STIG-RHEL-07-010119
    - NIST-800-53-AC-7(a)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(4)
    - accounts_password_pam_retry
    - configure_strategy
    - low_complexity
    - medium_disruption
    - medium_severity
    - no_reboot_needed

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

Identifiers:  CCE-27214-6

References:  6.3.2, CCI-000194, 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, 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, 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, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 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, 1, 12, 15, 16, 5, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, BP28(R18), RHEL-07-010140, SV-204409r603261_rule


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


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

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

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

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

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

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

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

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:
    - CCE-27214-6
    - DISA-STIG-RHEL-07-010140
    - 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:
    - CCE-27214-6
    - DISA-STIG-RHEL-07-010140
    - 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 - 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

Identifiers:  CCE-27512-3

References:  CCI-000195, 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, 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, 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, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 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, 1, 12, 15, 16, 5, RHEL-07-010190, SV-204414r603261_rule


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


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

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

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

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

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

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

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

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:
    - CCE-27512-3
    - DISA-STIG-RHEL-07-010190
    - 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:
    - CCE-27512-3
    - DISA-STIG-RHEL-07-010190
    - 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   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

Identifiers:  CCE-27360-7

References:  CCI-001619, 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, 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, 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, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 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, 1, 12, 15, 16, 5, 5.3.1, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, BP28(R18), RHEL-07-010150, SV-204410r603261_rule


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


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

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

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

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

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

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

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

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:
    - CCE-27360-7
    - DISA-STIG-RHEL-07-010150
    - 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:
    - CCE-27360-7
    - DISA-STIG-RHEL-07-010150
    - 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

Identifiers:  CCE-27200-5

References:  6.3.2, CCI-000192, 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, 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, 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, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 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, 1, 12, 15, 16, 5, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, BP28(R18), RHEL-07-010120, SV-204407r603261_rule


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


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

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

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

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

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

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

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

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:
    - CCE-27200-5
    - DISA-STIG-RHEL-07-010120
    - 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:
    - CCE-27200-5
    - DISA-STIG-RHEL-07-010120
    - 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

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=15 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

Identifiers:  CCE-27293-0

References:  6.3.2, 5.6.2.1.1, CCI-000205, 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, 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, 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, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 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, 1, 12, 15, 16, 5, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, BP28(R18), RHEL-07-010280, SV-204423r603261_rule


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


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

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

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

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

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

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

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

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:
    - CCE-27293-0
    - CJIS-5.6.2.1.1
    - DISA-STIG-RHEL-07-010280
    - 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 15
  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:
    - CCE-27293-0
    - CJIS-5.6.2.1.1
    - DISA-STIG-RHEL-07-010280
    - 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
Group   Set Password Hashing Algorithm   Group contains 3 rules
[ref]   The system's default algorithm for storing password hashes in /etc/shadow is SHA-512. This can be configured in several locations.

Rule   Set Password Hashing Algorithm in /etc/libuser.conf   [ref]

In /etc/libuser.conf, add or correct the following line in its [defaults] section to ensure the system will use the SHA-512 algorithm for password hashing:
crypt_style = sha512
Rationale:
Passwords need to be protected at all times, and encryption is the standard method for protecting passwords. If passwords are not encrypted, they can be plainly read (i.e., clear text) and easily compromised. Passwords that are encrypted with a weak algorithm are no more protected than if they are kepy in plain text.

This setting ensures user and group account administration utilities are configured to store only encrypted representations of passwords. Additionally, the crypt_style configuration option ensures the use of a strong hashing algorithm that makes password cracking attacks more difficult.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_set_password_hashing_algorithm_libuserconf
Identifiers and References

Identifiers:  CCE-82038-1

References:  5.6.2.2, 3.13.11, CCI-000196, IA-5(c), IA-5(1)(c), CM-6(a), PR.AC-1, PR.AC-6, PR.AC-7, Req-8.2.1, SRG-OS-000073-GPOS-00041, SRG-OS-000480-VMM-002000, 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, 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, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 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, 1, 12, 15, 16, 5, 0418, 1055, 1402, RHEL-07-010220, SV-204417r603261_rule


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

LIBUSER_CONF="/etc/libuser.conf"
CRYPT_STYLE_REGEX='[[:space:]]*\[defaults](.*(\n)+)+?[[:space:]]*crypt_style[[:space:]]*'

# Try find crypt_style in [defaults] section. If it is here, then change algorithm to sha512.
# If it isn't here, then add it to [defaults] section.
if grep -qzosP $CRYPT_STYLE_REGEX $LIBUSER_CONF ; then
        sed -i "s/\(crypt_style[[:space:]]*=[[:space:]]*\).*/\1sha512/g" $LIBUSER_CONF
elif grep -qs "\[defaults]" $LIBUSER_CONF ; then
        sed -i "/[[:space:]]*\[defaults]/a crypt_style = sha512" $LIBUSER_CONF
else
        echo -e "[defaults]\ncrypt_style = sha512" >> $LIBUSER_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:
    - CCE-82038-1
    - CJIS-5.6.2.2
    - DISA-STIG-RHEL-07-010220
    - NIST-800-171-3.13.11
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - set_password_hashing_algorithm_libuserconf

- name: Set Password Hashing Algorithm in /etc/libuser.conf
  lineinfile:
    dest: /etc/libuser.conf
    insertafter: ^\s*\[defaults]
    regexp: ^#?crypt_style
    line: crypt_style = sha512
    state: present
    create: true
  when: '"libuser" in ansible_facts.packages'
  tags:
    - CCE-82038-1
    - CJIS-5.6.2.2
    - DISA-STIG-RHEL-07-010220
    - NIST-800-171-3.13.11
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - set_password_hashing_algorithm_libuserconf

Rule   Set PAM's Password Hashing Algorithm   [ref]

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

This will help ensure when local users change their passwords, hashes for the new passwords will be generated using the SHA-512 algorithm. This is the default.
Rationale:
Passwords need to be protected at all times, and encryption is the standard method for protecting passwords. If passwords are not encrypted, they can be plainly read (i.e., clear text) and easily compromised. Passwords that are encrypted with a weak algorithm are no more protected than if they are kepy in plain text.

This setting ensures user and group account administration utilities are configured to store only encrypted representations of passwords. Additionally, the crypt_style configuration option ensures the use of a strong hashing algorithm that makes password cracking attacks more difficult.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_set_password_hashing_algorithm_systemauth
Identifiers and References

Identifiers:  CCE-82043-1

References:  5.3.4, 5.6.2.2, 3.13.11, CCI-000196, IA-5(c), IA-5(1)(c), CM-6(a), PR.AC-1, PR.AC-6, PR.AC-7, Req-8.2.1, SRG-OS-000073-GPOS-00041, SRG-OS-000480-VMM-002000, 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, 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, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 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, 1, 12, 15, 16, 5, 0418, 1055, 1402, BP28(R32), RHEL-07-010200, SV-204415r603261_rule


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

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 "^password.*sufficient.*pam_unix.so.*sha512" $pamFile; then
		sed -i --follow-symlinks "/^password.*sufficient.*pam_unix.so/ s/$/ sha512/" $pamFile
	fi
done

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

Rule   Set Password Hashing Algorithm in /etc/login.defs   [ref]

In /etc/login.defs, add or correct the following line to ensure the system will use SHA-512 as the hashing algorithm:
ENCRYPT_METHOD SHA512
Rationale:
Passwords need to be protected at all times, and encryption is the standard method for protecting passwords. If passwords are not encrypted, they can be plainly read (i.e., clear text) and easily compromised. Passwords that are encrypted with a weak algorithm are no more protected than if they are kept in plain text.

Using a stronger hashing algorithm makes password cracking attacks more difficult.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_set_password_hashing_algorithm_logindefs
Identifiers and References

Identifiers:  CCE-82050-6

References:  6.3.1, 5.6.2.2, 3.13.11, CCI-000196, IA-5(c), IA-5(1)(c), CM-6(a), PR.AC-1, PR.AC-6, PR.AC-7, Req-8.2.1, SRG-OS-000073-GPOS-00041, 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, 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, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 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, 1, 12, 15, 16, 5, BP28(R32), 0418, 1055, 1402, RHEL-07-010210, SV-204416r603261_rule


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


var_password_hashing_algorithm="SHA512"



if grep --silent ^ENCRYPT_METHOD /etc/login.defs ; then
	sed -i "s/^ENCRYPT_METHOD .*/ENCRYPT_METHOD $var_password_hashing_algorithm/g" /etc/login.defs
else
	echo "" >> /etc/login.defs
	echo "ENCRYPT_METHOD $var_password_hashing_algorithm" >> /etc/login.defs
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:
    - CCE-82050-6
    - CJIS-5.6.2.2
    - DISA-STIG-RHEL-07-010210
    - NIST-800-171-3.13.11
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - set_password_hashing_algorithm_logindefs
- name: XCCDF Value var_password_hashing_algorithm # promote to variable
  set_fact:
    var_password_hashing_algorithm: !!str SHA512
  tags:
    - always

- name: Set Password Hashing Algorithm in /etc/login.defs
  lineinfile:
    dest: /etc/login.defs
    regexp: ^#?ENCRYPT_METHOD
    line: ENCRYPT_METHOD {{ var_password_hashing_algorithm }}
    state: present
    create: true
  when: '"shadow-utils" in ansible_facts.packages'
  tags:
    - CCE-82050-6
    - CJIS-5.6.2.2
    - DISA-STIG-RHEL-07-010210
    - NIST-800-171-3.13.11
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(c)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.1
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - restrict_strategy
    - set_password_hashing_algorithm_logindefs
Group   Protect Physical Console Access   Group contains 3 groups and 12 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 2 groups and 7 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   Hardware Tokens for Authentication   Group contains 6 rules

Rule   Install the opensc Package For Multifactor Authentication   [ref]

The opensc package can be installed with the following command:
$ sudo yum install opensc
Rationale:
Using an authentication device, such as a CAC or token that is separate from the information system, ensures that even if the information system is compromised, that compromise will not affect credentials stored on the authentication device.

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

Identifiers:  CCE-80568-9

References:  CCI-001954, CM-6(a), SRG-OS-000375-GPOS-00160, SRG-OS-000376-VMM-001520, 1382, 1384, 1386


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

if ! rpm -q --quiet "opensc" ; then
    yum install -y "opensc"
fi

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

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

Complexity:low
Disruption:low
Strategy:enable
include install_opensc

class install_opensc {
  package { 'opensc':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=opensc

Rule   Install the pcsc-lite package   [ref]

The pcsc-lite package can be installed with the following command:
$ sudo yum install pcsc-lite
Rationale:
The pcsc-lite package must be installed if it is to be available for multifactor authentication using smartcards.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_pcsc-lite_installed
Identifiers and References

Identifiers:  CCE-82347-6

References:  CCI-001954, CM-6(a), SRG-OS-000375-GPOS-00160, SRG-OS-000377-VMM-001530, 1382, 1384, 1386


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

if ! rpm -q --quiet "pcsc-lite" ; then
    yum install -y "pcsc-lite"
fi

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

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

Complexity:low
Disruption:low
Strategy:enable
include install_pcsc-lite

class install_pcsc-lite {
  package { 'pcsc-lite':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=pcsc-lite

Rule   Enable the pcscd Service   [ref]

The pcscd service can be enabled with the following command:
$ sudo systemctl enable pcscd.service
Rationale:
Using an authentication device, such as a CAC or token that is separate from the information system, ensures that even if the information system is compromised, that compromise will not affect credentials stored on the authentication device.

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

Identifiers:  CCE-80569-7

References:  CCI-001954, IA-2(1), IA-2(2), IA-2(3), IA-2(4), IA-2(6), IA-2(7), IA-2(11), CM-6(a), SRG-OS-000375-GPOS-00160, SRG-OS-000377-VMM-001530, 1382, 1384, 1386


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" start 'pcscd.service'
"$SYSTEMCTL_EXEC" enable 'pcscd.service'

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

Complexity:low
Disruption:low
Strategy:enable
- name: Enable service pcscd
  block:

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

    - name: Enable service pcscd
      service:
        name: pcscd
        enabled: 'yes'
        state: started
      when:
        - '"pcsc-lite" in ansible_facts.packages'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80569-7
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-2(1)
    - NIST-800-53-IA-2(11)
    - NIST-800-53-IA-2(2)
    - NIST-800-53-IA-2(3)
    - NIST-800-53-IA-2(4)
    - NIST-800-53-IA-2(6)
    - NIST-800-53-IA-2(7)
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - service_pcscd_enabled

Complexity:low
Disruption:low
Strategy:enable
include enable_pcscd

class enable_pcscd {
  service {'pcscd':
    enable => true,
    ensure => 'running',
  }
}

Rule   Force opensc To Use Defined Smart Card Driver   [ref]

The OpenSC smart card tool can auto-detect smart card drivers; however by forcing the smart card driver in use by your organization, opensc will no longer autodetect or use other drivers unless specified. This helps to prevent users from using unauthorized smart cards. The default smart card driver for this profile is cac. To force the OpenSC driver, edit the /etc/opensc-ARCH.conf (where ARCH is the architecture of your operating system) file. Look for a line similar to:
# force_card_driver = customcos;
and change it to:
force_card_driver = cac;
Rationale:
Smart card login provides two-factor authentication stronger than that provided by a username and password combination. Smart cards leverage PKI (public key infrastructure) in order to provide and verify credentials. Forcing the smart card driver in use by your organization helps to prevent users from using unauthorized smart cards.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_force_opensc_card_drivers
Identifiers and References

Identifiers:  CCE-81002-8

References:  CCI-000765, CCI-000766, CCI-000767, CCI-000768, CCI-000771, CCI-000772, CCI-000884, IA-2(1), IA-2(2), IA-2(3), IA-2(4), IA-2(6), IA-2(7), IA-2(11), CM-6(a), PR.AC-1, PR.AC-6, PR.AC-7, Req-8.3, SRG-OS-000104-GPOS-00051, SRG-OS-000106-GPOS-00053, SRG-OS-000107-GPOS-00054, SRG-OS-000109-GPOS-00056, SRG-OS-000108-GPOS-00055, SRG-OS-000108-GPOS-00057, SRG-OS-000108-GPOS-00058, 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, 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, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 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, 1, 12, 15, 16, 5, SRG-OS-000376-VMM-001520, 1382, 1384, 1386


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


var_smartcard_drivers="cac"



OPENSC_TOOL="/usr/bin/opensc-tool"

if [ -f "${OPENSC_TOOL}" ]; then
    ${OPENSC_TOOL} -S app:default:force_card_driver:$var_smartcard_drivers
fi

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

Complexity:low
Disruption:low
Strategy:configure
- name: XCCDF Value var_smartcard_drivers # promote to variable
  set_fact:
    var_smartcard_drivers: !!str cac
  tags:
    - always

- name: Check existence of opensc conf
  stat:
    path: /etc/opensc-{{ ansible_architecture }}.conf
  register: opensc_conf_fcd
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-81002-8
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-2(1)
    - NIST-800-53-IA-2(11)
    - NIST-800-53-IA-2(2)
    - NIST-800-53-IA-2(3)
    - NIST-800-53-IA-2(4)
    - NIST-800-53-IA-2(6)
    - NIST-800-53-IA-2(7)
    - PCI-DSS-Req-8.3
    - configure_strategy
    - force_opensc_card_drivers
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Force smartcard driver block
  block:

    - name: Check if force_card_driver is defined
      command: /usr/bin/opensc-tool -G app:default:force_card_driver
      changed_when: false
      register: force_card_driver

    - name: Force opensc To Use Defined Smart Card Driver
      command: |
        /usr/bin/opensc-tool -S app:default:force_card_driver:{{ var_smartcard_drivers }}
      when:
        - force_card_driver.stdout != var_smartcard_drivers
  when:
    - opensc_conf_fcd.stat.exists
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-81002-8
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-2(1)
    - NIST-800-53-IA-2(11)
    - NIST-800-53-IA-2(2)
    - NIST-800-53-IA-2(3)
    - NIST-800-53-IA-2(4)
    - NIST-800-53-IA-2(6)
    - NIST-800-53-IA-2(7)
    - PCI-DSS-Req-8.3
    - configure_strategy
    - force_opensc_card_drivers
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

Rule   Configure opensc Smart Card Drivers   [ref]

The OpenSC smart card tool can auto-detect smart card drivers; however, setting the smart card drivers in use by your organization helps to prevent users from using unauthorized smart cards. The default smart card driver for this profile is cac. To configure the OpenSC driver, edit the /etc/opensc-ARCH.conf (where ARCH is the architecture of your operating system) file. Look for a line similar to:
# card_drivers = old, internal;
and change it to:
card_drivers = cac;
Rationale:
Smart card login provides two-factor authentication stronger than that provided by a username and password combination. Smart cards leverage PKI (public key infrastructure) in order to provide and verify credentials. Configuring the smart card driver in use by your organization helps to prevent users from using unauthorized smart cards.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_configure_opensc_card_drivers
Identifiers and References

Identifiers:  CCE-80565-5

References:  CCI-000765, CCI-000766, CCI-000767, CCI-000768, CCI-000771, CCI-000772, CCI-000884, IA-2(1), IA-2(2), IA-2(3), IA-2(4), IA-2(6), IA-2(7), IA-2(11), CM-6(a), PR.AC-1, PR.AC-6, PR.AC-7, Req-8.3, SRG-OS-000104-GPOS-00051, SRG-OS-000106-GPOS-00053, SRG-OS-000107-GPOS-00054, SRG-OS-000109-GPOS-00056, SRG-OS-000108-GPOS-00055, SRG-OS-000108-GPOS-00057, SRG-OS-000108-GPOS-00058, 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, 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, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 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, 1, 12, 15, 16, 5, SRG-OS-000376-VMM-001520, 1382, 1384, 1386


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


var_smartcard_drivers="cac"



OPENSC_TOOL="/usr/bin/opensc-tool"

if [ -f "${OPENSC_TOOL}" ]; then
    ${OPENSC_TOOL} -S app:default:card_drivers:$var_smartcard_drivers
fi

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

Complexity:low
Disruption:low
Strategy:configure
- name: XCCDF Value var_smartcard_drivers # promote to variable
  set_fact:
    var_smartcard_drivers: !!str cac
  tags:
    - always

- name: Check existence of opensc conf
  stat:
    path: /etc/opensc-{{ ansible_architecture }}.conf
  register: opensc_conf_cd
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80565-5
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-2(1)
    - NIST-800-53-IA-2(11)
    - NIST-800-53-IA-2(2)
    - NIST-800-53-IA-2(3)
    - NIST-800-53-IA-2(4)
    - NIST-800-53-IA-2(6)
    - NIST-800-53-IA-2(7)
    - PCI-DSS-Req-8.3
    - configure_opensc_card_drivers
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Configure smartcard driver block
  block:

    - name: Check if card_drivers is defined
      command: /usr/bin/opensc-tool -G app:default:card_drivers
      changed_when: false
      register: card_drivers

    - name: Configure opensc Smart Card Drivers
      command: |
        /usr/bin/opensc-tool -S app:default:card_drivers:{{ var_smartcard_drivers }}
      when:
        - card_drivers.stdout != var_smartcard_drivers
  when:
    - opensc_conf_cd.stat.exists
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80565-5
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-2(1)
    - NIST-800-53-IA-2(11)
    - NIST-800-53-IA-2(2)
    - NIST-800-53-IA-2(3)
    - NIST-800-53-IA-2(4)
    - NIST-800-53-IA-2(6)
    - NIST-800-53-IA-2(7)
    - PCI-DSS-Req-8.3
    - configure_opensc_card_drivers
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

Rule   Configure NSS DB To Use opensc   [ref]

The opensc module should be configured for use over the Coolkey PKCS#11 module in the NSS database. To configure the NSS database to use the opensc module, run the following command:
$ sudo pkcs11-switch opensc
Rationale:
Smart card login provides two-factor authentication stronger than that provided by a username and password combination. Smart cards leverage PKI (public key infrastructure) in order to provide and verify credentials.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_configure_opensc_nss_db
Identifiers and References

Identifiers:  CCE-80567-1

References:  CCI-000765, CCI-000766, CCI-000767, CCI-000768, CCI-000771, CCI-000772, CCI-000884, IA-2(1), IA-2(2), IA-2(3), IA-2(4), IA-2(6), IA-2(7), IA-2(11), CM-6(a), PR.AC-1, PR.AC-6, PR.AC-7, Req-8.3, SRG-OS-000104-GPOS-00051, SRG-OS-000106-GPOS-00053, SRG-OS-000107-GPOS-00054, SRG-OS-000109-GPOS-00056, SRG-OS-000108-GPOS-00055, SRG-OS-000108-GPOS-00057, SRG-OS-000108-GPOS-00058, 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, 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, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.10, 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, 1, 12, 15, 16, 5, SRG-OS-000376-VMM-001520, SRG-OS-000403-VMM-001640


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

PKCSSW=$(/usr/bin/pkcs11-switch)

if [ ${PKCSSW} != "opensc" ] ; then
    ${PKCSSW} opensc
fi

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

Complexity:low
Disruption:low
Strategy:configure
- name: Check existence of pkcs11-switch
  stat:
    path: /usr/bin/pkcs11-switch
  register: pkcs11switch
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80567-1
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-2(1)
    - NIST-800-53-IA-2(11)
    - NIST-800-53-IA-2(2)
    - NIST-800-53-IA-2(3)
    - NIST-800-53-IA-2(4)
    - NIST-800-53-IA-2(6)
    - NIST-800-53-IA-2(7)
    - PCI-DSS-Req-8.3
    - configure_opensc_nss_db
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Get NSS database smart card configuration
  command: /usr/bin/pkcs11-switch
  changed_when: true
  register: pkcsw_output
  when:
    - pkcs11switch.stat.exists
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80567-1
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-2(1)
    - NIST-800-53-IA-2(11)
    - NIST-800-53-IA-2(2)
    - NIST-800-53-IA-2(3)
    - NIST-800-53-IA-2(4)
    - NIST-800-53-IA-2(6)
    - NIST-800-53-IA-2(7)
    - PCI-DSS-Req-8.3
    - configure_opensc_nss_db
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed

- name: Configure NSS DB To Use opensc
  command: /usr/bin/pkcs11-switch opensc
  when:
    - pkcs11switch.stat.exists and pkcsw_output.stdout != "opensc"
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80567-1
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-2(1)
    - NIST-800-53-IA-2(11)
    - NIST-800-53-IA-2(2)
    - NIST-800-53-IA-2(3)
    - NIST-800-53-IA-2(4)
    - NIST-800-53-IA-2(6)
    - NIST-800-53-IA-2(7)
    - PCI-DSS-Req-8.3
    - configure_opensc_nss_db
    - configure_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
Group   Configure Console Screen Locking   Group contains 1 rule
[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 screen Package   [ref]

To enable console screen locking, install the screen package. The screen package can be installed with the following command:
$ sudo yum install screen
Instruct users to begin new terminal sessions with the following command:
$ screen
The console can now be locked with the following key combination:
ctrl+a x
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 screen package allows for a session lock to be implemented and configured.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_package_screen_installed
Identifiers and References

Identifiers:  CCE-27351-6

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


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

if ! rpm -q --quiet "screen" ; then
    yum install -y "screen"
fi

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

Complexity:low
Disruption:low
Strategy:enable
- name: Ensure screen is installed
  package:
    name: screen
    state: present
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-27351-6
    - DISA-STIG-RHEL-07-010090
    - NIST-800-171-3.1.10
    - NIST-800-53-CM-6(a)
    - enable_strategy
    - low_complexity
    - low_disruption
    - medium_severity
    - no_reboot_needed
    - package_screen_installed

Complexity:low
Disruption:low
Strategy:enable
include install_screen

class install_screen {
  package { 'screen':
    ensure => 'installed',
  }
}

Complexity:low
Disruption:low
Strategy:enable

package --add=screen

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

Identifiers:  CCE-80206-6

References:  3.4.5, 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), FIA_UAU.1, SRG-OS-000324-GPOS-00125


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: Gather the service facts
      service_facts: null

    - name: Disable service debug-shell
      systemd:
        name: debug-shell.service
        enabled: 'no'
        state: stopped
        masked: 'yes'
      when: '"debug-shell.service" in ansible_facts.services'
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80206-6
    - NIST-800-171-3.4.5
    - 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:
    - CCE-80206-6
    - NIST-800-171-3.4.5
    - 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:
    - '"debug-shell.socket" in socket_file_exists.stdout_lines[1]'
    - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-80206-6
    - NIST-800-171-3.4.5
    - 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

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

Identifiers:  CCE-27287-2

References:  1.4.3, 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), 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, 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, 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, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.03, DSS06.06, DSS06.10, 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, 1, 11, 12, 14, 15, 16, 18, 3, 5, 0421, 0422, 0431, 0974, 1173, 1401, 1504, 1505, 1546, 1557, 1558, 1559, 1560, 1561, RHEL-07-010481, SV-204437r603261_rule


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

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

sulogin='/bin/sh -c "/sbin/sulogin; /usr/bin/systemctl --fail --no-block default"'

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=-/bin/sh -c "/sbin/sulogin; /usr/bin/systemctl --fail --no-block
      default"
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-27287-2
    - DISA-STIG-RHEL-07-010481
    - 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

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

Identifiers:  CCE-27511-5

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(a), AC-6(1), PR.AC-4, PR.DS-5, SRG-OS-000324-GPOS-00125, SRG-OS-000480-GPOS-00227, SR 2.1, SR 5.2, 4.3.3.7.3, APO01.06, DSS05.04, DSS05.07, DSS06.02, 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, 12, 13, 14, 15, 16, 18, 3, 5, RHEL-07-020230, SV-204455r603261_rule


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

# The process to disable ctrl+alt+del has changed in RHEL7. 
# Reference: https://access.redhat.com/solutions/1123873

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

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

Complexity:low
Disruption:low
Strategy:disable
- name: Disable Ctrl-Alt-Del Reboot Activation
  systemd:
    name: ctrl-alt-del.target
    masked: true
    state: stopped
  when: ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"]
  tags:
    - CCE-27511-5
    - DISA-STIG-RHEL-07-020230
    - NIST-800-171-3.4.5
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - disable_ctrlaltdel_reboot
    - disable_strategy
    - high_severity
    - low_complexity
    - low_disruption
    - no_reboot_needed

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

Identifiers:  CCE-80449-2

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(a), AC-6(1), CM-6(a), PR.AC-4, PR.DS-5, SRG-OS-000324-GPOS-00125, SR 2.1, SR 5.2, 4.3.3.7.3, APO01.06, DSS05.04, DSS05.07, DSS06.02, 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, 12, 13, 14, 15, 16, 18, 3, 5


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

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

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

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

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

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

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

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

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

Complexity:low
Disruption:low
Strategy:disable
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CCE-80449-2
    - NIST-800-171-3.4.5
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-6(a)
    - disable_ctrlaltdel_burstaction
    - disable_strategy
    - high_severity
    - low_complexity
    - low_disruption
    - no_reboot_needed

- name: Disable Ctrl-Alt-Del Burst Action
  lineinfile:
    dest: /etc/systemd/system.conf
    state: present
    regexp: ^CtrlAltDelBurstAction
    line: CtrlAltDelBurstAction=none
    create: true
  when: '"systemd" in ansible_facts.packages'
  tags:
    - CCE-80449-2
    - NIST-800-171-3.4.5
    - NIST-800-53-AC-6(1)
    - NIST-800-53-CM-6(a)
    - NIST-800-53-CM-6(a)
    - disable_ctrlaltdel_burstaction
    - disable_strategy
    - high_severity
    - low_complexity
    - low_disruption
    - no_reboot_needed

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   Verify that Interactive Boot is Disabled   [ref]

Red Hat Enterprise Linux 7 systems support an "interactive boot" option that can be used to prevent services from being started. On a Red Hat Enterprise Linux 7 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

Identifiers:  CCE-27335-9

References:  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), SC-2(1), CM-6(a), PR.AC-4, PR.AC-6, PR.PT-3, FIA_UAU.1, 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, 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, DSS05.02, DSS05.04, DSS05.05, DSS05.07, DSS06.03, DSS06.06, 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, 11, 12, 14, 15, 16, 18, 3, 5, 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

Complexity:low
Disruption:low
Reboot:true
Strategy:restrict
- name: Gather the package facts
  package_facts:
    manager: auto
  tags:
    - CCE-27335-9
    - NIST-800-171-3.1.2
    - NIST-800-171-3.4.5
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SC-2(1)
    - grub2_disable_interactive_boot
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Verify that Interactive Boot is Disabled in /etc/default/grub
  replace:
    dest: /etc/default/grub
    regexp: systemd.confirm_spawn=(1|yes|true|on)
    replace: systemd.confirm_spawn=no
  when: '"grub2-common" in ansible_facts.packages'
  tags:
    - CCE-27335-9
    - NIST-800-171-3.1.2
    - NIST-800-171-3.4.5
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SC-2(1)
    - grub2_disable_interactive_boot
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy

- name: Verify that Interactive Boot is Disabled (runtime)
  command: /sbin/grubby --update-kernel=ALL --remove-args="systemd.confirm_spawn"
  when: '"grub2-common" in ansible_facts.packages'
  tags:
    - CCE-27335-9
    - NIST-800-171-3.1.2
    - NIST-800-171-3.4.5
    - NIST-800-53-CM-6(a)
    - NIST-800-53-SC-2(1)
    - grub2_disable_interactive_boot
    - low_complexity
    - low_disruption
    - medium_severity
    - reboot_required
    - restrict_strategy
Group   Protect Accounts by Restricting Password-Based Login   Group contains 4 groups and 14 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 6 rules
[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

Rule   Set Existing Passwords Maximum Age   [ref]

Configure non-compliant accounts to enforce a 60-day maximum password lifetime restriction by running the following command:
$ sudo chage -M 60 USER
Rationale:
Any password, no matter how complex, can eventually be cracked. Therefore, passwords need to be changed periodically. If the operating system does not limit the lifetime of passwords and force users to change their passwords, there is the risk that the operating system passwords could be compromised.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_password_set_max_life_existing
Identifiers and References

Identifiers:  CCE-80522-6

References:  IA-5(f), IA-5(1)(d), CM-6(a), CCI-000199, SRG-OS-000076-GPOS-00044, SRG-OS-000076-VMM-000430, RHEL-07-010260, SV-204421r603261_rule

Rule   Set Existing Passwords Minimum Age   [ref]

Configure non-compliant accounts to enforce a 24 hours/1 day minimum password lifetime by running the following command:
$ sudo chage -m 1 USER
Rationale:
Enforcing a minimum password lifetime helps to prevent repeated password changes to defeat the password reuse or history enforcement requirement. If users are allowed to immediately and continually change their password, the password could be repeatedly changed in a short period of time to defeat the organization's policy regarding password reuse.
Severity: 
medium
Rule ID:xccdf_org.ssgproject.content_rule_accounts_password_set_min_life_existing
Identifiers and References

Identifiers:  CCE-80521-8

References:  IA-5(f), IA-5(1)(d), CM-6(a), CCI-000198, SRG-OS-000075-GPOS-00043, SRG-OS-000075-VMM000420, RHEL-07-010240, SV-204419r603261_rule

Group   Verify Proper Storage and Existence of Password Hashes   Group contains 3 rules
[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.
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

Identifiers:  CCE-27286-4

References:  5.5.2, 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), 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, 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, 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, APO01.06, DSS05.04, DSS05.05, DSS05.07, DSS05.10, DSS06.02, DSS06.03, DSS06.10, 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, 1, 12, 13, 14, 15, 16, 18, 3, 5, RHEL-07-010290, SV-204424r603261_rule


sed --follow-symlinks -i 's/\<nullok\>//g' /etc/pam.d/system-auth
sed --follow-symlinks -i 's/\<nullok\>//g' /etc/pam.d/password-auth

Complexity:low
Disruption:medium
Strategy:configure
- name: Prevent Log In to Accounts With Empty Password - system-auth
  replace:
    dest: /etc/pam.d/system-auth
    regexp: nullok
  tags:
    - CCE-27286-4
    - CJIS-5.5.2
    - DISA-STIG-RHEL-07-010290
    - NIST-800-171-3.1.1
    - NIST-800-171-3.1.5
    - NIST-800-53-CM-6(a)
    - NIST-800-53-IA-5(1)(a)
    - NIST-800-53-IA-5(c)
    - PCI-DSS-Req-8.2.3
    - configure_strategy
    - high_severity
    - low_complexity
    - medium_disruption
    - no_empty_passwords
    - no_reboot_needed

- name: Prevent Log In to Accounts With Empty Password - password-auth
  replace:
    dest: /etc/pam.d/password-auth
    regexp: nullok
  tags:
    - CCE-27286-4
    - CJIS-5.5.2
    - DISA-STIG-RHEL-07-010290
    - 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

Rule   All GIDs referenced in /etc/passwd must be defined in /etc/group   [ref]

Add a group to the system for each GID referenced without a corresponding group.
Rationale:
If a user is assigned the Group Identifier (GID) of a group not existing on the system, and a group with the Gruop Identifier (GID) is subsequently created, the user may have unintended rights to any files associated with the group.
Severity: 
low
Rule ID:xccdf_org.ssgproject.content_rule_gid_passwd_group_same
Identifiers and References

Identifiers:  CCE-27503-2

References:  5.5.2, CCI-000764, IA-2, CM-6(a), PR.AC-1, PR.AC-6, PR.AC-7, Req-8.5.a, SRG-OS-000104-GPOS-00051, 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, 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,