-
Notifications
You must be signed in to change notification settings - Fork 685
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update rules related to pam_pwhistory module to consider pwhistory.conf file #9994
Update rules related to pam_pwhistory module to consider pwhistory.conf file #9994
Conversation
Relatively recent it was introduced the /etc/security/pwhistory.conf file in order to make the PAM pam_pwhistory.so module easier to be configured. Using this file also avoids the necessity to edit PAM files directly and consequently mitigate PAM errors. Therefore, its a good practice to use this file and more systems should be configured using this approach. Now the OVAL is capable to properly assess these cases. accounts_password_pam_pwhistory_remember_system_auth rule
This datastream diff is auto generated by the check Click here to see the trimmed diffbash remediation for rule 'xccdf_org.ssgproject.content_rule_display_login_attempts' differs.
--- xccdf_org.ssgproject.content_rule_display_login_attempts
+++ xccdf_org.ssgproject.content_rule_display_login_attempts
@@ -4,6 +4,7 @@
if [ -e "/etc/pam.d/postlogin" ] ; then
PAM_FILE_PATH="/etc/pam.d/postlogin"
if [ -f /usr/bin/authselect ]; then
+
if ! authselect check; then
echo "
authselect integrity check failed. Remediation aborted!
@@ -12,6 +13,7 @@
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
@@ -29,7 +31,7 @@
fi
PAM_FILE_NAME=$(basename "/etc/pam.d/postlogin")
PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
-
+
authselect apply-changes -b
fi
if ! grep -qP '^\s*session\s+'"required"'\s+pam_lastlog.so\s*.*' "$PAM_FILE_PATH"; then
@@ -55,14 +57,16 @@
if [ -e "/etc/pam.d/postlogin" ] ; then
PAM_FILE_PATH="/etc/pam.d/postlogin"
if [ -f /usr/bin/authselect ]; 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
+ 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
@@ -80,7 +84,7 @@
fi
PAM_FILE_NAME=$(basename "/etc/pam.d/postlogin")
PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
-
+
authselect apply-changes -b
fi
ansible remediation for rule 'xccdf_org.ssgproject.content_rule_display_login_attempts' differs.
--- xccdf_org.ssgproject.content_rule_display_login_attempts
+++ xccdf_org.ssgproject.content_rule_display_login_attempts
@@ -45,12 +45,13 @@
pam_file_path: /etc/pam.d/postlogin
- name: Ensure PAM Displays Last Logon/Access Notification - Check if system relies
- on authselect
+ on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- - name: Ensure PAM Displays Last Logon/Access Notification - Remediate using authselect
+ - name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect custom
+ profile is used if authselect is present
block:
- name: Ensure PAM Displays Last Logon/Access Notification - Check integrity of
@@ -314,12 +315,13 @@
pam_file_path: /etc/pam.d/postlogin
- name: Ensure PAM Displays Last Logon/Access Notification - Check if system relies
- on authselect
+ on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- - name: Ensure PAM Displays Last Logon/Access Notification - Remediate using authselect
+ - name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect custom
+ profile is used if authselect is present
block:
- name: Ensure PAM Displays Last Logon/Access Notification - Check integrity of
bash remediation for rule 'xccdf_org.ssgproject.content_rule_account_passwords_pam_faillock_audit' differs.
--- xccdf_org.ssgproject.content_rule_account_passwords_pam_faillock_audit
+++ xccdf_org.ssgproject.content_rule_account_passwords_pam_faillock_audit
@@ -39,14 +39,16 @@
if [ -e "$pam_file" ] ; then
PAM_FILE_PATH="$pam_file"
if [ -f /usr/bin/authselect ]; 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
+ 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
@@ -64,7 +66,7 @@
fi
PAM_FILE_NAME=$(basename "$pam_file")
PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
-
+
authselect apply-changes -b
fi
ansible remediation for rule 'xccdf_org.ssgproject.content_rule_account_passwords_pam_faillock_audit' differs.
--- xccdf_org.ssgproject.content_rule_account_passwords_pam_faillock_audit
+++ xccdf_org.ssgproject.content_rule_account_passwords_pam_faillock_audit
@@ -187,11 +187,13 @@
pam_file_path: /etc/pam.d/system-auth
- name: Account Lockouts Must Be Logged - Check if system relies on authselect
+ tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- - name: Account Lockouts Must Be Logged - Remediate using authselect
+ - name: Account Lockouts Must Be Logged - Ensure authselect custom profile is
+ used if authselect is present
block:
- name: Account Lockouts Must Be Logged - Check integrity of authselect current
@@ -352,11 +354,13 @@
pam_file_path: /etc/pam.d/password-auth
- name: Account Lockouts Must Be Logged - Check if system relies on authselect
+ tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- - name: Account Lockouts Must Be Logged - Remediate using authselect
+ - name: Account Lockouts Must Be Logged - Ensure authselect custom profile is
+ used if authselect is present
block:
- name: Account Lockouts Must Be Logged - Check integrity of authselect current
New content has different text for rule 'xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_password_auth'.
--- xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_password_auth
+++ xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_password_auth
@@ -6,11 +6,19 @@
Do not allow users to reuse recent passwords. This can be accomplished by using the
remember option for the pam_pwhistory PAM module.
-In the file /etc/pam.d/password-auth, make sure the parameter
-remember is present and it has a value equal to or greater than
-'xccdf_org.ssgproject.content_value_var_password_pam_remember'. For example:
-password control_flag pam_pwhistory.so ...existing_options... remember='xccdf_org.ssgproject.content_value_var_password_pam_remember' use_authtok
-control_flag should be one of the next values: 'xccdf_org.ssgproject.content_value_var_password_pam_remember_control_flag'
+
+On systems with newer versions of authselect, the pam_pwhistory PAM module
+can be enabled via authselect feature:
+authselect enable-feature with-pwhistory
+
+Otherwise, it should be enabled using an authselect custom profile.
+
+Newer systems also have the /etc/security/pwhistory.conf file for setting
+pam_pwhistory module options. This file should be used whenever available.
+Otherwise, the pam_pwhistory module options can be set in PAM files.
+
+The value for remember option must be equal or greater than
+'xccdf_org.ssgproject.content_value_var_password_pam_remember'
[warning]:
If the system relies on authselect tool to manage PAM settings, the remediation
@@ -19,6 +27,11 @@
aborted in order to preserve intentional changes. In this case, an informative message will
be shown in the remediation report.
+[warning]:
+Newer versions of authselect contain an authselect feature to easily and properly
+enable pam_pwhistory.so module. If this feature is not yet available in your
+system, an authselect custom profile must be used to avoid integrity issues in PAM files.
+
[reference]:
1
@@ -197,7 +210,8 @@
SV-230368r810414_rule
[rationale]:
-Preventing re-use of previous passwords helps ensure that a compromised password is not re-used by a user.
+Preventing re-use of previous passwords helps ensure that a compromised password is not
+re-used by a user.
[ident]:
CCE-83478-8
OVAL for rule 'xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_password_auth' differs.
--- oval:ssg-accounts_password_pam_pwhistory_remember_password_auth:def:1
+++ oval:ssg-accounts_password_pam_pwhistory_remember_password_auth:def:1
@@ -1,2 +1,9 @@
criteria AND
criterion oval:ssg-test_accounts_password_pam_pwhistory_remember_password_auth:tst:1
+criteria OR
+criteria AND
+criterion oval:ssg-test_accounts_password_pam_pwhistory_remember_password_auth_pamd:tst:1
+criterion oval:ssg-test_accounts_password_pam_pwhistory_remember_password_auth_no_pwhistory_conf:tst:1
+criteria AND
+criterion oval:ssg-test_accounts_password_pam_pwhistory_remember_password_auth_no_pamd:tst:1
+criterion oval:ssg-test_accounts_password_pam_pwhistory_remember_password_auth_pwhistory_conf:tst:1
OCIL for rule 'xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_password_auth' differs.
--- ocil:ssg-accounts_password_pam_pwhistory_remember_password_auth_ocil:questionnaire:1
+++ ocil:ssg-accounts_password_pam_pwhistory_remember_password_auth_ocil:questionnaire:1
@@ -1,9 +1,20 @@
-Verify Red Hat Enterprise Linux 8 is configured in the password-auth file to prohibit password reuse
-for a minimum of generations with the following command:
+Verify Red Hat Enterprise Linux 8 use the "pam_pwhistory.so" module in the /etc/pam.d/password-auth file
+and is configured to prohibit password reuse for a minimum of
+generations.
-$ grep -i remember /etc/pam.d/password-auth
-password pam_pwhistory.so use_authtok remember= retry=3
- Is it the case that the line containing "pam_pwhistory.so" does not have the "remember" module argument set,
-is commented out, or the value of the "remember" module argument is set to less than
-"<sub idref="var_password_pam_remember" />"?
+Verify the "/etc/pam.d/password-auth" file with the following command:
+
+$ grep pam_pwhistory.so /etc/pam.d/password-auth
+password pam_pwhistory.so use_authtok remember=
+
+
+Verify the "/etc/security/pwhistory.conf" file using the following command:
+
+$ grep remember /etc/security/pwhistory.conf
+remember =
+
+The pam_pwhistory.so "remember" option must be configured only in one file.
+ Is it the case that the pam_pwhistory.so module is not used, the "remember" module option is not set in
+/etc/pam.d/password-auth or in /etc/security/pwhistory.conf, or is set in both files, or is set
+with a value less than "<sub idref="var_password_pam_remember" />"?
bash remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_password_auth' differs.
--- xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_password_auth
+++ xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_password_auth
@@ -7,9 +7,8 @@
var_password_pam_remember_control_flag="$(echo $var_password_pam_remember_control_flag | cut -d \, -f 1)"
-if [ -e "/etc/pam.d/password-auth" ] ; then
- PAM_FILE_PATH="/etc/pam.d/password-auth"
- if [ -f /usr/bin/authselect ]; then
+if [ -f /usr/bin/authselect ]; then
+ if authselect list-features minimal | grep -q with-pwhistory; then
if ! authselect check; then
echo "
authselect integrity check failed. Remediation aborted!
@@ -18,6 +17,20 @@
In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
exit 1
fi
+ authselect enable-feature with-pwhistory
+
+ authselect apply-changes -b
+ else
+
+ 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
@@ -35,35 +48,135 @@
fi
PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth")
PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
-
+
authselect apply-changes -b
- fi
- if ! grep -qP '^\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so\s*.*' "$PAM_FILE_PATH"; then
+ if ! grep -qP '^\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so\s*.*' "$PAM_FILE_PATH"; then
# Line matching group + control + module was not found. Check group + module.
if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then
# The control is updated only if one single line matches.
sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"$var_password_pam_remember_control_flag"' \2/' "$PAM_FILE_PATH"
else
- LAST_MATCH_LINE=$(grep -nP "^password.*requisite.*pam_pwquality\.so" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1)
- if [ ! -z $LAST_MATCH_LINE ]; then
- sed -i --follow-symlinks $LAST_MATCH_LINE' a password '"$var_password_pam_remember_control_flag"' pam_pwhistory.so' "$PAM_FILE_PATH"
- else
- echo 'password '"$var_password_pam_remember_control_flag"' pam_pwhistory.so' >> "$PAM_FILE_PATH"
- fi
+ echo 'password '"$var_password_pam_remember_control_flag"' pam_pwhistory.so' >> "$PAM_FILE_PATH"
fi
fi
- # Check the option
- if ! grep -qP '^\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so\s*.*\sremember\b' "$PAM_FILE_PATH"; then
- sed -i -E --follow-symlinks '/\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so.*/ s/$/ remember='"$var_password_pam_remember"'/' "$PAM_FILE_PATH"
+ fi
+else
+ if ! grep -qP '^\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so\s*.*' "/etc/pam.d/password-auth"; then
+ # Line matching group + control + module was not found. Check group + module.
+ if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "/etc/pam.d/password-auth")" -eq 1 ]; then
+ # The control is updated only if one single line matches.
+ sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"$var_password_pam_remember_control_flag"' \2/' "/etc/pam.d/password-auth"
else
- sed -i -E --follow-symlinks 's/(\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so\s+.*)('"remember"'=)[[:alnum:]]+\s*(.*)/\1\2'"$var_password_pam_remember"' \3/' "$PAM_FILE_PATH"
+ echo 'password '"$var_password_pam_remember_control_flag"' pam_pwhistory.so' >> "/etc/pam.d/password-auth"
fi
+ fi
+fi
+
+PWHISTORY_CONF="/etc/security/pwhistory.conf"
+if [ -f $PWHISTORY_CONF ]; then
+ regex="^\s*remember\s*="
+ line="remember = $var_password_pam_remember"
+ if ! grep -q $regex $PWHISTORY_CONF; then
+ echo $line >> $PWHISTORY_CONF
+ else
+ sed -i --follow-symlinks 's|^\s*\(remember\s*=\s*\)\(\S\+\)|\1'"$var_password_pam_remember"'|g' $PWHISTORY_CONF
+ fi
+ if [ -e "/etc/pam.d/password-auth" ] ; then
+ PAM_FILE_PATH="/etc/pam.d/password-auth"
+ if [ -f /usr/bin/authselect ]; 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 }')
+ 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
+ PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth")
+ PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
+
+ authselect apply-changes -b
+ fi
+
+ if grep -qP '^\s*password\s.*\bpam_pwhistory.so\s.*\bremember\b' "$PAM_FILE_PATH"; then
+ sed -i -E --follow-symlinks 's/(.*password.*pam_pwhistory.so.*)\bremember\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH"
+ fi
+ if [ -f /usr/bin/authselect ]; then
+
+ authselect apply-changes -b
+ fi
+ else
+ echo "/etc/pam.d/password-auth was not found" >&2
+ fi
+else
+ PAM_FILE_PATH="/etc/pam.d/password-auth"
+ if [ -f /usr/bin/authselect ]; 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 }')
+ 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
+ PAM_FILE_NAME=$(basename "/etc/pam.d/password-auth")
+ PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
+
+ authselect apply-changes -b
+ fi
+ if ! grep -qP '^\s*password\s+'"requisite"'\s+pam_pwhistory.so\s*.*' "$PAM_FILE_PATH"; then
+ # Line matching group + control + module was not found. Check group + module.
+ if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then
+ # The control is updated only if one single line matches.
+ sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"requisite"' \2/' "$PAM_FILE_PATH"
+ else
+ echo 'password '"requisite"' pam_pwhistory.so' >> "$PAM_FILE_PATH"
+ fi
+ fi
+ # Check the option
+ if ! grep -qP '^\s*password\s+'"requisite"'\s+pam_pwhistory.so\s*.*\sremember\b' "$PAM_FILE_PATH"; then
+ sed -i -E --follow-symlinks '/\s*password\s+'"requisite"'\s+pam_pwhistory.so.*/ s/$/ remember='"$var_password_pam_remember"'/' "$PAM_FILE_PATH"
+ else
+ sed -i -E --follow-symlinks 's/(\s*password\s+'"requisite"'\s+pam_pwhistory.so\s+.*)('"remember"'=)[[:alnum:]]+\s*(.*)/\1\2'"$var_password_pam_remember"' \3/' "$PAM_FILE_PATH"
+ fi
if [ -f /usr/bin/authselect ]; then
authselect apply-changes -b
fi
-else
- echo "/etc/pam.d/password-auth was not found" >&2
fi
else
ansible remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_password_auth' differs.
--- xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_password_auth
+++ xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_password_auth
@@ -26,11 +26,11 @@
tags:
- always
-- name: 'Limit Password Reuse: password-auth - Check if /etc/pam.d/password-auth file
- is present'
+- name: 'Limit Password Reuse: password-auth - Check if system relies on authselect
+ tool'
ansible.builtin.stat:
- path: /etc/pam.d/password-auth
- register: result_pam_file_present
+ path: /usr/bin/authselect
+ register: result_authselect_present
when: '"pam" in ansible_facts.packages'
tags:
- CCE-83478-8
@@ -47,8 +47,101 @@
- medium_severity
- no_reboot_needed
-- name: 'Limit Password Reuse: password-auth - Check the proper remediation for the
- system'
+- name: 'Limit Password Reuse: password-auth - Collect the available authselect features'
+ ansible.builtin.command:
+ cmd: authselect list-features minimal
+ register: result_authselect_available_features
+ changed_when: false
+ when:
+ - '"pam" in ansible_facts.packages'
+ - result_authselect_present.stat.exists
+ tags:
+ - CCE-83478-8
+ - CJIS-5.6.2.1.1
+ - DISA-STIG-RHEL-08-020220
+ - NIST-800-171-3.5.8
+ - NIST-800-53-IA-5(1)(e)
+ - NIST-800-53-IA-5(f)
+ - PCI-DSS-Req-8.2.5
+ - accounts_password_pam_pwhistory_remember_password_auth
+ - configure_strategy
+ - low_complexity
+ - medium_disruption
+ - medium_severity
+ - no_reboot_needed
+
+- name: 'Limit Password Reuse: password-auth - Enable pam_pwhistory.so using authselect
+ feature'
+ block:
+
+ - name: 'Limit Password Reuse: password-auth - Check integrity of authselect current
+ profile'
+ ansible.builtin.command:
+ cmd: authselect check
+ register: result_authselect_check_cmd
+ changed_when: false
+ ignore_errors: true
+
+ - name: 'Limit Password Reuse: password-auth - Informative message based on the
+ authselect integrity check result'
+ ansible.builtin.assert:
+ that:
+ - result_authselect_check_cmd is success
+ fail_msg:
+ - authselect integrity check failed. Remediation aborted!
+ - This remediation could not be applied because 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
+
+ - name: 'Limit Password Reuse: password-auth - Get authselect current features'
+ ansible.builtin.shell:
+ cmd: authselect current | tail -n+3 | awk '{ print $2 }'
+ register: result_authselect_features
+ changed_when: false
+ when:
+ - result_authselect_check_cmd is success
+
+ - name: 'Limit Password Reuse: password-auth - Ensure "with-pwhistory" feature is
+ enabled using authselect tool'
+ ansible.builtin.command:
+ cmd: authselect enable-feature with-pwhistory
+ register: result_authselect_enable_feature_cmd
+ when:
+ - result_authselect_check_cmd is success
+ - result_authselect_features.stdout is not search("with-pwhistory")
+
+ - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are applied'
+ ansible.builtin.command:
+ cmd: authselect apply-changes -b
+ when:
+ - result_authselect_enable_feature_cmd is not skipped
+ - result_authselect_enable_feature_cmd is success
+ when:
+ - '"pam" in ansible_facts.packages'
+ - result_authselect_present.stat.exists
+ - result_authselect_available_features.stdout is search("with-pwhistory")
+ tags:
+ - CCE-83478-8
+ - CJIS-5.6.2.1.1
+ - DISA-STIG-RHEL-08-020220
+ - NIST-800-171-3.5.8
+ - NIST-800-53-IA-5(1)(e)
+ - NIST-800-53-IA-5(f)
+ - PCI-DSS-Req-8.2.5
+ - accounts_password_pam_pwhistory_remember_password_auth
+ - configure_strategy
+ - low_complexity
+ - medium_disruption
+ - medium_severity
+ - no_reboot_needed
+
+- name: 'Limit Password Reuse: password-auth - Enable pam_pwhistory.so in appropriate
+ PAM files'
block:
- name: 'Limit Password Reuse: password-auth - Define the PAM file to be edited
@@ -56,12 +149,14 @@
ansible.builtin.set_fact:
pam_file_path: /etc/pam.d/password-auth
- - name: 'Limit Password Reuse: password-auth - Check if system relies on authselect'
+ - name: 'Limit Password Reuse: password-auth - Check if system relies on authselect
+ tool'
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- - name: 'Limit Password Reuse: password-auth - Remediate using authselect'
+ - name: 'Limit Password Reuse: password-auth - Ensure authselect custom profile
+ is used if authselect is present'
block:
- name: 'Limit Password Reuse: password-auth - Check integrity of authselect current
@@ -245,53 +340,10 @@
when:
- result_pam_line_present.found is defined
- result_pam_line_present.found == 0
-
- - name: 'Limit Password Reuse: password-auth - Check if the required PAM module
- option is present in {{ pam_file_path }}'
- ansible.builtin.lineinfile:
- path: '{{ pam_file_path }}'
- regexp: ^\s*password\s+{{ var_password_pam_remember_control_flag.split(",")[0]
- }}\s+pam_pwhistory.so\s*.*\sremember\b
- state: absent
- check_mode: true
- changed_when: false
- register: result_pam_module_remember_option_present
-
- - name: 'Limit Password Reuse: password-auth - Ensure the "remember" PAM option
- for "pam_pwhistory.so" is included in {{ pam_file_path }}'
- ansible.builtin.lineinfile:
- path: '{{ pam_file_path }}'
- backrefs: true
- regexp: ^(\s*password\s+{{ var_password_pam_remember_control_flag.split(",")[0]
- }}\s+pam_pwhistory.so.*)
- line: \1 remember={{ var_password_pam_remember }}
- state: present
- register: result_pam_remember_add
- when:
- - result_pam_module_remember_option_present.found == 0
-
- - name: 'Limit Password Reuse: password-auth - Ensure the required value for "remember"
- PAM option from "pam_pwhistory.so" in {{ pam_file_path }}'
- ansible.builtin.lineinfile:
- path: '{{ pam_file_path }}'
- backrefs: true
- regexp: ^(\s*password\s+{{ var_password_pam_remember_control_flag.split(",")[0]
- }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*)
- line: \1\2={{ var_password_pam_remember }} \3
- register: result_pam_remember_edit
- when:
- - result_pam_module_remember_option_present.found > 0
-
- - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are applied'
- ansible.builtin.command:
- cmd: authselect apply-changes -b
- when:
- - result_authselect_present.stat.exists
- - (result_pam_remember_add is defined and result_pam_remember_add.changed) or
- (result_pam_remember_edit is defined and result_pam_remember_edit.changed)
when:
- '"pam" in ansible_facts.packages'
- - result_pam_file_present.stat.exists
+ - |
+ (result_authselect_available_features.stdout is defined and result_authselect_available_features.stdout is not search("with-pwhistory")) or result_authselect_available_features is not defined
tags:
- CCE-83478-8
- CJIS-5.6.2.1.1
@@ -306,3 +358,484 @@
- medium_disruption
- medium_severity
- no_reboot_needed
+
+- name: 'Limit Password Reuse: password-auth - Check the presence of /etc/security/pwhistory.conf
+ file'
+ ansible.builtin.stat:
+ path: /etc/security/pwhistory.conf
+ register: result_pwhistory_conf_check
+ when: '"pam" in ansible_facts.packages'
+ tags:
+ - CCE-83478-8
+ - CJIS-5.6.2.1.1
+ - DISA-STIG-RHEL-08-020220
+ - NIST-800-171-3.5.8
+ - NIST-800-53-IA-5(1)(e)
+ - NIST-800-53-IA-5(f)
+ - PCI-DSS-Req-8.2.5
+ - accounts_password_pam_pwhistory_remember_password_auth
+ - configure_strategy
+ - low_complexity
+ - medium_disruption
+ - medium_severity
+ - no_reboot_needed
+
+- name: 'Limit Password Reuse: password-auth - pam_pwhistory.so parameters are configured
+ in /etc/security/pwhistory.conf file'
+ block:
+
+ - name: 'Limit Password Reuse: password-auth - Ensure the pam_pwhistory.so remember
+ parameter in /etc/security/pwhistory.conf'
+ ansible.builtin.lineinfile:
+ path: /etc/security/pwhistory.conf
+ regexp: ^\s*remember\s*=
+ line: remember = {{ var_password_pam_remember }}
+ state: present
+
+ - name: 'Limit Password Reuse: password-auth - Ensure the pam_pwhistory.so remember
+ parameter is removed from PAM files'
+ block:
+
+ - name: 'Limit Password Reuse: password-auth - Check if /etc/pam.d/password-auth
+ file is present'
+ ansible.builtin.stat:
+ path: /etc/pam.d/password-auth
+ register: result_pam_file_present
+
+ - name: 'Limit Password Reuse: password-auth - Check the proper remediation for
+ the system'
+ block:
+
+ - name: 'Limit Password Reuse: password-auth - Define the PAM file to be edited
+ as a local fact'
+ ansible.builtin.set_fact:
+ pam_file_path: /etc/pam.d/password-auth
+
+ - name: 'Limit Password Reuse: password-auth - Check if system relies on authselect
+ tool'
+ ansible.builtin.stat:
+ path: /usr/bin/authselect
+ register: result_authselect_present
+
+ - name: 'Limit Password Reuse: password-auth - Ensure authselect custom profile
+ is used if authselect is present'
+ block:
+
+ - name: 'Limit Password Reuse: password-auth - Check integrity of authselect
+ current profile'
+ ansible.builtin.command:
+ cmd: authselect check
+ register: result_authselect_check_cmd
+ changed_when: false
+ ignore_errors: true
+
+ - name: 'Limit Password Reuse: password-auth - Informative message based on
+ the authselect integrity check result'
+ ansible.builtin.assert:
+ that:
+ - result_authselect_check_cmd is success
+ fail_msg:
+ - authselect integrity check failed. Remediation aborted!
+ - This remediation could not be applied because 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
+
+ - name: 'Limit Password Reuse: password-auth - Get authselect current profile'
+ ansible.builtin.shell:
+ cmd: authselect current -r | awk '{ print $1 }'
+ register: result_authselect_profile
+ changed_when: false
+ when:
+ - result_authselect_check_cmd is success
+
+ - name: 'Limit Password Reuse: password-auth - Define the current authselect
+ profile as a local fact'
+ ansible.builtin.set_fact:
+ authselect_current_profile: '{{ result_authselect_profile.stdout }}'
+ authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
+ when:
+ - result_authselect_profile is not skipped
+ - result_authselect_profile.stdout is match("custom/")
+
+ - name: 'Limit Password Reuse: password-auth - Define the new authselect custom
+ profile as a local fact'
+ ansible.builtin.set_fact:
+ authselect_current_profile: '{{ result_authselect_profile.stdout }}'
+ authselect_custom_profile: custom/hardening
+ when:
+ - result_authselect_profile is not skipped
+ - result_authselect_profile.stdout is not match("custom/")
+
+ - name: 'Limit Password Reuse: password-auth - Get authselect current features
+ to also enable them in the custom profile'
+ ansible.builtin.shell:
+ cmd: authselect current | tail -n+3 | awk '{ print $2 }'
+ register: result_authselect_features
+ changed_when: false
+ when:
+ - result_authselect_profile is not skipped
+ - authselect_current_profile is not match("custom/")
+
+ - name: 'Limit Password Reuse: password-auth - 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:
+ - authselect_current_profile is not match("custom/")
+
+ - name: 'Limit Password Reuse: password-auth - Create an authselect custom
+ profile based on the current profile'
+ ansible.builtin.command:
+ cmd: authselect create-profile hardening -b {{ authselect_current_profile
+ }}
+ when:
+ - result_authselect_check_cmd is success
+ - authselect_current_profile is not match("custom/")
+ - not result_authselect_custom_profile_present.stat.exists
+
+ - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are
+ applied'
+ ansible.builtin.command:
+ cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
+ when:
+ - result_authselect_check_cmd is success
+ - result_authselect_profile is not skipped
+ - authselect_current_profile is not match("custom/")
+ - authselect_custom_profile is not match(authselect_current_profile)
+
+ - name: 'Limit Password Reuse: password-auth - Ensure the authselect custom
+ profile is selected'
+ ansible.builtin.command:
+ cmd: authselect select {{ authselect_custom_profile }}
+ register: result_pam_authselect_select_profile
+ when:
+ - result_authselect_check_cmd is success
+ - result_authselect_profile is not skipped
+ - authselect_current_profile is not match("custom/")
+ - authselect_custom_profile is not match(authselect_current_profile)
+
+ - name: 'Limit Password Reuse: password-auth - 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:
+ - result_authselect_profile is not skipped
+ - result_authselect_features is not skipped
+ - result_pam_authselect_select_profile is not skipped
+
+ - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are
+ applied'
+ ansible.builtin.command:
+ cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
+ when:
+ - result_authselect_check_cmd is success
+ - result_authselect_profile is not skipped
+ - result_pam_authselect_restore_features is not skipped
+
+ - name: 'Limit Password Reuse: password-auth - Change the PAM file to be edited
+ according to the custom authselect profile'
+ ansible.builtin.set_fact:
+ pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
+ | basename }}
+ when:
+ - result_authselect_present.stat.exists
+
+ - name: 'Limit Password Reuse: password-auth - Ensure the "remember" option
+ from "pam_pwhistory.so" is not present in {{ pam_file_path }}'
+ ansible.builtin.replace:
+ dest: '{{ pam_file_path }}'
+ regexp: (.*password.*pam_pwhistory.so.*)\bremember\b=?[0-9a-zA-Z]*(.*)
+ replace: \1\2
+ register: result_pam_option_removal
+
+ - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are
+ applied'
+ ansible.builtin.command:
+ cmd: authselect apply-changes -b
+ when:
+ - result_authselect_present.stat.exists
+ - result_pam_option_removal is changed
+ when:
+ - result_pam_file_present.stat.exists
+ when:
+ - '"pam" in ansible_facts.packages'
+ - result_pwhistory_conf_check.stat.exists
+ tags:
+ - CCE-83478-8
+ - CJIS-5.6.2.1.1
+ - DISA-STIG-RHEL-08-020220
+ - NIST-800-171-3.5.8
+ - NIST-800-53-IA-5(1)(e)
+ - NIST-800-53-IA-5(f)
+ - PCI-DSS-Req-8.2.5
+ - accounts_password_pam_pwhistory_remember_password_auth
+ - configure_strategy
+ - low_complexity
+ - medium_disruption
+ - medium_severity
+ - no_reboot_needed
+
+- name: 'Limit Password Reuse: password-auth - pam_pwhistory.so parameters are configured
+ in PAM files'
+ block:
+
+ - name: 'Limit Password Reuse: password-auth - Define the PAM file to be edited
+ as a local fact'
+ ansible.builtin.set_fact:
+ pam_file_path: /etc/pam.d/password-auth
+
+ - name: 'Limit Password Reuse: password-auth - Check if system relies on authselect
+ tool'
+ ansible.builtin.stat:
+ path: /usr/bin/authselect
+ register: result_authselect_present
+
+ - name: 'Limit Password Reuse: password-auth - Ensure authselect custom profile
+ is used if authselect is present'
+ block:
+
+ - name: 'Limit Password Reuse: password-auth - Check integrity of authselect current
+ profile'
+ ansible.builtin.command:
+ cmd: authselect check
+ register: result_authselect_check_cmd
+ changed_when: false
+ ignore_errors: true
+
+ - name: 'Limit Password Reuse: password-auth - Informative message based on the
+ authselect integrity check result'
+ ansible.builtin.assert:
+ that:
+ - result_authselect_check_cmd is success
+ fail_msg:
+ - authselect integrity check failed. Remediation aborted!
+ - This remediation could not be applied because 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
+
+ - name: 'Limit Password Reuse: password-auth - Get authselect current profile'
+ ansible.builtin.shell:
+ cmd: authselect current -r | awk '{ print $1 }'
+ register: result_authselect_profile
+ changed_when: false
+ when:
+ - result_authselect_check_cmd is success
+
+ - name: 'Limit Password Reuse: password-auth - Define the current authselect profile
+ as a local fact'
+ ansible.builtin.set_fact:
+ authselect_current_profile: '{{ result_authselect_profile.stdout }}'
+ authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
+ when:
+ - result_authselect_profile is not skipped
+ - result_authselect_profile.stdout is match("custom/")
+
+ - name: 'Limit Password Reuse: password-auth - Define the new authselect custom
+ profile as a local fact'
+ ansible.builtin.set_fact:
+ authselect_current_profile: '{{ result_authselect_profile.stdout }}'
+ authselect_custom_profile: custom/hardening
+ when:
+ - result_authselect_profile is not skipped
+ - result_authselect_profile.stdout is not match("custom/")
+
+ - name: 'Limit Password Reuse: password-auth - Get authselect current features
+ to also enable them in the custom profile'
+ ansible.builtin.shell:
+ cmd: authselect current | tail -n+3 | awk '{ print $2 }'
+ register: result_authselect_features
+ changed_when: false
+ when:
+ - result_authselect_profile is not skipped
+ - authselect_current_profile is not match("custom/")
+
+ - name: 'Limit Password Reuse: password-auth - 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:
+ - authselect_current_profile is not match("custom/")
+
+ - name: 'Limit Password Reuse: password-auth - Create an authselect custom profile
+ based on the current profile'
+ ansible.builtin.command:
+ cmd: authselect create-profile hardening -b {{ authselect_current_profile
+ }}
+ when:
+ - result_authselect_check_cmd is success
+ - authselect_current_profile is not match("custom/")
+ - not result_authselect_custom_profile_present.stat.exists
+
+ - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are applied'
+ ansible.builtin.command:
+ cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
+ when:
+ - result_authselect_check_cmd is success
+ - result_authselect_profile is not skipped
+ - authselect_current_profile is not match("custom/")
+ - authselect_custom_profile is not match(authselect_current_profile)
+
+ - name: 'Limit Password Reuse: password-auth - Ensure the authselect custom profile
+ is selected'
+ ansible.builtin.command:
+ cmd: authselect select {{ authselect_custom_profile }}
+ register: result_pam_authselect_select_profile
+ when:
+ - result_authselect_check_cmd is success
+ - result_authselect_profile is not skipped
+ - authselect_current_profile is not match("custom/")
+ - authselect_custom_profile is not match(authselect_current_profile)
+
+ - name: 'Limit Password Reuse: password-auth - 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:
+ - result_authselect_profile is not skipped
+ - result_authselect_features is not skipped
+ - result_pam_authselect_select_profile is not skipped
+
+ - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are applied'
+ ansible.builtin.command:
+ cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
+ when:
+ - result_authselect_check_cmd is success
+ - result_authselect_profile is not skipped
+ - result_pam_authselect_restore_features is not skipped
+
+ - name: 'Limit Password Reuse: password-auth - Change the PAM file to be edited
+ according to the custom authselect profile'
+ ansible.builtin.set_fact:
+ pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
+ | basename }}
+ when:
+ - result_authselect_present.stat.exists
+
+ - name: 'Limit Password Reuse: password-auth - Check if expected PAM module line
+ is present in {{ pam_file_path }}'
+ ansible.builtin.lineinfile:
+ path: '{{ pam_file_path }}'
+ regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.*
+ state: absent
+ check_mode: true
+ changed_when: false
+ register: result_pam_line_present
+
+ - name: 'Limit Password Reuse: password-auth - Include or update the PAM module
+ line in {{ pam_file_path }}'
+ block:
+
+ - name: 'Limit Password Reuse: password-auth - Check if required PAM module line
+ is present in {{ pam_file_path }} with different control'
+ ansible.builtin.lineinfile:
+ path: '{{ pam_file_path }}'
+ regexp: ^\s*password\s+.*\s+pam_pwhistory.so\s*
+ state: absent
+ check_mode: true
+ changed_when: false
+ register: result_pam_line_other_control_present
+
+ - name: 'Limit Password Reuse: password-auth - Ensure the correct control for
+ the required PAM module line in {{ pam_file_path }}'
+ ansible.builtin.replace:
+ dest: '{{ pam_file_path }}'
+ regexp: ^(\s*password\s+).*(\bpam_pwhistory.so.*)
+ replace: \1requisite \2
+ register: result_pam_module_edit
+ when:
+ - result_pam_line_other_control_present.found == 1
+
+ - name: 'Limit Password Reuse: password-auth - Ensure the required PAM module
+ line is included in {{ pam_file_path }}'
+ ansible.builtin.lineinfile:
+ dest: '{{ pam_file_path }}'
+ line: password requisite pam_pwhistory.so
+ register: result_pam_module_add
+ when:
+ - result_pam_line_other_control_present.found == 0 or result_pam_line_other_control_present.found
+ > 1
+
+ - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are applied'
+ ansible.builtin.command:
+ cmd: authselect apply-changes -b
+ when: |
+ result_authselect_present is defined and result_authselect_present.stat.exists and ((result_pam_module_add is defined and result_pam_module_add.changed) or (result_pam_module_edit is defined and result_pam_module_edit.changed))
+ when:
+ - result_pam_line_present.found is defined
+ - result_pam_line_present.found == 0
+
+ - name: 'Limit Password Reuse: password-auth - Check if the required PAM module
+ option is present in {{ pam_file_path }}'
+ ansible.builtin.lineinfile:
+ path: '{{ pam_file_path }}'
+ regexp: ^\s*password\s+requisite\s+pam_pwhistory.so\s*.*\sremember\b
+ state: absent
+ check_mode: true
+ changed_when: false
+ register: result_pam_module_remember_option_present
+
+ - name: 'Limit Password Reuse: password-auth - Ensure the "remember" PAM option
+ for "pam_pwhistory.so" is included in {{ pam_file_path }}'
+ ansible.builtin.lineinfile:
+ path: '{{ pam_file_path }}'
+ backrefs: true
+ regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so.*)
+ line: \1 remember={{ var_password_pam_remember }}
+ state: present
+ register: result_pam_remember_add
+ when:
+ - result_pam_module_remember_option_present.found == 0
+
+ - name: 'Limit Password Reuse: password-auth - Ensure the required value for "remember"
+ PAM option from "pam_pwhistory.so" in {{ pam_file_path }}'
+ ansible.builtin.lineinfile:
+ path: '{{ pam_file_path }}'
+ backrefs: true
+ regexp: ^(\s*password\s+requisite\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]+\s*(.*)
+ line: \1\2={{ var_password_pam_remember }} \3
+ register: result_pam_remember_edit
+ when:
+ - result_pam_module_remember_option_present.found > 0
+
+ - name: 'Limit Password Reuse: password-auth - Ensure authselect changes are applied'
+ ansible.builtin.command:
+ cmd: authselect apply-changes -b
+ when:
+ - result_authselect_present.stat.exists
+ - (result_pam_remember_add is defined and result_pam_remember_add.changed) or
+ (result_pam_remember_edit is defined and result_pam_remember_edit.changed)
+ when:
+ - '"pam" in ansible_facts.packages'
+ - not result_pwhistory_conf_check.stat.exists
+ tags:
+ - CCE-83478-8
+ - CJIS-5.6.2.1.1
+ - DISA-STIG-RHEL-08-020220
+ - NIST-800-171-3.5.8
+ - NIST-800-53-IA-5(1)(e)
+ - NIST-800-53-IA-5(f)
+ - PCI-DSS-Req-8.2.5
+ - accounts_password_pam_pwhistory_remember_password_auth
+ - configure_strategy
+ - low_complexity
+ - medium_disruption
+ - medium_severity
+ - no_reboot_needed
New content has different text for rule 'xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_system_auth'.
--- xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_system_auth
+++ xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_system_auth
@@ -6,12 +6,19 @@
Do not allow users to reuse recent passwords. This can be accomplished by using the
remember option for the pam_pwhistory PAM module.
-In the file /etc/pam.d/system-auth, make sure the parameter
-remember is present and it has a value equal to or greater than
+
+On systems with newer versions of authselect, the pam_pwhistory PAM module
+can be enabled via authselect feature:
+authselect enable-feature with-pwhistory
+
+Otherwise, it should be enabled using an authselect custom profile.
+
+Newer systems also have the /etc/security/pwhistory.conf file for setting
+pam_pwhistory module options. This file should be used whenever available.
+Otherwise, the pam_pwhistory module options can be set in PAM files.
+
+The value for remember option must be equal or greater than
'xccdf_org.ssgproject.content_value_var_password_pam_remember'
-For example:
-password control_flag pam_pwhistory.so ...existing_options... remember='xccdf_org.ssgproject.content_value_var_password_pam_remember' use_authtok
-control_flag should be one of the next values: 'xccdf_org.ssgproject.content_value_var_password_pam_remember_control_flag'
[warning]:
If the system relies on authselect tool to manage PAM settings, the remediation
@@ -20,6 +27,11 @@
aborted in order to preserve intentional changes. In this case, an informative message will
be shown in the remediation report.
+[warning]:
+Newer versions of authselect contain an authselect feature to easily and properly
+enable pam_pwhistory.so module. If this feature is not yet available in your
+system, an authselect custom profile must be used to avoid integrity issues in PAM files.
+
[reference]:
1
@@ -198,7 +210,8 @@
SV-251717r858745_rule
[rationale]:
-Preventing re-use of previous passwords helps ensure that a compromised password is not re-used by a user.
+Preventing re-use of previous passwords helps ensure that a compromised password is not
+re-used by a user.
[ident]:
CCE-83480-4
OVAL for rule 'xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_system_auth' differs.
--- oval:ssg-accounts_password_pam_pwhistory_remember_system_auth:def:1
+++ oval:ssg-accounts_password_pam_pwhistory_remember_system_auth:def:1
@@ -1,2 +1,9 @@
criteria AND
criterion oval:ssg-test_accounts_password_pam_pwhistory_remember_system_auth:tst:1
+criteria OR
+criteria AND
+criterion oval:ssg-test_accounts_password_pam_pwhistory_remember_system_auth_pamd:tst:1
+criterion oval:ssg-test_accounts_password_pam_pwhistory_remember_system_auth_no_pwhistory_conf:tst:1
+criteria AND
+criterion oval:ssg-test_accounts_password_pam_pwhistory_remember_system_auth_no_pamd:tst:1
+criterion oval:ssg-test_accounts_password_pam_pwhistory_remember_system_auth_pwhistory_conf:tst:1
OCIL for rule 'xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_system_auth' differs.
--- ocil:ssg-accounts_password_pam_pwhistory_remember_system_auth_ocil:questionnaire:1
+++ ocil:ssg-accounts_password_pam_pwhistory_remember_system_auth_ocil:questionnaire:1
@@ -1,9 +1,20 @@
-Verify Red Hat Enterprise Linux 8 is configured in the system-auth file to prohibit password reuse
-for a minimum of generations with the following command:
+Verify Red Hat Enterprise Linux 8 use the "pam_pwhistory.so" module in the /etc/pam.d/system-auth file
+and is configured to prohibit password reuse for a minimum of
+generations.
-$ grep -i remember /etc/pam.d/system-auth
-password pam_pwhistory.so use_authtok remember= retry=3
- Is it the case that the line containing "pam_pwhistory.so" does not have the "remember" module argument set,
-is commented out, or the value of the "remember" module argument is set to less than
-"<sub idref="var_password_pam_remember" />"?
+Verify the "/etc/pam.d/system-auth" file with the following command:
+
+$ grep pam_pwhistory.so /etc/pam.d/system-auth
+password pam_pwhistory.so use_authtok remember=
+
+
+Verify the "/etc/security/pwhistory.conf" file using the following command:
+
+$ grep remember /etc/security/pwhistory.conf
+remember =
+
+The pam_pwhistory.so "remember" option must be configured only in one file.
+ Is it the case that the pam_pwhistory.so module is not used, the "remember" module option is not set in
+/etc/pam.d/system-auth or in /etc/security/pwhistory.conf, or is set in both files, or is set
+with a value less than "<sub idref="var_password_pam_remember" />"?
bash remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_system_auth' differs.
--- xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_system_auth
+++ xccdf_org.ssgproject.content_rule_accounts_password_pam_pwhistory_remember_system_auth
@@ -7,9 +7,8 @@
var_password_pam_remember_control_flag="$(echo $var_password_pam_remember_control_flag | cut -d \, -f 1)"
-if [ -e "/etc/pam.d/system-auth" ] ; then
- PAM_FILE_PATH="/etc/pam.d/system-auth"
- if [ -f /usr/bin/authselect ]; then
+if [ -f /usr/bin/authselect ]; then
+ if authselect list-features minimal | grep -q with-pwhistory; then
if ! authselect check; then
echo "
authselect integrity check failed. Remediation aborted!
@@ -18,6 +17,20 @@
In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended."
exit 1
fi
+ authselect enable-feature with-pwhistory
+
+ authselect apply-changes -b
+ else
+
+ 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
@@ -35,35 +48,135 @@
fi
PAM_FILE_NAME=$(basename "/etc/pam.d/system-auth")
PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
-
+
authselect apply-changes -b
- fi
- if ! grep -qP '^\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so\s*.*' "$PAM_FILE_PATH"; then
+ if ! grep -qP '^\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so\s*.*' "$PAM_FILE_PATH"; then
# Line matching group + control + module was not found. Check group + module.
if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "$PAM_FILE_PATH")" -eq 1 ]; then
# The control is updated only if one single line matches.
sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"$var_password_pam_remember_control_flag"' \2/' "$PAM_FILE_PATH"
else
- LAST_MATCH_LINE=$(grep -nP "^password.*requisite.*pam_pwquality\.so" "$PAM_FILE_PATH" | tail -n 1 | cut -d: -f 1)
- if [ ! -z $LAST_MATCH_LINE ]; then
- sed -i --follow-symlinks $LAST_MATCH_LINE' a password '"$var_password_pam_remember_control_flag"' pam_pwhistory.so' "$PAM_FILE_PATH"
- else
- echo 'password '"$var_password_pam_remember_control_flag"' pam_pwhistory.so' >> "$PAM_FILE_PATH"
- fi
+ echo 'password '"$var_password_pam_remember_control_flag"' pam_pwhistory.so' >> "$PAM_FILE_PATH"
fi
fi
- # Check the option
- if ! grep -qP '^\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so\s*.*\sremember\b' "$PAM_FILE_PATH"; then
- sed -i -E --follow-symlinks '/\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so.*/ s/$/ remember='"$var_password_pam_remember"'/' "$PAM_FILE_PATH"
+ fi
+else
+ if ! grep -qP '^\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so\s*.*' "/etc/pam.d/system-auth"; then
+ # Line matching group + control + module was not found. Check group + module.
+ if [ "$(grep -cP '^\s*password\s+.*\s+pam_pwhistory.so\s*' "/etc/pam.d/system-auth")" -eq 1 ]; then
+ # The control is updated only if one single line matches.
+ sed -i -E --follow-symlinks 's/^(\s*password\s+).*(\bpam_pwhistory.so.*)/\1'"$var_password_pam_remember_control_flag"' \2/' "/etc/pam.d/system-auth"
else
- sed -i -E --follow-symlinks 's/(\s*password\s+'"$var_password_pam_remember_control_flag"'\s+pam_pwhistory.so\s+.*)('"remember"'=)[[:alnum:]]+\s*(.*)/\1\2'"$var_password_pam_remember"' \3/' "$PAM_FILE_PATH"
+ echo 'password '"$var_password_pam_remember_control_flag"' pam_pwhistory.so' >> "/etc/pam.d/system-auth"
fi
+ fi
+fi
+
+PWHISTORY_CONF="/etc/security/pwhistory.conf"
+if [ -f $PWHISTORY_CONF ]; then
+ regex="^\s*remember\s*="
+ line="remember = $var_password_pam_remember"
+ if ! grep -q $regex $PWHISTORY_CONF; then
+ echo $line >> $PWHISTORY_CONF
+ else
+ sed -i --follow-symlinks 's|^\s*\(remember\s*=\s*\)\(\S\+\)|\1'"$var_password_pam_remember"'|g' $PWHISTORY_CONF
+ fi
+ if [ -e "/etc/pam.d/system-auth" ] ; then
+ PAM_FILE_PATH="/etc/pam.d/system-auth"
+ if [ -f /usr/bin/authselect ]; 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 }')
+ 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
+ PAM_FILE_NAME=$(basename "/etc/pam.d/system-auth")
+ PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
+
+ authselect apply-changes -b
+
... The diff is trimmed here ... |
I saw the Ansible remediation needs some adjustments. I am working on it. |
It should be fine now after the last commit. |
A new feature to configure this module was recently included in authselect. There is currently 3 scenarios where the module configuration differs. On systems with newer versions of authselect, the module should be enabled using authselect feature. On systems with older versions of authselect, the module should be enabled using custom profiles. On systems without authselect, the module is configured directly editing PAM files. Since the macros were created, they were also extended to use /etc/security/pwhistory.conf file whenever ossible.
accounts_password_pam_pwhistory_remember_system_auth rule
e6f3467
to
d56a11a
Compare
The existing and relevant test scenarios were udpated to consider the /etc/security/pwhistory.conf file. It was included a test scenario for conflicting settings.
These macros were created in Ansible in aligment to the respective macros in Bash.
accounts_password_pam_pwhistory_remember_system_auth rule
accounts_password_pam_pwhistory_remember_password_auth rule
accounts_password_pam_pwhistory_remember_password_auth rule
accounts_password_pam_pwhistory_remember_password_auth rule
d56a11a
to
fa16ac2
Compare
/retest |
accounts_password_pam_pwhistory_remember_password_auth rule
accounts_password_pam_unix_remember rule
accounts_password_pam_unix_remember rule
accounts_password_pam_unix_remember rule
accounts_password_pam_unix_remember rule
accounts_password_pam_pwhistory_remember_password_auth accounts_password_pam_pwhistory_remember_system_auth
accounts_password_pam_unix_remember
The first condition was prone to fatal errors, as there were chances of an object used in the criteria not being defined in some contexts.
fa16ac2
to
2c5b9e1
Compare
...g_out_password_attempts/accounts_password_pam_pwhistory_remember_system_auth/oval/shared.xml
Show resolved
Hide resolved
d74855f
to
a677b68
Compare
The name "bash_validate_authselect_custom_profile" was not so intuitive about the variables defined there. On the other hand, the equivalent macro in Ansible was much clearer. In order to make it more readable, the macro was renamed to "bash_ensure_pam_variables_and_authselect_profile" and a more complete description was included. It is now more readble and more aligned to the equivalent in Ansible. In addition, a jinja comment was included when a macro is called to set or modify a variable.
a677b68
to
ed55009
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changes look good now. Thank you for this improvement and excellent test scenarios.
Code Climate has analyzed commit ed55009 and detected 0 issues on this pull request. The test coverage on the diff in this pull request is 100.0% (50% is the threshold). This pull request will bring the total coverage in the repository to 49.8% (0.0% change). View more on Code Climate. |
/retest |
Description:
Recently the
authselect
tool was improved (authselect/authselect#321) to include a new feature to easily and properly enable thepam_pwhistory.so
module.The
pam_pwhistoy.so
module was also updated use the/etc/security/pwhistory.conf
file in order to set its options without the need to edit PAM files directly.This PR refactored the following rules to make them compatible with these new improvements in
authselect
andpam_pwhistory.so
:In order to make the remediation consistent among the rules, new macros were also introduced for Ansible and Bash.
Rationale:
These rules are now compatible with systems which already use newer versions of
authselect
andpam_pwhistoy.so
.These updates will make sure that CI tests in CentOS Stream no longer fail for the related rules.
Review Hints:
The first rule I worked was the
accounts_password_pam_pwhistory_remember_system_auth
, so it will appear first in the commits. Once the rule was well tested and refined, the logic was replicated toaccounts_password_pam_pwhistory_remember_password_auth
andaccounts_password_pam_unix_remember
.The
accounts_password_pam_pwhistory_remember_system_auth
andaccounts_password_pam_pwhistory_remember_password_auth
are almost identical, except they use a different file.The
accounts_password_pam_unix_remember
is a little bit different since its OVAL also accepts thepam_unix.so
module. However, the remediation is in favor ofpam_pwhistory.so
, so using the same approach of the other two rules.I recommend to review this PR commit by commit since they are chronologically organized and detailed messages are describing each commit. This is a relatively complex PR but using this approach to review it should be much easier.