Blob Blame History Raw
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/ansible/shared.yml b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/ansible/shared.yml
new file mode 100644
index 00000000000..b44c91cbf4a
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/ansible/shared.yml
@@ -0,0 +1,150 @@
+# platform = Red Hat Virtualization 4,multi_platform_fedora,multi_platform_rhel
+# reboot = false
+# strategy = configure
+# complexity = low
+# disruption = medium
+
+- name: Check for existing pam_pwquality.so entry
+  ansible.builtin.lineinfile:
+    path: "/etc/pam.d/password-auth"
+    create: no
+    regexp: '^password.*pam_pwquality.so.*'
+    state: absent
+  check_mode: true
+  changed_when: false
+  register: result_pam_pwquality_present
+
+- name: Check if system relies on authselect
+  ansible.builtin.stat:
+    path: /usr/bin/authselect
+  register: result_authselect_present
+
+- name: "Remediation where authselect tool is present"
+  block:
+    - name: Check the integrity of the current authselect profile
+      ansible.builtin.command:
+        cmd: authselect check
+      register: result_authselect_check_cmd
+      changed_when: false
+      ignore_errors: true
+
+    - name: Informative message based on the authselect integrity check result
+      ansible.builtin.assert:
+        that:
+          - result_authselect_check_cmd is success
+        fail_msg:
+        - authselect integrity check failed. Remediation aborted!
+        - This remediation could not be applied because the authselect profile is not intact.
+        - It is not recommended to manually edit the PAM files when authselect is available.
+        - In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended.
+        success_msg:
+        - authselect integrity check passed
+
+    - name: Get authselect current profile
+      ansible.builtin.shell:
+        cmd: authselect current -r | awk '{ print $1 }'
+      register: result_authselect_profile
+      changed_when: false
+      when:
+        - result_authselect_check_cmd is success
+
+    - name: Define the current authselect profile as a local fact
+      ansible.builtin.set_fact:
+        authselect_current_profile: "{{ result_authselect_profile.stdout }}"
+        authselect_custom_profile: "{{ result_authselect_profile.stdout }}"
+      when:
+        - result_authselect_profile is not skipped
+        - result_authselect_profile.stdout is match("custom/")
+
+    - name: Define the new authselect custom profile as a local fact
+      ansible.builtin.set_fact:
+        authselect_current_profile: "{{ result_authselect_profile.stdout }}"
+        authselect_custom_profile: "custom/hardening"
+      when:
+        - result_authselect_profile is not skipped
+        - result_authselect_profile.stdout is not match("custom/")
+
+    - name: Get authselect current features to also enable them in the custom profile
+      ansible.builtin.shell:
+        cmd: authselect current | tail -n+3 | awk '{ print $2 }'
+      register: result_authselect_features
+      changed_when: false
+      when:
+        - result_authselect_profile is not skipped
+        - authselect_current_profile is not match("custom/")
+
+    - name: Check if any custom profile with the same name was already created in the past
+      ansible.builtin.stat:
+        path: /etc/authselect/{{ authselect_custom_profile }}
+      register: result_authselect_custom_profile_present
+      changed_when: false
+      when:
+        - authselect_current_profile is not match("custom/")
+
+    - name: Create a custom profile based on the current profile
+      ansible.builtin.command:
+        cmd: authselect create-profile hardening -b sssd
+      when:
+        - result_authselect_check_cmd is success
+        - authselect_current_profile is not match("custom/")
+        - not result_authselect_custom_profile_present.stat.exists
+
+    - name: Ensure the desired configuration is present in the custom profile
+      ansible.builtin.lineinfile:
+        dest: "/etc/authselect/{{ authselect_custom_profile }}/password-auth"
+        insertbefore: ^password.*sufficient.*pam_unix.so.*
+        line: "password    requisite                                    pam_pwquality.so"
+      when:
+        - result_authselect_profile is not skipped
+        - result_pam_pwquality_present.found == 0
+
+    - name: Ensure a backup of current authselect profile before selecting the custom profile
+      ansible.builtin.command:
+        cmd: authselect apply-changes -b --backup=before-pwquality-hardening.backup
+      register: result_authselect_backup
+      when:
+        - result_authselect_check_cmd is success
+        - result_authselect_profile is not skipped
+        - authselect_current_profile is not match("custom/")
+        - authselect_custom_profile is not match(authselect_current_profile)
+
+    - name: Ensure the custom profile is selected
+      ansible.builtin.command:
+        cmd: authselect select {{ authselect_custom_profile }} --force
+      register: result_pam_authselect_select_profile
+      when:
+        - result_authselect_check_cmd is success
+        - result_authselect_profile is not skipped
+        - authselect_current_profile is not match("custom/")
+        - authselect_custom_profile is not match(authselect_current_profile)
+
+    - name: Restore the authselect features in the custom profile
+      ansible.builtin.command:
+        cmd: authselect enable-feature {{ item }}
+      loop: "{{ result_authselect_features.stdout_lines }}"
+      when:
+        - result_authselect_profile is not skipped
+        - result_authselect_features is not skipped
+        - result_pam_authselect_select_profile is not skipped
+
+    - name: Ensure the custom profile changes are applied
+      ansible.builtin.command:
+        cmd: authselect apply-changes -b --backup=after-pwquality-hardening.backup
+      when:
+        - result_authselect_check_cmd is success
+        - result_authselect_profile is not skipped
+  when:
+  - result_authselect_present.stat.exists
+
+# For systems without authselect
+- name: "Remediation where authselect tool is not present and PAM files are directly edited"
+  block:
+    - name: Ensure the desired configuration is present in the custom profile
+      ansible.builtin.lineinfile:
+        dest: "/etc/pam.d/password-auth"
+        insertbefore: ^password.*sufficient.*pam_unix.so.*
+        line: "password    requisite                                    pam_pwquality.so"
+      when:
+        - result_pam_pwquality_present.found == 0
+  when:
+    - not result_authselect_present.stat.exists
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/bash/shared.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/bash/shared.sh
new file mode 100644
index 00000000000..d2fca2a79ca
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/bash/shared.sh
@@ -0,0 +1,41 @@
+# platform = Red Hat Virtualization 4,multi_platform_fedora,multi_platform_rhel
+
+PAM_FILE="password-auth"
+
+if [ -f /usr/bin/authselect ]; then
+    if authselect check; then
+        CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
+        # Standard profiles delivered with authselect should not be modified.
+        # If not already in use, a custom profile is created preserving the enabled features.
+        if [[ ! $CURRENT_PROFILE == custom/* ]]; then
+            ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
+            authselect create-profile hardening -b $CURRENT_PROFILE
+            CURRENT_PROFILE="custom/hardening"
+            # Ensure a backup before changing the profile
+            authselect apply-changes -b --backup=before-pwquality-hardening.backup
+            authselect select $CURRENT_PROFILE
+            for feature in $ENABLED_FEATURES; do
+                authselect enable-feature $feature;
+            done
+        fi
+        # Include the desired configuration in the custom profile
+        CUSTOM_FILE="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE"
+        # The line should be included on the top password section
+		if [ $(grep -c "^\s*password.*requisite.*pam_pwquality.so" $CUSTOM_FILE) -eq 0 ]; then
+  		  sed -i --follow-symlinks '0,/^password.*/s/^password.*/password    requisite                                    pam_pwquality.so\n&/' $CUSTOM_FILE
+		fi
+        authselect apply-changes -b --backup=after-pwquality-hardening.backup
+    else
+        echo "
+authselect integrity check failed. Remediation aborted!
+This remediation could not be applied because the authselect profile is not intact.
+It is not recommended to manually edit the PAM files when authselect is available.
+In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
+        false
+    fi
+else
+    FILE_PATH="/etc/pam.d/$PAM_FILE"
+    if [ $(grep -c "^\s*password.*requisite.*pam_pwquality.so" $FILE_PATH) -eq 0 ]; then
+        sed -i --follow-symlinks '0,/^password.*/s/^password.*/password    requisite                                    pam_pwquality.so\n&/' $FILE_PATH
+    fi
+fi
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/oval/shared.xml b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/oval/shared.xml
new file mode 100644
index 00000000000..84f32456beb
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/oval/shared.xml
@@ -0,0 +1,21 @@
+<def-group>
+  <definition class="compliance" id="{{{ rule_id }}}" version="1">
+    {{{ oval_metadata("The PAM module pam_pwquality is used in password-auth") }}}
+    <criteria comment="Condition for pam_pwquality in password-auth is satisfied">
+      <criterion comment="pam_pwquality password-auth"
+                 test_ref="test_accounts_password_pam_pwquality_password_auth"/>
+      </criteria>
+  </definition>
+
+  <ind:textfilecontent54_object id="object_accounts_password_pam_pwquality_password_auth" version="1">
+    <ind:filepath>/etc/pam.d/password-auth</ind:filepath>
+    <ind:pattern operation="pattern match">^password[\s]*requisite[\s]*pam_pwquality\.so</ind:pattern>
+    <ind:instance datatype="int" operation="equals">1</ind:instance>
+  </ind:textfilecontent54_object>
+
+  <ind:textfilecontent54_test check="all" check_existence="only_one_exists" version="1"
+                              id="test_accounts_password_pam_pwquality_password_auth"
+                              comment="check the configuration of /etc/pam.d/password-auth">
+    <ind:object object_ref="object_accounts_password_pam_pwquality_password_auth"/>
+  </ind:textfilecontent54_test>
+</def-group>
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/rule.yml b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/rule.yml
new file mode 100644
index 00000000000..6c7bb1ad7a0
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/rule.yml
@@ -0,0 +1,35 @@
+documentation_complete: true
+
+prodtype: fedora,rhel7,rhel8,rhel9,rhv4
+
+title: 'Ensure PAM password complexity module is enabled in password-auth'
+
+description: |-
+    To enable PAM password complexity in password-auth file:
+    Edit the <tt>password</tt> section in
+    <tt>/etc/pam.d/password-auth</tt> to show
+    <tt>password    requisite                                    pam_pwquality.so</tt>.
+
+rationale: |-
+    Enabling PAM password complexity permits to enforce strong passwords and consequently
+    makes the system less prone to dictionary attacks.
+
+severity: medium
+
+identifiers:
+    cce@rhel7: CCE-85876-1
+    cce@rhel8: CCE-85877-9
+    cce@rhel9: CCE-85878-7
+
+references:
+    stigid@rhel8: RHEL-08-020100
+
+ocil_clause: 'pam_pwquality.so is not enabled in password-auth'
+
+ocil: |-
+    To check if pam_pwhistory.so is enabled in password-auth, run the following command:
+    <pre>$ grep pam_pwquality /etc/pam.d/password-auth</pre></pre>
+    The output should be similar to the following:
+    <pre>password    requisite                                    pam_pwquality.so</pre>
+
+platform: pam
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/tests/authselect_commented_entry.fail.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/tests/authselect_commented_entry.fail.sh
new file mode 100644
index 00000000000..3d696c36b76
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/tests/authselect_commented_entry.fail.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+# packages = authselect
+# platform = Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+
+authselect create-profile hardening -b sssd
+CUSTOM_PROFILE="custom/hardening"
+authselect select $CUSTOM_PROFILE --force
+
+CUSTOM_SYSTEM_AUTH="/etc/authselect/$CUSTOM_PROFILE/password-auth"
+sed -i --follow-symlinks -e '/^password\s*requisite\s*pam_pwquality\.so/ s/^#*/#/g' $CUSTOM_SYSTEM_AUTH
+authselect apply-changes -b
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/tests/authselect_correct_entry.pass.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/tests/authselect_correct_entry.pass.sh
new file mode 100644
index 00000000000..0435899262b
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/tests/authselect_correct_entry.pass.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+# packages = authselect
+# platform = Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+
+authselect create-profile hardening -b sssd
+CUSTOM_PROFILE="custom/hardening"
+authselect select $CUSTOM_PROFILE --force
+
+CUSTOM_SYSTEM_AUTH="/etc/authselect/$CUSTOM_PROFILE/password-auth"
+if [ $(grep -c "^\s*password.*requisite.*pam_pwquality.so" $CUSTOM_SYSTEM_AUTH) -eq 0 ]; then
+    sed -i --follow-symlinks '0,/^password.*/s/^password.*/password     requisite   pam_pwquality.so\n&/' $CUSTOM_SYSTEM_AUTH
+fi
+authselect apply-changes -b
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/tests/authselect_missing_entry.fail.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/tests/authselect_missing_entry.fail.sh
new file mode 100644
index 00000000000..472616a51f6
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/tests/authselect_missing_entry.fail.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+# packages = authselect
+# platform = Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+
+authselect create-profile hardening -b sssd
+CUSTOM_PROFILE="custom/hardening"
+authselect select $CUSTOM_PROFILE --force
+
+CUSTOM_SYSTEM_AUTH="/etc/authselect/$CUSTOM_PROFILE/password-auth"
+sed -i --follow-symlinks '/^password\s*requisite\s*pam_pwquality\.so/d' $CUSTOM_SYSTEM_AUTH
+authselect apply-changes -b
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/tests/authselect_modified_pam.fail.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/tests/authselect_modified_pam.fail.sh
new file mode 100644
index 00000000000..59f9d6f77c4
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/tests/authselect_modified_pam.fail.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+# packages = authselect
+# platform = Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+# remediation = none
+
+SYSTEM_AUTH_FILE="/etc/pam.d/password-auth"
+
+# This modification will break the integrity checks done by authselect.
+sed -i --follow-symlinks -e '/^password\s*requisite\s*pam_pwquality\.so/ s/^#*/#/g' $SYSTEM_AUTH_FILE
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/tests/correct_entry.pass.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/tests/correct_entry.pass.sh
new file mode 100644
index 00000000000..71f87b19045
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/tests/correct_entry.pass.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+# packages = pam
+# platform = Red Hat Enterprise Linux 7,Red Hat Virtualization 4,multi_platform_fedora
+
+config_file=/etc/pam.d/password-auth
+if [ $(grep -c "^\s*password.*requisite.*pam_pwquality.so" $config_file) -eq 0 ]; then
+    sed -i --follow-symlinks '0,/^password.*/s/^password.*/password		requisite	pam_pwquality.so\n&/' $config_file
+fi
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/tests/missing_entry.fail.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/tests/missing_entry.fail.sh
new file mode 100644
index 00000000000..95b73b24d26
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_password_auth/tests/missing_entry.fail.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+# platform = Red Hat Enterprise Linux 7,Red Hat Virtualization 4,multi_platform_fedora
+# packages = pam
+
+config_file=/etc/pam.d/password-auth
+
+sed -i --follow-symlinks '/^password\s*requisite\s*pam_pwquality\.so/d' $config_file
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/ansible/shared.yml b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/ansible/shared.yml
new file mode 100644
index 00000000000..13cd20458ed
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/ansible/shared.yml
@@ -0,0 +1,150 @@
+# platform = Red Hat Virtualization 4,multi_platform_fedora,multi_platform_rhel
+# reboot = false
+# strategy = configure
+# complexity = low
+# disruption = medium
+
+- name: Check for existing pam_pwquality.so entry
+  ansible.builtin.lineinfile:
+    path: "/etc/pam.d/system-auth"
+    create: no
+    regexp: '^password.*pam_pwquality.so.*'
+    state: absent
+  check_mode: true
+  changed_when: false
+  register: result_pam_pwquality_present
+
+- name: Check if system relies on authselect
+  ansible.builtin.stat:
+    path: /usr/bin/authselect
+  register: result_authselect_present
+
+- name: "Remediation where authselect tool is present"
+  block:
+    - name: Check the integrity of the current authselect profile
+      ansible.builtin.command:
+        cmd: authselect check
+      register: result_authselect_check_cmd
+      changed_when: false
+      ignore_errors: true
+
+    - name: Informative message based on the authselect integrity check result
+      ansible.builtin.assert:
+        that:
+          - result_authselect_check_cmd is success
+        fail_msg:
+        - authselect integrity check failed. Remediation aborted!
+        - This remediation could not be applied because the authselect profile is not intact.
+        - It is not recommended to manually edit the PAM files when authselect is available.
+        - In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended.
+        success_msg:
+        - authselect integrity check passed
+
+    - name: Get authselect current profile
+      ansible.builtin.shell:
+        cmd: authselect current -r | awk '{ print $1 }'
+      register: result_authselect_profile
+      changed_when: false
+      when:
+        - result_authselect_check_cmd is success
+
+    - name: Define the current authselect profile as a local fact
+      ansible.builtin.set_fact:
+        authselect_current_profile: "{{ result_authselect_profile.stdout }}"
+        authselect_custom_profile: "{{ result_authselect_profile.stdout }}"
+      when:
+        - result_authselect_profile is not skipped
+        - result_authselect_profile.stdout is match("custom/")
+
+    - name: Define the new authselect custom profile as a local fact
+      ansible.builtin.set_fact:
+        authselect_current_profile: "{{ result_authselect_profile.stdout }}"
+        authselect_custom_profile: "custom/hardening"
+      when:
+        - result_authselect_profile is not skipped
+        - result_authselect_profile.stdout is not match("custom/")
+
+    - name: Get authselect current features to also enable them in the custom profile
+      ansible.builtin.shell:
+        cmd: authselect current | tail -n+3 | awk '{ print $2 }'
+      register: result_authselect_features
+      changed_when: false
+      when:
+        - result_authselect_profile is not skipped
+        - authselect_current_profile is not match("custom/")
+
+    - name: Check if any custom profile with the same name was already created in the past
+      ansible.builtin.stat:
+        path: /etc/authselect/{{ authselect_custom_profile }}
+      register: result_authselect_custom_profile_present
+      changed_when: false
+      when:
+        - authselect_current_profile is not match("custom/")
+
+    - name: Create a custom profile based on the current profile
+      ansible.builtin.command:
+        cmd: authselect create-profile hardening -b sssd
+      when:
+        - result_authselect_check_cmd is success
+        - authselect_current_profile is not match("custom/")
+        - not result_authselect_custom_profile_present.stat.exists
+
+    - name: Ensure the desired configuration is present in the custom profile
+      ansible.builtin.lineinfile:
+        dest: "/etc/authselect/{{ authselect_custom_profile }}/system-auth"
+        insertbefore: ^password.*sufficient.*pam_unix.so.*
+        line: "password    requisite                                    pam_pwquality.so"
+      when:
+        - result_authselect_profile is not skipped
+        - result_pam_pwquality_present.found == 0
+
+    - name: Ensure a backup of current authselect profile before selecting the custom profile
+      ansible.builtin.command:
+        cmd: authselect apply-changes -b --backup=before-pwquality-hardening.backup
+      register: result_authselect_backup
+      when:
+        - result_authselect_check_cmd is success
+        - result_authselect_profile is not skipped
+        - authselect_current_profile is not match("custom/")
+        - authselect_custom_profile is not match(authselect_current_profile)
+
+    - name: Ensure the custom profile is selected
+      ansible.builtin.command:
+        cmd: authselect select {{ authselect_custom_profile }} --force
+      register: result_pam_authselect_select_profile
+      when:
+        - result_authselect_check_cmd is success
+        - result_authselect_profile is not skipped
+        - authselect_current_profile is not match("custom/")
+        - authselect_custom_profile is not match(authselect_current_profile)
+
+    - name: Restore the authselect features in the custom profile
+      ansible.builtin.command:
+        cmd: authselect enable-feature {{ item }}
+      loop: "{{ result_authselect_features.stdout_lines }}"
+      when:
+        - result_authselect_profile is not skipped
+        - result_authselect_features is not skipped
+        - result_pam_authselect_select_profile is not skipped
+
+    - name: Ensure the custom profile changes are applied
+      ansible.builtin.command:
+        cmd: authselect apply-changes -b --backup=after-pwquality-hardening.backup
+      when:
+        - result_authselect_check_cmd is success
+        - result_authselect_profile is not skipped
+  when:
+  - result_authselect_present.stat.exists
+
+# For systems without authselect
+- name: "Remediation where authselect tool is not present and PAM files are directly edited"
+  block:
+    - name: Ensure the desired configuration is present in the custom profile
+      ansible.builtin.lineinfile:
+        dest: "/etc/pam.d/system-auth"
+        insertbefore: ^password.*sufficient.*pam_unix.so.*
+        line: "password    requisite                                    pam_pwquality.so"
+      when:
+        - result_pam_pwquality_present.found == 0
+  when:
+    - not result_authselect_present.stat.exists
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/bash/shared.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/bash/shared.sh
new file mode 100644
index 00000000000..9a7972a3f93
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/bash/shared.sh
@@ -0,0 +1,41 @@
+# platform = Red Hat Virtualization 4,multi_platform_fedora,multi_platform_rhel
+
+PAM_FILE="system-auth"
+
+if [ -f /usr/bin/authselect ]; then
+    if authselect check; then
+        CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
+        # Standard profiles delivered with authselect should not be modified.
+        # If not already in use, a custom profile is created preserving the enabled features.
+        if [[ ! $CURRENT_PROFILE == custom/* ]]; then
+            ENABLED_FEATURES=$(authselect current | tail -n+3 | awk '{ print $2 }')
+            authselect create-profile hardening -b $CURRENT_PROFILE
+            CURRENT_PROFILE="custom/hardening"
+            # Ensure a backup before changing the profile
+            authselect apply-changes -b --backup=before-pwquality-hardening.backup
+            authselect select $CURRENT_PROFILE
+            for feature in $ENABLED_FEATURES; do
+                authselect enable-feature $feature;
+            done
+        fi
+        # Include the desired configuration in the custom profile
+        CUSTOM_FILE="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE"
+        # The line should be included on the top password section
+		if [ $(grep -c "^\s*password.*requisite.*pam_pwquality.so" $CUSTOM_FILE) -eq 0 ]; then
+  		  sed -i --follow-symlinks '0,/^password.*/s/^password.*/password    requisite                                    pam_pwquality.so\n&/' $CUSTOM_FILE
+		fi
+        authselect apply-changes -b --backup=after-pwquality-hardening.backup
+    else
+        echo "
+authselect integrity check failed. Remediation aborted!
+This remediation could not be applied because the authselect profile is not intact.
+It is not recommended to manually edit the PAM files when authselect is available.
+In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
+        false
+    fi
+else
+    FILE_PATH="/etc/pam.d/$PAM_FILE"
+    if [ $(grep -c "^\s*password.*requisite.*pam_pwquality.so" $FILE_PATH) -eq 0 ]; then
+        sed -i --follow-symlinks '0,/^password.*/s/^password.*/password    requisite                                    pam_pwquality.so\n&/' $FILE_PATH
+    fi
+fi
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/oval/shared.xml b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/oval/shared.xml
new file mode 100644
index 00000000000..f8d241f1ff2
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/oval/shared.xml
@@ -0,0 +1,21 @@
+<def-group>
+  <definition class="compliance" id="{{{ rule_id }}}" version="1">
+    {{{ oval_metadata("The PAM module pam_pwquality is used in system-auth") }}}
+    <criteria comment="Condition for pam_pwquality in system-auth is satisfied">
+      <criterion comment="pam_pwquality system-auth"
+                 test_ref="test_accounts_password_pam_pwquality_system_auth"/>
+      </criteria>
+  </definition>
+
+  <ind:textfilecontent54_object id="object_accounts_password_pam_pwquality_system_auth" version="1">
+    <ind:filepath>/etc/pam.d/system-auth</ind:filepath>
+    <ind:pattern operation="pattern match">^password[\s]*requisite[\s]*pam_pwquality\.so</ind:pattern>
+    <ind:instance datatype="int" operation="equals">1</ind:instance>
+  </ind:textfilecontent54_object>
+
+  <ind:textfilecontent54_test check="all" check_existence="only_one_exists" version="1"
+                              id="test_accounts_password_pam_pwquality_system_auth"
+                              comment="check the configuration of /etc/pam.d/system-auth">
+    <ind:object object_ref="object_accounts_password_pam_pwquality_system_auth"/>
+  </ind:textfilecontent54_test>
+</def-group>
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/rule.yml b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/rule.yml
new file mode 100644
index 00000000000..ea42ff9b07a
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/rule.yml
@@ -0,0 +1,35 @@
+documentation_complete: true
+
+prodtype: fedora,rhel7,rhel8,rhel9,rhv4
+
+title: 'Ensure PAM password complexity module is enabled in system-auth'
+
+description: |-
+    To enable PAM password complexity in system-auth file:
+    Edit the <tt>password</tt> section in
+    <tt>/etc/pam.d/system-auth</tt> to show
+    <tt>password    requisite                                    pam_pwquality.so</tt>.
+
+rationale: |-
+    Enabling PAM password complexity permits to enforce strong passwords and consequently
+    makes the system less prone to dictionary attacks.
+
+severity: medium
+
+identifiers:
+    cce@rhel7: CCE-85874-6
+    cce@rhel8: CCE-85872-0
+    cce@rhel9: CCE-85873-8
+
+references:
+    stigid@rhel8: RHEL-08-020101
+
+ocil_clause: 'pam_pwquality.so is not enabled in system-auth'
+
+ocil: |-
+    To check if pam_pwhistory.so is enabled in system-auth, run the following command:
+    <pre>$ grep pam_pwquality /etc/pam.d/system-auth</pre></pre>
+    The output should be similar to the following:
+    <pre>password    requisite                                    pam_pwquality.so</pre>
+
+platform: pam
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/tests/authselect_commented_entry.fail.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/tests/authselect_commented_entry.fail.sh
new file mode 100644
index 00000000000..849f16d0f93
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/tests/authselect_commented_entry.fail.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+# packages = authselect
+# platform = Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+
+authselect create-profile hardening -b sssd
+CUSTOM_PROFILE="custom/hardening"
+authselect select $CUSTOM_PROFILE --force
+
+CUSTOM_SYSTEM_AUTH="/etc/authselect/$CUSTOM_PROFILE/system-auth"
+sed -i --follow-symlinks -e '/^password\s*requisite\s*pam_pwquality\.so/ s/^#*/#/g' $CUSTOM_SYSTEM_AUTH
+authselect apply-changes -b
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/tests/authselect_correct_entry.pass.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/tests/authselect_correct_entry.pass.sh
new file mode 100644
index 00000000000..6a98c244980
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/tests/authselect_correct_entry.pass.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+# packages = authselect
+# platform = Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+
+authselect create-profile hardening -b sssd
+CUSTOM_PROFILE="custom/hardening"
+authselect select $CUSTOM_PROFILE --force
+
+CUSTOM_SYSTEM_AUTH="/etc/authselect/$CUSTOM_PROFILE/system-auth"
+if [ $(grep -c "^\s*password.*requisite.*pam_pwquality.so" $CUSTOM_SYSTEM_AUTH) -eq 0 ]; then
+    sed -i --follow-symlinks '0,/^password.*/s/^password.*/password     requisite   pam_pwquality.so\n&/' $CUSTOM_SYSTEM_AUTH
+fi
+authselect apply-changes -b
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/tests/authselect_missing_entry.fail.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/tests/authselect_missing_entry.fail.sh
new file mode 100644
index 00000000000..6786f6c13d7
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/tests/authselect_missing_entry.fail.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+# packages = authselect
+# platform = Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+
+authselect create-profile hardening -b sssd
+CUSTOM_PROFILE="custom/hardening"
+authselect select $CUSTOM_PROFILE --force
+
+CUSTOM_SYSTEM_AUTH="/etc/authselect/$CUSTOM_PROFILE/system-auth"
+sed -i --follow-symlinks '/^password\s*requisite\s*pam_pwquality\.so/d' $CUSTOM_SYSTEM_AUTH
+authselect apply-changes -b
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/tests/authselect_modified_pam.fail.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/tests/authselect_modified_pam.fail.sh
new file mode 100644
index 00000000000..b3d9e5884f5
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/tests/authselect_modified_pam.fail.sh
@@ -0,0 +1,9 @@
+#!/bin/bash
+# packages = authselect
+# platform = Red Hat Enterprise Linux 8,Red Hat Enterprise Linux 9,multi_platform_fedora
+# remediation = none
+
+SYSTEM_AUTH_FILE="/etc/pam.d/system-auth"
+
+# This modification will break the integrity checks done by authselect.
+sed -i --follow-symlinks -e '/^password\s*requisite\s*pam_pwquality\.so/ s/^#*/#/g' $SYSTEM_AUTH_FILE
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/tests/correct_entry.pass.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/tests/correct_entry.pass.sh
new file mode 100644
index 00000000000..71f87b19045
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/tests/correct_entry.pass.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+# packages = pam
+# platform = Red Hat Enterprise Linux 7,Red Hat Virtualization 4,multi_platform_fedora
+
+config_file=/etc/pam.d/password-auth
+if [ $(grep -c "^\s*password.*requisite.*pam_pwquality.so" $config_file) -eq 0 ]; then
+    sed -i --follow-symlinks '0,/^password.*/s/^password.*/password		requisite	pam_pwquality.so\n&/' $config_file
+fi
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/tests/missing_entry.fail.sh b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/tests/missing_entry.fail.sh
new file mode 100644
index 00000000000..3c8f6f79fe9
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_pwquality_system_auth/tests/missing_entry.fail.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+# platform = Red Hat Enterprise Linux 7,Red Hat Virtualization 4,multi_platform_fedora
+# packages = pam
+
+config_file=/etc/pam.d/system-auth
+
+sed -i --follow-symlinks '/^password\s*requisite\s*pam_pwquality\.so/d' $config_file
diff --git a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/rule.yml b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/rule.yml
index eeb55a6ff5c..6b2219a3eab 100644
--- a/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/rule.yml
+++ b/linux_os/guide/system/accounts/accounts-pam/password_quality/password_quality_pwquality/accounts_password_pam_retry/rule.yml
@@ -6,13 +6,16 @@ title: 'Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
 
 description: |-
     To configure the number of retry prompts that are permitted per-session:
+    {{% if product in ['rhel8', 'rhel9'] %}}
+    Edit the <tt>/etc/security/pwquality.conf</tt> to include
+    {{% else %}}
     Edit the <tt>pam_pwquality.so</tt> statement in
     {{% if 'ubuntu' not in product %}}
-    <tt>/etc/pam.d/system-auth</tt> {{% if product in ['rhel8', 'rhel9'] %}} and
-    <tt>/etc/pam.d/password-auth</tt> {{% endif %}} to show
+    <tt>/etc/pam.d/system-auth</tt> to show
     {{% else %}}
     <tt>/etc/pam.d/common-password</tt> to show
     {{% endif %}}
+    {{% endif %}}
     <tt>retry={{{xccdf_value("var_password_pam_retry") }}}</tt>, or a lower value if site
     policy is more restrictive. The DoD requirement is a maximum of 3 prompts
     per session.
@@ -48,17 +51,21 @@ references:
     stigid@ol7: OL07-00-010119
     stigid@ol8: OL08-00-020100
     stigid@rhel7: RHEL-07-010119
-    stigid@rhel8: RHEL-08-020100
+    stigid@rhel8: RHEL-08-020104
     stigid@ubuntu2004: UBTU-20-010057
 
 ocil_clause: 'it is not the required value'
 
 ocil: |-
     To check how many retry attempts are permitted on a per-session basis, run the following command:
+    {{% if product in ['rhel8', 'rhel9'] %}}
+    <pre>$ grep retry /etc/security/pwquality.conf</pre>
+    {{% else %}}
     {{% if 'ubuntu' in product %}}
     <pre>$ grep pam_pwquality /etc/pam.d/common-password</pre>
     {{% else %}}
-    <pre>$ grep pam_pwquality /etc/pam.d/system-auth {{% if product in ['rhel8', 'rhel9'] %}}/etc/pam.d/password-auth{{% endif %}}</pre>
+    <pre>$ grep pam_pwquality /etc/pam.d/system-auth</pre>
+    {{% endif %}}
     {{% endif %}}
     The <tt>retry</tt> parameter will indicate how many attempts are permitted.
     The DoD required value is less than or equal to 3.
diff --git a/products/rhel8/profiles/stig.profile b/products/rhel8/profiles/stig.profile
index d92bc72971c..62fc512f05e 100644
--- a/products/rhel8/profiles/stig.profile
+++ b/products/rhel8/profiles/stig.profile
@@ -523,6 +523,20 @@ selections:
     - sssd_enable_certmap
 
     # RHEL-08-020100
+    - accounts_password_pam_pwquality_password_auth
+
+    # RHEL-08-020101
+    - accounts_password_pam_pwquality_system_auth
+
+    # RHEL-08-020102
+    # This is only required for RHEL8 systems below version 8.4 where the
+    # retry parameter was not yet available on /etc/security/pwquality.conf.
+
+    # RHEL-08-020103
+    # This is only required for RHEL8 systems below version 8.4 where the
+    # retry parameter was not yet available on /etc/security/pwquality.conf.
+
+    # RHEL-08-020104
     - accounts_password_pam_retry
 
     # RHEL-08-020110
diff --git a/products/rhel9/profiles/stig.profile b/products/rhel9/profiles/stig.profile
index 42c6d0e9aca..ad08a6d3410 100644
--- a/products/rhel9/profiles/stig.profile
+++ b/products/rhel9/profiles/stig.profile
@@ -524,6 +524,20 @@ selections:
     - sssd_enable_certmap
 
     # RHEL-08-020100
+    - accounts_password_pam_pwquality_password_auth
+
+    # RHEL-08-020101
+    - accounts_password_pam_pwquality_system_auth
+
+    # RHEL-08-020102
+    # This is only required for RHEL8 systems below version 8.4 where the
+    # retry parameter was not yet available on /etc/security/pwquality.conf.
+
+    # RHEL-08-020103
+    # This is only required for RHEL8 systems below version 8.4 where the
+    # retry parameter was not yet available on /etc/security/pwquality.conf.
+
+    # RHEL-08-020104
     - accounts_password_pam_retry
 
     # RHEL-08-020110
diff --git a/tests/data/profile_stability/rhel8/stig.profile b/tests/data/profile_stability/rhel8/stig.profile
index e4fee44f9f9..33e82401c3d 100644
--- a/tests/data/profile_stability/rhel8/stig.profile
+++ b/tests/data/profile_stability/rhel8/stig.profile
@@ -53,6 +53,8 @@ selections:
 - accounts_password_pam_ocredit
 - accounts_password_pam_pwhistory_remember_password_auth
 - accounts_password_pam_pwhistory_remember_system_auth
+- accounts_password_pam_pwquality_password_auth
+- accounts_password_pam_pwquality_system_auth
 - accounts_password_pam_retry
 - accounts_password_pam_ucredit
 - accounts_password_pam_unix_rounds_password_auth
diff --git a/tests/data/profile_stability/rhel8/stig_gui.profile b/tests/data/profile_stability/rhel8/stig_gui.profile
index 83d04775e3a..5beeb4f28af 100644
--- a/tests/data/profile_stability/rhel8/stig_gui.profile
+++ b/tests/data/profile_stability/rhel8/stig_gui.profile
@@ -64,6 +64,8 @@ selections:
 - accounts_password_pam_ocredit
 - accounts_password_pam_pwhistory_remember_password_auth
 - accounts_password_pam_pwhistory_remember_system_auth
+- accounts_password_pam_pwquality_password_auth
+- accounts_password_pam_pwquality_system_auth
 - accounts_password_pam_retry
 - accounts_password_pam_ucredit
 - accounts_password_pam_unix_rounds_password_auth