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 @@ + + + + + + {{{ oval_metadata("Ensure active authselect profile includes pam modules", rule_title=rule_title) }}} + + + + + + + + + + + + + + + + + + + + + + + + + /etc/authselect/authselect.conf + ^(.+)$ + 1 + + + + + + + + + + +{{%- macro oval_pam_module_check(module_name, file_name) -%}} + + + + /etc/authselect/ + + /{{{ file_name }}} + + + + + + + + + + ^\s*\S+\s+\S+\s+pam_{{{ module_name }}}\.so + 1 + +{{%- endmacro -%}} + +{{{ oval_pam_module_check("pwquality", "system-auth") }}} +{{{ oval_pam_module_check("pwhistory", "system-auth") }}} +{{{ oval_pam_module_check("faillock", "system-auth") }}} +{{{ oval_pam_module_check("unix", "system-auth") }}} +{{{ oval_pam_module_check("pwquality", "password-auth") }}} +{{{ oval_pam_module_check("pwhistory", "password-auth") }}} +{{{ oval_pam_module_check("faillock", "password-auth") }}} +{{{ oval_pam_module_check("unix", "password-auth") }}} + + diff --git a/linux_os/guide/system/accounts/accounts-pam/accounts_password_pam_modules_in_authselect_profile/rule.yml b/linux_os/guide/system/accounts/accounts-pam/accounts_password_pam_modules_in_authselect_profile/rule.yml new file mode 100644 index 00000000000..75fc04f6236 --- /dev/null +++ b/linux_os/guide/system/accounts/accounts-pam/accounts_password_pam_modules_in_authselect_profile/rule.yml @@ -0,0 +1,49 @@ +documentation_complete: true + +title: 'Ensure Active Authselect Profile Includes PAM Modules' + +description: |- + The active authselect profile must include 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. + + A custom authselect profile can be created by copying and customizing one of the default profiles. + The default profiles include: local, sssd, and winbind. These profiles can be customized + to follow site specific requirements. + +rationale: |- + A custom profile is required to customize many of the PAM options. + Modifications made to a default profile may be overwritten during an update. + When you deploy a profile, the profile is applied to every user logging into the given host. + +severity: medium + +identifiers: + cce@rhel8: CCE-90716-2 + cce@rhel9: CCE-90719-6 + cce@rhel10: CCE-90464-9 + +ocil_clause: 'the active authselect profile does not include all required PAM modules' + +ocil: |- + Run the following command to verify the active authselect profile includes lines for the + pwquality, pwhistory, faillock, and unix modules: + +
# 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