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.
Shell script
The following script can be run on the host to remediate the issue.
#!/bin/bash
# Remediation is applicable only in certain platforms
if rpm --quiet -q pam; then
if ! authselect check; then
echo "
authselect integrity check failed. Remediation aborted!
This remediation could not be applied because an authselect profile was not selected or the selected profile is not intact.
It is not recommended to manually edit the PAM files when authselect tool is available.
In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
exit 1
fi
CURRENT_PROFILE=$(authselect current -r | awk '{ print $1 }')
# 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 }')
# The "local" profile does not contain essential security features required by multiple Benchmarks.
# If currently used, it is replaced by "sssd", which is the best option in this case.
if [[ $CURRENT_PROFILE == local ]]; then
CURRENT_PROFILE="sssd"
fi
authselect create-profile hardening -b $CURRENT_PROFILE
CURRENT_PROFILE="custom/hardening"
authselect apply-changes -b --backup=before-hardening-custom-profile
authselect select $CURRENT_PROFILE
for feature in $ENABLED_FEATURES; do
authselect enable-feature $feature;
done
authselect apply-changes -b --backup=after-hardening-custom-profile
fi
# 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
else
>&2 echo 'Remediation is not applicable, nothing was done'
fi
Ansible playbook
The following playbook can be run with Ansible to remediate the issue.
- name: Gather the package facts
package_facts:
manager: auto
tags:
- CCE-90716-2
- accounts_password_pam_modules_in_authselect_profile
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure Active Authselect Profile Includes PAM Modules - Check integrity of
authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
when: '"pam" in ansible_facts.packages'
tags:
- CCE-90716-2
- accounts_password_pam_modules_in_authselect_profile
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure Active Authselect Profile Includes PAM Modules - Informative message
based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was not
selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool is
available.
- In cases where the default authselect profile does not cover a specific demand,
a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
when: '"pam" in ansible_facts.packages'
tags:
- CCE-90716-2
- accounts_password_pam_modules_in_authselect_profile
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure Active Authselect Profile Includes PAM Modules - Get authselect current
profile
ansible.builtin.shell:
cmd: authselect current -r | awk '{ print $1 }'
register: result_authselect_profile
changed_when: false
when:
- '"pam" in ansible_facts.packages'
- result_authselect_check_cmd is success
tags:
- CCE-90716-2
- accounts_password_pam_modules_in_authselect_profile
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure Active Authselect Profile Includes PAM Modules - Define the current
authselect profile as a local fact
ansible.builtin.set_fact:
authselect_current_profile: '{{ result_authselect_profile.stdout }}'
authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
when:
- '"pam" in ansible_facts.packages'
- result_authselect_profile is not skipped
- result_authselect_profile.stdout is match("custom/")
tags:
- CCE-90716-2
- accounts_password_pam_modules_in_authselect_profile
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure Active Authselect Profile Includes PAM Modules - Define the new authselect
custom profile as a local fact
ansible.builtin.set_fact:
authselect_current_profile: '{{ result_authselect_profile.stdout }}'
authselect_custom_profile: custom/hardening
when:
- '"pam" in ansible_facts.packages'
- result_authselect_profile is not skipped
- result_authselect_profile.stdout is not match("custom/")
tags:
- CCE-90716-2
- accounts_password_pam_modules_in_authselect_profile
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure Active Authselect Profile Includes PAM Modules - 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
check_mode: false
when:
- '"pam" in ansible_facts.packages'
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
tags:
- CCE-90716-2
- accounts_password_pam_modules_in_authselect_profile
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure Active Authselect Profile Includes PAM Modules - Check if any custom
profile with the same name was already created
ansible.builtin.stat:
path: /etc/authselect/{{ authselect_custom_profile }}
register: result_authselect_custom_profile_present
changed_when: false
when:
- '"pam" in ansible_facts.packages'
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
tags:
- CCE-90716-2
- accounts_password_pam_modules_in_authselect_profile
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure Active Authselect Profile Includes PAM Modules - Create an authselect
custom profile based on the current profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b {{ authselect_current_profile }}
when:
- '"pam" in ansible_facts.packages'
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
tags:
- CCE-90716-2
- accounts_password_pam_modules_in_authselect_profile
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure Active Authselect Profile Includes PAM Modules - Create an authselect
custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- '"pam" in ansible_facts.packages'
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
tags:
- CCE-90716-2
- accounts_password_pam_modules_in_authselect_profile
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure Active Authselect Profile Includes PAM Modules - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
when:
- '"pam" in ansible_facts.packages'
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- authselect_custom_profile is not match(authselect_current_profile)
tags:
- CCE-90716-2
- accounts_password_pam_modules_in_authselect_profile
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure Active Authselect Profile Includes PAM Modules - Ensure the authselect
custom profile is selected
ansible.builtin.command:
cmd: authselect select {{ authselect_custom_profile }}
register: result_pam_authselect_select_profile
when:
- '"pam" in ansible_facts.packages'
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- authselect_custom_profile is not match(authselect_current_profile)
tags:
- CCE-90716-2
- accounts_password_pam_modules_in_authselect_profile
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure Active Authselect Profile Includes PAM Modules - Restore the authselect
features in the custom profile
ansible.builtin.command:
cmd: authselect enable-feature {{ item }}
loop: '{{ result_authselect_features.stdout_lines }}'
register: result_pam_authselect_restore_features
when:
- '"pam" in ansible_facts.packages'
- result_authselect_profile is not skipped
- result_authselect_features is not skipped
- result_pam_authselect_select_profile is not skipped
tags:
- CCE-90716-2
- accounts_password_pam_modules_in_authselect_profile
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure Active Authselect Profile Includes PAM Modules - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
when:
- '"pam" in ansible_facts.packages'
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- result_pam_authselect_restore_features is not skipped
tags:
- CCE-90716-2
- accounts_password_pam_modules_in_authselect_profile
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure Active Authselect Profile Includes PAM Modules - Get authselect current
profile
ansible.builtin.command: head -1 /etc/authselect/authselect.conf
register: result_authselect_profile_name
changed_when: false
when:
- '"pam" in ansible_facts.packages'
- result_authselect_check_cmd is success
tags:
- CCE-90716-2
- accounts_password_pam_modules_in_authselect_profile
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure Active Authselect Profile Includes PAM Modules - 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:
- '"pam" in ansible_facts.packages'
- result_authselect_check_cmd is success
- result_authselect_profile_name is not skipped
tags:
- CCE-90716-2
- accounts_password_pam_modules_in_authselect_profile
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure Active Authselect Profile Includes PAM Modules - Ensure PAM modules
are present in system-auth and password-auth
block:
- name: Ensure Active Authselect Profile Includes PAM Modules - 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: Ensure Active Authselect Profile Includes PAM Modules - 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: Ensure Active Authselect Profile Includes PAM Modules - 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: Ensure Active Authselect Profile Includes PAM Modules - 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: Ensure Active Authselect Profile Includes PAM Modules - 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: Ensure Active Authselect Profile Includes PAM Modules - 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: Ensure Active Authselect Profile Includes PAM Modules - 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: Ensure Active Authselect Profile Includes PAM Modules - 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: Ensure Active Authselect Profile Includes PAM Modules - 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: Ensure Active Authselect Profile Includes PAM Modules - 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: Ensure Active Authselect Profile Includes PAM Modules - 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: Ensure Active Authselect Profile Includes PAM Modules - 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: Ensure Active Authselect Profile Includes PAM Modules - 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: Ensure Active Authselect Profile Includes PAM Modules - 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: Ensure Active Authselect Profile Includes PAM Modules - 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:
- '"pam" in ansible_facts.packages'
- result_authselect_check_cmd is success
- pam_profile_path is defined
tags:
- CCE-90716-2
- accounts_password_pam_modules_in_authselect_profile
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure Active Authselect Profile Includes PAM Modules - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b
when:
- '"pam" in ansible_facts.packages'
- 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)
tags:
- CCE-90716-2
- accounts_password_pam_modules_in_authselect_profile
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
Warning
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.