diff --git a/components/pam.yml b/components/pam.yml
index fb15e21b9cd..8cc1332d520 100644
--- a/components/pam.yml
+++ b/components/pam.yml
@@ -39,6 +39,7 @@ rules:
- accounts_password_all_shadowed_sha512
- accounts_password_last_change_is_in_past
- accounts_password_minlen_login_defs
+- accounts_password_pam_modules_in_authselect_profile
- accounts_password_pam_pwhistory_enabled
- accounts_password_pam_pwhistory_enforce_root
- accounts_password_pam_pwhistory_enforce_for_root
diff --git a/controls/cis_fedora.yml b/controls/cis_fedora.yml
index e1d03da07f5..031e276bc3d 100644
--- a/controls/cis_fedora.yml
+++ b/controls/cis_fedora.yml
@@ -1978,15 +1978,24 @@ controls:
levels:
- l1_server
- l1_workstation
- status: partial
+ status: automated
notes: |-
- This requirement is hard to be automated without any specific requirement. The policy even
- states that provided commands are examples, other custom settings might be in place and the
- settings might be different depending on site policies. The other rules will already make
- sure there is a correct autheselect profile regardless of the existing settings. It is
- necessary to better discuss with CIS Community.
+ This rule verifies that the active authselect profile includes the required PAM modules:
+ pam_pwquality.so, pam_pwhistory.so, pam_faillock.so, and pam_unix.so in both system-auth
+ and password-auth files. The rule checks the authselect profile source files directly,
+ not the symlinked files in /etc/pam.d/. Other rules ensure these modules are properly
+ configured with correct options.
+ rules:
+ - accounts_password_pam_modules_in_authselect_profile
related_rules:
- - no_empty_passwords
+ - enable_authselect
+ - account_password_pam_faillock_password_auth
+ - account_password_pam_faillock_system_auth
+ - accounts_password_pam_pwquality_password_auth
+ - accounts_password_pam_pwquality_system_auth
+ - accounts_password_pam_pwhistory_remember_password_auth
+ - accounts_password_pam_pwhistory_remember_system_auth
+ - accounts_password_pam_unix_enabled
- id: 5.3.2.2
title: Ensure pam_faillock module is enabled (Automated)
diff --git a/linux_os/guide/system/accounts/accounts-pam/accounts_password_pam_modules_in_authselect_profile/ansible/shared.yml b/linux_os/guide/system/accounts/accounts-pam/accounts_password_pam_modules_in_authselect_profile/ansible/shared.yml
new file mode 100644
index 00000000000..24e06e4e17d
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/accounts_password_pam_modules_in_authselect_profile/ansible/shared.yml
@@ -0,0 +1,235 @@
+# platform = multi_platform_rhel
+# reboot = false
+# strategy = restrict
+# complexity = low
+# disruption = low
+
+{{{ ansible_check_authselect_integrity(rule_title) }}}
+
+{{{ ansible_ensure_authselect_custom_profile(rule_title) }}}
+
+- name: '{{{ rule_title }}} - Get authselect current profile'
+ ansible.builtin.command: head -1 /etc/authselect/authselect.conf
+ register: result_authselect_profile_name
+ changed_when: false
+ when:
+ - result_authselect_check_cmd is success
+
+- name: '{{{ rule_title }}} - Determine PAM profile path'
+ ansible.builtin.set_fact:
+ pam_profile_path: >-
+ {%- if result_authselect_profile_name.stdout is match('^custom/') -%}
+ /etc/authselect/{{ result_authselect_profile_name.stdout }}
+ {%- else -%}
+ /usr/share/authselect/default/{{ result_authselect_profile_name.stdout }}
+ {%- endif %}
+ when:
+ - result_authselect_check_cmd is success
+ - result_authselect_profile_name is not skipped
+
+- name: '{{{ rule_title }}} - Ensure PAM modules are present in system-auth and password-auth'
+ block:
+ - name: '{{{ rule_title }}} - Check if {{ item }} file exists'
+ ansible.builtin.stat:
+ path: "{{ pam_profile_path }}/{{ item }}"
+ register: pam_file_stat
+ loop:
+ - system-auth
+ - password-auth
+ when:
+ - pam_profile_path is defined
+
+ - name: '{{{ rule_title }}} - Set list of PAM files to process'
+ ansible.builtin.set_fact:
+ pam_files_to_process: "{{ pam_file_stat.results | default([]) | selectattr('stat.exists', 'equalto', true) | map(attribute='item') | list }}"
+
+ - name: '{{{ rule_title }}} - Check if pam_faillock.so exists in auth section of {{ item }}'
+ ansible.builtin.lineinfile:
+ path: "{{ pam_profile_path }}/{{ item }}"
+ regexp: ^\s*auth\s+\S+\s+pam_faillock\.so\s+preauth
+ state: absent
+ check_mode: true
+ changed_when: false
+ register: pam_faillock_auth_check_result
+ loop: "{{ pam_files_to_process | default([]) }}"
+ when:
+ - item is defined
+ - pam_profile_path is defined
+
+ - name: '{{{ rule_title }}} - Add pam_faillock.so preauth entry in auth section of {{ item }}'
+ ansible.builtin.lineinfile:
+ path: "{{ pam_profile_path }}/{{ item }}"
+ regexp: ^\s*auth\s+\S+\s+pam_faillock\.so\s+preauth
+ insertbefore: "^auth"
+ line: "auth required pam_faillock.so preauth"
+ state: present
+ register: pam_faillock_auth_add_result
+ loop: "{{ pam_files_to_process | default([]) }}"
+ when:
+ - item is defined
+ - pam_profile_path is defined
+ - "pam_faillock_auth_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(1) == 0"
+
+ - name: '{{{ rule_title }}} - Check if pam_faillock.so exists in account section of {{ item }}'
+ ansible.builtin.lineinfile:
+ path: "{{ pam_profile_path }}/{{ item }}"
+ regexp: ^\s*account\s+\S+\s+pam_faillock\.so
+ state: absent
+ check_mode: true
+ changed_when: false
+ register: pam_faillock_account_check_result
+ loop: "{{ pam_files_to_process | default([]) }}"
+ when:
+ - item is defined
+ - pam_profile_path is defined
+
+ - name: '{{{ rule_title }}} - Add pam_faillock.so entry in account section of {{ item }}'
+ ansible.builtin.lineinfile:
+ path: "{{ pam_profile_path }}/{{ item }}"
+ regexp: ^\s*account\s+\S+\s+pam_faillock\.so
+ insertafter: "^account"
+ line: "account required pam_faillock.so"
+ state: present
+ register: pam_faillock_account_add_result
+ loop: "{{ pam_files_to_process | default([]) }}"
+ when:
+ - item is defined
+ - pam_profile_path is defined
+ - "pam_faillock_account_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(1) == 0"
+
+ - name: '{{{ rule_title }}} - Check if pam_pwquality.so exists in {{ item }}'
+ ansible.builtin.lineinfile:
+ path: "{{ pam_profile_path }}/{{ item }}"
+ regexp: ^\s*password\s+\S+\s+pam_pwquality\.so
+ state: absent
+ check_mode: true
+ changed_when: false
+ register: pam_pwquality_check_result
+ loop: "{{ pam_files_to_process | default([]) }}"
+ when:
+ - item is defined
+ - pam_profile_path is defined
+
+ - name: '{{{ rule_title }}} - Add pam_pwquality.so entry in password section of {{ item }}'
+ ansible.builtin.lineinfile:
+ path: "{{ pam_profile_path }}/{{ item }}"
+ regexp: ^\s*password\s+\S+\s+pam_pwquality\.so
+ insertbefore: "^password"
+ line: "password requisite pam_pwquality.so"
+ state: present
+ register: pam_pwquality_add_result
+ loop: "{{ pam_files_to_process | default([]) }}"
+ when:
+ - item is defined
+ - pam_profile_path is defined
+ - "pam_pwquality_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(1) == 0"
+
+ - name: '{{{ rule_title }}} - Check if pam_pwhistory.so exists in {{ item }}'
+ ansible.builtin.lineinfile:
+ path: "{{ pam_profile_path }}/{{ item }}"
+ regexp: ^\s*password\s+\S+\s+pam_pwhistory\.so
+ state: absent
+ check_mode: true
+ changed_when: false
+ register: pam_pwhistory_check_result
+ loop: "{{ pam_files_to_process | default([]) }}"
+ when:
+ - item is defined
+ - pam_profile_path is defined
+
+ - name: '{{{ rule_title }}} - Add pam_pwhistory.so entry after pam_pwquality in {{ item }}'
+ ansible.builtin.lineinfile:
+ path: "{{ pam_profile_path }}/{{ item }}"
+ regexp: ^\s*password\s+\S+\s+pam_pwhistory\.so
+ insertafter: "^.*pam_pwquality\\.so.*"
+ line: "password requisite pam_pwhistory.so"
+ state: present
+ register: pam_pwhistory_add_result
+ loop: "{{ pam_files_to_process | default([]) }}"
+ when:
+ - item is defined
+ - pam_profile_path is defined
+ - "pam_pwhistory_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(1) == 0"
+ - "pam_pwquality_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(0) > 0"
+
+ - name: '{{{ rule_title }}} - Add pam_pwhistory.so entry at beginning of password section in {{ item }}'
+ ansible.builtin.lineinfile:
+ path: "{{ pam_profile_path }}/{{ item }}"
+ regexp: ^\s*password\s+\S+\s+pam_pwhistory\.so
+ insertbefore: "^password"
+ line: "password requisite pam_pwhistory.so"
+ state: present
+ register: pam_pwhistory_add_result
+ loop: "{{ pam_files_to_process | default([]) }}"
+ when:
+ - item is defined
+ - pam_profile_path is defined
+ - "pam_pwhistory_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(1) == 0"
+ - "pam_pwquality_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(1) == 0"
+
+ - name: '{{{ rule_title }}} - Check if pam_unix.so exists in password section of {{ item }}'
+ ansible.builtin.lineinfile:
+ path: "{{ pam_profile_path }}/{{ item }}"
+ regexp: ^\s*password\s+\S+\s+pam_unix\.so
+ state: absent
+ check_mode: true
+ changed_when: false
+ register: pam_unix_check_result
+ loop: "{{ pam_files_to_process | default([]) }}"
+ when:
+ - item is defined
+ - pam_profile_path is defined
+
+ - name: '{{{ rule_title }}} - Add pam_unix.so entry after pam_pwhistory in {{ item }}'
+ ansible.builtin.lineinfile:
+ path: "{{ pam_profile_path }}/{{ item }}"
+ regexp: ^\s*password\s+\S+\s+pam_unix\.so
+ insertafter: "^.*pam_pwhistory\\.so.*"
+ line: "password sufficient pam_unix.so"
+ state: present
+ register: pam_unix_add_result
+ loop: "{{ pam_files_to_process | default([]) }}"
+ when:
+ - item is defined
+ - pam_profile_path is defined
+ - "pam_unix_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(1) == 0"
+ - "pam_pwhistory_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(0) > 0"
+
+ - name: '{{{ rule_title }}} - Add pam_unix.so entry at end of password section in {{ item }}'
+ ansible.builtin.lineinfile:
+ path: "{{ pam_profile_path }}/{{ item }}"
+ regexp: ^\s*password\s+\S+\s+pam_unix\.so
+ insertafter: "^password.*"
+ line: "password sufficient pam_unix.so"
+ state: present
+ register: pam_unix_add_result
+ loop: "{{ pam_files_to_process | default([]) }}"
+ when:
+ - item is defined
+ - pam_profile_path is defined
+ - "pam_unix_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(1) == 0"
+ - "pam_pwhistory_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(1) == 0"
+
+ - name: '{{{ rule_title }}} - Store results for {{ item }}'
+ ansible.builtin.set_fact:
+ "pam_changes_{{ item | replace('-', '_') }}": >-
+ {{ ((pam_faillock_auth_add_result.results | selectattr('item', 'equalto', item) | map(attribute='changed') | first | default(false)) or
+ (pam_faillock_account_add_result.results | selectattr('item', 'equalto', item) | map(attribute='changed') | first | default(false)) or
+ (pam_pwquality_add_result.results | selectattr('item', 'equalto', item) | map(attribute='changed') | first | default(false)) or
+ (pam_pwhistory_add_result.results | selectattr('item', 'equalto', item) | map(attribute='changed') | first | default(false)) or
+ (pam_unix_add_result.results | selectattr('item', 'equalto', item) | map(attribute='changed') | first | default(false))) }}
+ loop: "{{ pam_files_to_process | default([]) }}"
+ when:
+ - item is defined
+ - pam_profile_path is defined
+
+ when:
+ - result_authselect_check_cmd is success
+ - pam_profile_path is defined
+
+{{{ ansible_apply_authselect_changes(rule_title=rule_title) }}}
+ when:
+ - result_authselect_check_cmd is success
+ - >-
+ (pam_changes_system_auth is defined and pam_changes_system_auth)
+ or (pam_changes_password_auth is defined and pam_changes_password_auth)
diff --git a/linux_os/guide/system/accounts/accounts-pam/accounts_password_pam_modules_in_authselect_profile/bash/shared.sh b/linux_os/guide/system/accounts/accounts-pam/accounts_password_pam_modules_in_authselect_profile/bash/shared.sh
new file mode 100644
index 00000000000..b15f498cb8a
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/accounts_password_pam_modules_in_authselect_profile/bash/shared.sh
@@ -0,0 +1,135 @@
+# platform = multi_platform_rhel
+
+{{{ bash_check_authselect_integrity() }}}
+
+{{{ bash_ensure_authselect_custom_profile() }}}
+
+# Function to add a missing PAM module to a file
+# This function handles module placement based on typical PAM stack ordering
+add_pam_module() {
+ local authselect_file="$1"
+ local module="$2"
+
+ # Check if module already exists in any group
+ if grep -Pq "^\s*\S+\s+\S+\s+$module" "$authselect_file"; then
+ return 0
+ fi
+
+ # Special handling for pam_faillock.so - needs entries in auth and account groups
+ if [ "$module" = "pam_faillock.so" ]; then
+ # Add preauth entry in auth section (at the beginning of auth section)
+ if ! grep -Pq "^\s*auth\s+\S+\s+$module" "$authselect_file"; then
+ if grep -qP "^auth" "$authselect_file"; then
+ FIRST_AUTH_LINE=$(grep -nP "^auth" "$authselect_file" | head -n 1 | cut -d: -f 1)
+ if [ ! -z "$FIRST_AUTH_LINE" ]; then
+ sed -i --follow-symlinks "${FIRST_AUTH_LINE}i auth required pam_faillock.so preauth" "$authselect_file"
+ fi
+ else
+ # If no auth section exists, create it at the beginning
+ sed -i --follow-symlinks "1i auth required pam_faillock.so preauth" "$authselect_file"
+ fi
+ fi
+ # Add entry in account section
+ if ! grep -Pq "^\s*account\s+\S+\s+$module" "$authselect_file"; then
+ if grep -qP "^account" "$authselect_file"; then
+ FIRST_ACCOUNT_LINE=$(grep -nP "^account" "$authselect_file" | head -n 1 | cut -d: -f 1)
+ if [ ! -z "$FIRST_ACCOUNT_LINE" ]; then
+ sed -i --follow-symlinks "${FIRST_ACCOUNT_LINE}a account required pam_faillock.so" "$authselect_file"
+ fi
+ else
+ # If no account section exists, add it after auth section
+ if grep -qP "^auth" "$authselect_file"; then
+ LAST_AUTH_LINE=$(grep -nP "^auth" "$authselect_file" | tail -n 1 | cut -d: -f 1)
+ if [ ! -z "$LAST_AUTH_LINE" ]; then
+ sed -i --follow-symlinks "${LAST_AUTH_LINE}a account required pam_faillock.so" "$authselect_file"
+ fi
+ else
+ echo "account required pam_faillock.so" >> "$authselect_file"
+ fi
+ fi
+ fi
+ return 0
+ fi
+
+ # Handle pam_pwquality.so - goes in password section, before other password modules
+ if [ "$module" = "pam_pwquality.so" ]; then
+ if grep -qP "^password" "$authselect_file"; then
+ FIRST_PASSWORD_LINE=$(grep -nP "^password" "$authselect_file" | head -n 1 | cut -d: -f 1)
+ if [ ! -z "$FIRST_PASSWORD_LINE" ]; then
+ sed -i --follow-symlinks "${FIRST_PASSWORD_LINE}i password requisite pam_pwquality.so" "$authselect_file"
+ fi
+ else
+ # If no password section exists, add it after account section
+ if grep -qP "^account" "$authselect_file"; then
+ LAST_ACCOUNT_LINE=$(grep -nP "^account" "$authselect_file" | tail -n 1 | cut -d: -f 1)
+ if [ ! -z "$LAST_ACCOUNT_LINE" ]; then
+ sed -i --follow-symlinks "${LAST_ACCOUNT_LINE}a password requisite pam_pwquality.so" "$authselect_file"
+ fi
+ else
+ echo "password requisite pam_pwquality.so" >> "$authselect_file"
+ fi
+ fi
+ return 0
+ fi
+
+ # Handle pam_pwhistory.so - goes in password section, after pam_pwquality
+ if [ "$module" = "pam_pwhistory.so" ]; then
+ if grep -qP "pam_pwquality\.so" "$authselect_file"; then
+ # Add after pam_pwquality
+ PWQUALITY_LINE=$(grep -nP "pam_pwquality\.so" "$authselect_file" | tail -n 1 | cut -d: -f 1)
+ if [ ! -z "$PWQUALITY_LINE" ]; then
+ sed -i --follow-symlinks "${PWQUALITY_LINE}a password requisite pam_pwhistory.so" "$authselect_file"
+ fi
+ elif grep -qP "^password" "$authselect_file"; then
+ # Add at the beginning of password section if pam_pwquality not found
+ FIRST_PASSWORD_LINE=$(grep -nP "^password" "$authselect_file" | head -n 1 | cut -d: -f 1)
+ if [ ! -z "$FIRST_PASSWORD_LINE" ]; then
+ sed -i --follow-symlinks "${FIRST_PASSWORD_LINE}i password requisite pam_pwhistory.so" "$authselect_file"
+ fi
+ else
+ echo "password requisite pam_pwhistory.so" >> "$authselect_file"
+ fi
+ return 0
+ fi
+
+ # Handle pam_unix.so - typically appears in multiple groups (auth, account, password, session)
+ # We'll add it to password group if missing, as that's most critical for this rule
+ if [ "$module" = "pam_unix.so" ]; then
+ # Check if it exists in password group
+ if ! grep -Pq "^\s*password\s+\S+\s+$module" "$authselect_file"; then
+ if grep -qP "pam_pwhistory\.so" "$authselect_file"; then
+ # Add after pam_pwhistory
+ PWHISTORY_LINE=$(grep -nP "pam_pwhistory\.so" "$authselect_file" | tail -n 1 | cut -d: -f 1)
+ if [ ! -z "$PWHISTORY_LINE" ]; then
+ sed -i --follow-symlinks "${PWHISTORY_LINE}a password sufficient pam_unix.so" "$authselect_file"
+ fi
+ elif grep -qP "^password" "$authselect_file"; then
+ # Add at the end of password section
+ LAST_PASSWORD_LINE=$(grep -nP "^password" "$authselect_file" | tail -n 1 | cut -d: -f 1)
+ if [ ! -z "$LAST_PASSWORD_LINE" ]; then
+ sed -i --follow-symlinks "${LAST_PASSWORD_LINE}a password sufficient pam_unix.so" "$authselect_file"
+ fi
+ else
+ echo "password sufficient pam_unix.so" >> "$authselect_file"
+ fi
+ fi
+ return 0
+ fi
+}
+
+# Check and ensure modules are present in both system-auth and password-auth
+pam_profile="$(head -1 /etc/authselect/authselect.conf)"
+pam_profile_path="/etc/authselect/$pam_profile"
+for authselect_file in "$pam_profile_path"/system-auth "$pam_profile_path"/password-auth; do
+ if [ ! -f "$authselect_file" ]; then
+ echo "Warning: $authselect_file not found"
+ continue
+ fi
+ for module in pam_pwquality.so pam_pwhistory.so pam_faillock.so pam_unix.so; do
+ if ! grep -Pq "^\s*\S+\s+\S+\s+$module" "$authselect_file"; then
+ add_pam_module "$authselect_file" "$module"
+ fi
+ done
+done
+
+authselect apply-changes
diff --git a/linux_os/guide/system/accounts/accounts-pam/accounts_password_pam_modules_in_authselect_profile/oval/shared.xml b/linux_os/guide/system/accounts/accounts-pam/accounts_password_pam_modules_in_authselect_profile/oval/shared.xml
new file mode 100644
index 00000000000..7cad9f2aed8
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/accounts_password_pam_modules_in_authselect_profile/oval/shared.xml
@@ -0,0 +1,84 @@
+
+
+
+
# grep -P '\b(pam_pwquality\.so|pam_pwhistory\.so|pam_faillock\.so|pam_unix\.so)\b' /etc/authselect/"$(head -1 /etc/authselect/authselect.conf)"/{system,password}-auth
+
+ The output should show entries for all four modules in both system-auth and password-auth files.
+
+fixtext: |-
+ Ensure that the active authselect profile includes all required PAM modules.
+ If using a default profile, create a custom profile and ensure it includes:
+ pam_pwquality.so, pam_pwhistory.so, pam_faillock.so, and pam_unix.so
+ in both system-auth and password-auth files.
+
+platform: package[pam]
+
+warnings:
+ - general: |-
+ If local site customizations have been made to the authselect template or files in
+ /etc/pam.d, these custom entries should be added to the newly created custom profile
+ before it's applied to the system. The order within the PAM stacks is important when
+ adding these entries.
diff --git a/linux_os/guide/system/accounts/accounts-pam/accounts_password_pam_modules_in_authselect_profile/tests/rhel_correct.pass.sh b/linux_os/guide/system/accounts/accounts-pam/accounts_password_pam_modules_in_authselect_profile/tests/rhel_correct.pass.sh
new file mode 100755
index 00000000000..5256856fc79
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/accounts_password_pam_modules_in_authselect_profile/tests/rhel_correct.pass.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+# platform = multi_platform_rhel
+
+# Create a custom authselect profile
+authselect create-profile hardening -b sssd
+CUSTOM_PROFILE="custom/hardening"
+authselect select $CUSTOM_PROFILE --force
+
+# Enable required features
+authselect enable-feature with-pwhistory
+authselect enable-feature with-faillock
+
+authselect apply-changes
diff --git a/linux_os/guide/system/accounts/accounts-pam/accounts_password_pam_modules_in_authselect_profile/tests/rhel_wrong.fail.sh b/linux_os/guide/system/accounts/accounts-pam/accounts_password_pam_modules_in_authselect_profile/tests/rhel_wrong.fail.sh
new file mode 100755
index 00000000000..0ef28bd1bf7
--- /dev/null
+++ b/linux_os/guide/system/accounts/accounts-pam/accounts_password_pam_modules_in_authselect_profile/tests/rhel_wrong.fail.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+# platform = multi_platform_rhel
+
+# Create a custom authselect profile
+authselect create-profile hardening -b sssd
+CUSTOM_PROFILE="custom/hardening"
+authselect select $CUSTOM_PROFILE --force
+
+pam_profile_path="/etc/authselect/$CUSTOM_PROFILE"
+sed -i '/pam_faillock\.so/d' "$pam_profile_path"/password-auth
+sed -i '/pam_faillock\.so/d' "$pam_profile_path"/system-auth
+authselect apply-changes
diff --git a/products/rhel10/controls/cis_rhel10.yml b/products/rhel10/controls/cis_rhel10.yml
index 76c4397306d..8269196f299 100644
--- a/products/rhel10/controls/cis_rhel10.yml
+++ b/products/rhel10/controls/cis_rhel10.yml
@@ -1884,15 +1884,24 @@ controls:
levels:
- l1_server
- l1_workstation
- status: partial
+ status: automated
notes: |-
- This requirement is hard to be automated without any specific requirement. The policy even
- states that provided commands are examples, other custom settings might be in place and the
- settings might be different depending on site policies. The other rules will already make
- sure there is a correct autheselect profile regardless of the existing settings. It is
- necessary to better discuss with CIS Community.
+ This rule verifies that the active authselect profile includes the required PAM modules:
+ pam_pwquality.so, pam_pwhistory.so, pam_faillock.so, and pam_unix.so in both system-auth
+ and password-auth files. The rule checks the authselect profile source files directly,
+ not the symlinked files in /etc/pam.d/. Other rules ensure these modules are properly
+ configured with correct options.
+ rules:
+ - accounts_password_pam_modules_in_authselect_profile
related_rules:
- - no_empty_passwords
+ - enable_authselect
+ - account_password_pam_faillock_password_auth
+ - account_password_pam_faillock_system_auth
+ - accounts_password_pam_pwquality_password_auth
+ - accounts_password_pam_pwquality_system_auth
+ - accounts_password_pam_pwhistory_remember_password_auth
+ - accounts_password_pam_pwhistory_remember_system_auth
+ - accounts_password_pam_unix_enabled
- id: 5.3.1.2
title: Ensure pam_faillock module is enabled (Automated)
diff --git a/products/rhel8/controls/cis_rhel8.yml b/products/rhel8/controls/cis_rhel8.yml
index cbc90ab6597..cbe5d4d6454 100644
--- a/products/rhel8/controls/cis_rhel8.yml
+++ b/products/rhel8/controls/cis_rhel8.yml
@@ -1977,15 +1977,24 @@ controls:
levels:
- l1_server
- l1_workstation
- status: partial
+ status: automated
notes: |-
- This requirement is hard to be automated without any specific requirement. The policy even
- states that provided commands are examples, other custom settings might be in place and the
- settings might be different depending on site policies. The other rules will already make
- sure there is a correct autheselect profile regardless of the existing settings. It is
- necessary to better discuss with CIS Community.
+ This rule verifies that the active authselect profile includes the required PAM modules:
+ pam_pwquality.so, pam_pwhistory.so, pam_faillock.so, and pam_unix.so in both system-auth
+ and password-auth files. The rule checks the authselect profile source files directly,
+ not the symlinked files in /etc/pam.d/. Other rules ensure these modules are properly
+ configured with correct options.
+ rules:
+ - accounts_password_pam_modules_in_authselect_profile
related_rules:
- - no_empty_passwords
+ - enable_authselect
+ - account_password_pam_faillock_password_auth
+ - account_password_pam_faillock_system_auth
+ - accounts_password_pam_pwquality_password_auth
+ - accounts_password_pam_pwquality_system_auth
+ - accounts_password_pam_pwhistory_remember_password_auth
+ - accounts_password_pam_pwhistory_remember_system_auth
+ - accounts_password_pam_unix_enabled
- id: 5.3.2.2
title: Ensure pam_faillock module is enabled (Automated)
diff --git a/products/rhel9/controls/cis_rhel9.yml b/products/rhel9/controls/cis_rhel9.yml
index 8cc174b6d3e..442e8822ca5 100644
--- a/products/rhel9/controls/cis_rhel9.yml
+++ b/products/rhel9/controls/cis_rhel9.yml
@@ -1808,15 +1808,24 @@ controls:
levels:
- l1_server
- l1_workstation
- status: partial
+ status: automated
notes: |-
- This requirement is hard to be automated without any specific requirement. The policy even
- states that provided commands are examples, other custom settings might be in place and the
- settings might be different depending on site policies. The other rules will already make
- sure there is a correct autheselect profile regardless of the existing settings. It is
- necessary to better discuss with CIS Community.
+ This rule verifies that the active authselect profile includes the required PAM modules:
+ pam_pwquality.so, pam_pwhistory.so, pam_faillock.so, and pam_unix.so in both system-auth
+ and password-auth files. The rule checks the authselect profile source files directly,
+ not the symlinked files in /etc/pam.d/. Other rules ensure these modules are properly
+ configured with correct options.
+ rules:
+ - accounts_password_pam_modules_in_authselect_profile
related_rules:
- - no_empty_passwords
+ - enable_authselect
+ - account_password_pam_faillock_password_auth
+ - account_password_pam_faillock_system_auth
+ - accounts_password_pam_pwquality_password_auth
+ - accounts_password_pam_pwquality_system_auth
+ - accounts_password_pam_pwhistory_remember_password_auth
+ - accounts_password_pam_pwhistory_remember_system_auth
+ - accounts_password_pam_unix_enabled
- id: 5.3.2.2
title: Ensure pam_faillock module is enabled (Automated)
diff --git a/shared/references/cce-redhat-avail.txt b/shared/references/cce-redhat-avail.txt
index 31e83090d09..f1dff1792b6 100644
--- a/shared/references/cce-redhat-avail.txt
+++ b/shared/references/cce-redhat-avail.txt
@@ -2210,7 +2210,6 @@ CCE-90458-1
CCE-90459-9
CCE-90460-7
CCE-90462-3
-CCE-90464-9
CCE-90467-2
CCE-90468-0
CCE-90470-6
@@ -2348,8 +2347,6 @@ CCE-90707-1
CCE-90710-5
CCE-90711-3
CCE-90715-4
-CCE-90716-2
-CCE-90719-6
CCE-90720-4
CCE-90721-2
CCE-90722-0
diff --git a/tests/data/profile_stability/rhel10/cis.profile b/tests/data/profile_stability/rhel10/cis.profile
index 38893f5771e..acb21b876b6 100644
--- a/tests/data/profile_stability/rhel10/cis.profile
+++ b/tests/data/profile_stability/rhel10/cis.profile
@@ -15,6 +15,7 @@ accounts_password_pam_maxrepeat
accounts_password_pam_maxsequence
accounts_password_pam_minclass
accounts_password_pam_minlen
+accounts_password_pam_modules_in_authselect_profile
accounts_password_pam_pwhistory_enforce_for_root
accounts_password_pam_pwhistory_remember_password_auth
accounts_password_pam_pwhistory_remember_system_auth
diff --git a/tests/data/profile_stability/rhel10/cis_server_l1.profile b/tests/data/profile_stability/rhel10/cis_server_l1.profile
index a887761b3cf..1a8d4a41324 100644
--- a/tests/data/profile_stability/rhel10/cis_server_l1.profile
+++ b/tests/data/profile_stability/rhel10/cis_server_l1.profile
@@ -14,6 +14,7 @@ accounts_password_pam_maxrepeat
accounts_password_pam_maxsequence
accounts_password_pam_minclass
accounts_password_pam_minlen
+accounts_password_pam_modules_in_authselect_profile
accounts_password_pam_pwhistory_enforce_for_root
accounts_password_pam_pwhistory_remember_password_auth
accounts_password_pam_pwhistory_remember_system_auth
diff --git a/tests/data/profile_stability/rhel10/cis_workstation_l1.profile b/tests/data/profile_stability/rhel10/cis_workstation_l1.profile
index c5b713130b4..63186a34c25 100644
--- a/tests/data/profile_stability/rhel10/cis_workstation_l1.profile
+++ b/tests/data/profile_stability/rhel10/cis_workstation_l1.profile
@@ -14,6 +14,7 @@ accounts_password_pam_maxrepeat
accounts_password_pam_maxsequence
accounts_password_pam_minclass
accounts_password_pam_minlen
+accounts_password_pam_modules_in_authselect_profile
accounts_password_pam_pwhistory_enforce_for_root
accounts_password_pam_pwhistory_remember_password_auth
accounts_password_pam_pwhistory_remember_system_auth
diff --git a/tests/data/profile_stability/rhel10/cis_workstation_l2.profile b/tests/data/profile_stability/rhel10/cis_workstation_l2.profile
index ec48c096f6e..221ffac1755 100644
--- a/tests/data/profile_stability/rhel10/cis_workstation_l2.profile
+++ b/tests/data/profile_stability/rhel10/cis_workstation_l2.profile
@@ -15,6 +15,7 @@ accounts_password_pam_maxrepeat
accounts_password_pam_maxsequence
accounts_password_pam_minclass
accounts_password_pam_minlen
+accounts_password_pam_modules_in_authselect_profile
accounts_password_pam_pwhistory_enforce_for_root
accounts_password_pam_pwhistory_remember_password_auth
accounts_password_pam_pwhistory_remember_system_auth
diff --git a/tests/data/profile_stability/rhel8/cis.profile b/tests/data/profile_stability/rhel8/cis.profile
index 4490d3742f2..40ef7718866 100644
--- a/tests/data/profile_stability/rhel8/cis.profile
+++ b/tests/data/profile_stability/rhel8/cis.profile
@@ -13,6 +13,7 @@ accounts_password_pam_enforce_root
accounts_password_pam_maxrepeat
accounts_password_pam_maxsequence
accounts_password_pam_minlen
+accounts_password_pam_modules_in_authselect_profile
accounts_password_pam_pwhistory_enforce_for_root
accounts_password_pam_pwhistory_remember_password_auth
accounts_password_pam_pwhistory_remember_system_auth
diff --git a/tests/data/profile_stability/rhel8/cis_server_l1.profile b/tests/data/profile_stability/rhel8/cis_server_l1.profile
index 3fe6d56bf92..c186914d253 100644
--- a/tests/data/profile_stability/rhel8/cis_server_l1.profile
+++ b/tests/data/profile_stability/rhel8/cis_server_l1.profile
@@ -13,6 +13,7 @@ accounts_password_pam_enforce_root
accounts_password_pam_maxrepeat
accounts_password_pam_maxsequence
accounts_password_pam_minlen
+accounts_password_pam_modules_in_authselect_profile
accounts_password_pam_pwhistory_enforce_for_root
accounts_password_pam_pwhistory_remember_password_auth
accounts_password_pam_pwhistory_remember_system_auth
diff --git a/tests/data/profile_stability/rhel8/cis_workstation_l1.profile b/tests/data/profile_stability/rhel8/cis_workstation_l1.profile
index 7abde497a26..f53d2e0dd71 100644
--- a/tests/data/profile_stability/rhel8/cis_workstation_l1.profile
+++ b/tests/data/profile_stability/rhel8/cis_workstation_l1.profile
@@ -13,6 +13,7 @@ accounts_password_pam_enforce_root
accounts_password_pam_maxrepeat
accounts_password_pam_maxsequence
accounts_password_pam_minlen
+accounts_password_pam_modules_in_authselect_profile
accounts_password_pam_pwhistory_enforce_for_root
accounts_password_pam_pwhistory_remember_password_auth
accounts_password_pam_pwhistory_remember_system_auth
diff --git a/tests/data/profile_stability/rhel8/cis_workstation_l2.profile b/tests/data/profile_stability/rhel8/cis_workstation_l2.profile
index 42619443f87..f43c7d9ea9b 100644
--- a/tests/data/profile_stability/rhel8/cis_workstation_l2.profile
+++ b/tests/data/profile_stability/rhel8/cis_workstation_l2.profile
@@ -13,6 +13,7 @@ accounts_password_pam_enforce_root
accounts_password_pam_maxrepeat
accounts_password_pam_maxsequence
accounts_password_pam_minlen
+accounts_password_pam_modules_in_authselect_profile
accounts_password_pam_pwhistory_enforce_for_root
accounts_password_pam_pwhistory_remember_password_auth
accounts_password_pam_pwhistory_remember_system_auth
diff --git a/tests/data/profile_stability/rhel9/cis.profile b/tests/data/profile_stability/rhel9/cis.profile
index e0b98624241..cb9b054b895 100644
--- a/tests/data/profile_stability/rhel9/cis.profile
+++ b/tests/data/profile_stability/rhel9/cis.profile
@@ -15,6 +15,7 @@ accounts_password_pam_maxrepeat
accounts_password_pam_maxsequence
accounts_password_pam_minclass
accounts_password_pam_minlen
+accounts_password_pam_modules_in_authselect_profile
accounts_password_pam_pwhistory_enforce_for_root
accounts_password_pam_pwhistory_remember_password_auth
accounts_password_pam_pwhistory_remember_system_auth
diff --git a/tests/data/profile_stability/rhel9/cis_server_l1.profile b/tests/data/profile_stability/rhel9/cis_server_l1.profile
index dd0277ea8b8..129cece2df2 100644
--- a/tests/data/profile_stability/rhel9/cis_server_l1.profile
+++ b/tests/data/profile_stability/rhel9/cis_server_l1.profile
@@ -14,6 +14,7 @@ accounts_password_pam_maxrepeat
accounts_password_pam_maxsequence
accounts_password_pam_minclass
accounts_password_pam_minlen
+accounts_password_pam_modules_in_authselect_profile
accounts_password_pam_pwhistory_enforce_for_root
accounts_password_pam_pwhistory_remember_password_auth
accounts_password_pam_pwhistory_remember_system_auth
diff --git a/tests/data/profile_stability/rhel9/cis_workstation_l1.profile b/tests/data/profile_stability/rhel9/cis_workstation_l1.profile
index 6cc11e35b8c..0e0e651c590 100644
--- a/tests/data/profile_stability/rhel9/cis_workstation_l1.profile
+++ b/tests/data/profile_stability/rhel9/cis_workstation_l1.profile
@@ -14,6 +14,7 @@ accounts_password_pam_maxrepeat
accounts_password_pam_maxsequence
accounts_password_pam_minclass
accounts_password_pam_minlen
+accounts_password_pam_modules_in_authselect_profile
accounts_password_pam_pwhistory_enforce_for_root
accounts_password_pam_pwhistory_remember_password_auth
accounts_password_pam_pwhistory_remember_system_auth
diff --git a/tests/data/profile_stability/rhel9/cis_workstation_l2.profile b/tests/data/profile_stability/rhel9/cis_workstation_l2.profile
index 2ca88460a01..19c563a3e7f 100644
--- a/tests/data/profile_stability/rhel9/cis_workstation_l2.profile
+++ b/tests/data/profile_stability/rhel9/cis_workstation_l2.profile
@@ -15,6 +15,7 @@ accounts_password_pam_maxrepeat
accounts_password_pam_maxsequence
accounts_password_pam_minclass
accounts_password_pam_minlen
+accounts_password_pam_modules_in_authselect_profile
accounts_password_pam_pwhistory_enforce_for_root
accounts_password_pam_pwhistory_remember_password_auth
accounts_password_pam_pwhistory_remember_system_auth