Skip to content
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 faillock related macros #9139

Merged

Conversation

Xeicker
Copy link
Contributor

@Xeicker Xeicker commented Jul 12, 2022

Description:

  • Make faillock related macros manage the edge cases:
    • When the user had set options in pam files, but faillock.conf was available
    • When the option is not a number
    • Remove pam option when the option doesn't have a value associated

Rationale:

  • As stated in pam_faillock man page, modifying pam_faillock options from pam files is still possible but not recommended.
  • This prepares for the dir option which isn't a number
  • Doing this it was found that when a pam option didn't have a value associated, the macro bash_remove_pam_module_option_configuration wasn't working

@openshift-ci openshift-ci bot added the needs-ok-to-test Used by openshift-ci bot. label Jul 12, 2022
@openshift-ci
Copy link

openshift-ci bot commented Jul 12, 2022

Hi @Xeicker. Thanks for your PR.

I'm waiting for a ComplianceAsCode member to verify that this patch is reasonable to test. If it is, they should reply with /ok-to-test on its own line. Until that is done, I will not automatically test new commits in this PR, but the usual testing commands by org members will still work. Regular contributors should join the org to skip this step.

Once the patch is verified, the new status will be reflected by the ok-to-test label.

I understand the commands that are listed here.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@github-actions
Copy link

Start a new ephemeral environment with changes proposed in this pull request:

rhel8 (from CTF) Environment (using Fedora as testing environment)
Open in Gitpod

Fedora Testing Environment
Open in Gitpod

Oracle Linux 8 Environment
Open in Gitpod

@github-actions
Copy link

This datastream diff is auto generated by the check Compare DS/Generate Diff.
Due to the excessive size of the diff, it has been trimmed to fit the 65535-character limit.

Click here to see the trimmed diff
bash remediation for rule 'xccdf_org.ssgproject.content_rule_display_login_attempts' differs:
--- old datastream
+++ new datastream
@@ -84,7 +84,7 @@
 authselect apply-changes -b
 fi
 
-if grep -qP '^\s*session\s.*\bpam_lastlog.so\s.*\bsilent[=\s$]' "$PAM_FILE_PATH"; then
+if grep -qP '^\s*session\s.*\bpam_lastlog.so\s.*\bsilent\b' "$PAM_FILE_PATH"; then
 sed -i -E --follow-symlinks 's/(.*session.*pam_lastlog.so.*)\bsilent\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH"
 fi
 if [ -f /usr/bin/authselect ]; then

bash remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_deny' differs:
--- old datastream
+++ new datastream
@@ -28,6 +28,7 @@
 sed -Ei 's/(auth.*)(\[default=die\])(.*pam_faillock.so)/\1required \3/g' "$pam_file"
 done
 fi
+AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth")
 FAILLOCK_CONF="/etc/security/faillock.conf"
 if [ -f $FAILLOCK_CONF ]; then
 regex="^\s*deny\s*="
@@ -35,10 +36,54 @@
 if ! grep -q $regex $FAILLOCK_CONF; then
 echo $line >> $FAILLOCK_CONF
 else
- sed -i --follow-symlinks 's/^\s*\(deny\s*=\s*\)\([0-9]\+\)/\1'"$var_accounts_passwords_pam_faillock_deny"'/g' $FAILLOCK_CONF
+ sed -i --follow-symlinks 's|^\s*\(deny\s*=\s*\)\(\S\+\)|\1'"$var_accounts_passwords_pam_faillock_deny"'|g' $FAILLOCK_CONF
 fi
+ for pam_file in "${AUTH_FILES[@]}"
+ do
+ 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
+ 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 "$pam_file")
+ PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
+ 
+ authselect apply-changes -b
+ fi
+ 
+ if grep -qP '^\s*auth\s.*\bpam_faillock.so\s.*\bdeny\b' "$PAM_FILE_PATH"; then
+ sed -i -E --follow-symlinks 's/(.*auth.*pam_faillock.so.*)\bdeny\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH"
+ fi
+ if [ -f /usr/bin/authselect ]; then
+ 
+ authselect apply-changes -b
+ fi
+ else
+ echo "$pam_file was not found" >&2
+ fi
+ done
 else
- AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth")
 for pam_file in "${AUTH_FILES[@]}"
 do
 if ! grep -qE '^\s*auth.*pam_faillock.so (preauth|authfail).*deny' "$pam_file"; then

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_deny' differs:
--- old datastream
+++ new datastream
@@ -229,6 +229,369 @@
 - restrict_strategy
 
 - name: Lock Accounts After Failed Password Attempts - Ensure the pam_faillock.so
+ deny parameter not in PAM files
+ block:
+
+ - name: Lock Accounts After Failed Password Attempts - Check if /etc/pam.d/system-auth
+ file is present
+ ansible.builtin.stat:
+ path: /etc/pam.d/system-auth
+ register: result_pam_file_present
+
+ - name: Lock Accounts After Failed Password Attempts - Check the proper remediation
+ for the system
+ block:
+
+ - name: Lock Accounts After Failed Password Attempts - Define the PAM file to
+ be edited as a local fact
+ ansible.builtin.set_fact:
+ pam_file_path: /etc/pam.d/system-auth
+
+ - name: Lock Accounts After Failed Password Attempts - Check if system relies
+ on authselect
+ ansible.builtin.stat:
+ path: /usr/bin/authselect
+ register: result_authselect_present
+
+ - name: Lock Accounts After Failed Password Attempts - Remediate using authselect
+ block:
+
+ - name: Lock Accounts After Failed Password Attempts - Check integrity of authselect
+ current profile
+ ansible.builtin.command:
+ cmd: authselect check
+ register: result_authselect_check_cmd
+ changed_when: false
+ ignore_errors: true
+
+ - name: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - Ensure the "deny" option
+ from "pam_faillock.so" is not present in {{ pam_file_path }}
+ ansible.builtin.replace:
+ dest: '{{ pam_file_path }}'
+ regexp: (.*auth.*pam_faillock.so.*)\bdeny\b=?[0-9a-zA-Z]*(.*)
+ replace: \1\2
+ register: result_pam_option_removal
+
+ - name: Lock Accounts After Failed Password Attempts - 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
+
+ - name: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - Check the proper remediation
+ for the system
+ block:
+
+ - name: Lock Accounts After Failed Password Attempts - Define the PAM file to
+ be edited as a local fact
+ ansible.builtin.set_fact:
+ pam_file_path: /etc/pam.d/password-auth
+
+ - name: Lock Accounts After Failed Password Attempts - Check if system relies
+ on authselect
+ ansible.builtin.stat:
+ path: /usr/bin/authselect
+ register: result_authselect_present
+
+ - name: Lock Accounts After Failed Password Attempts - Remediate using authselect
+ block:
+
+ - name: Lock Accounts After Failed Password Attempts - Check integrity of authselect
+ current profile
+ ansible.builtin.command:
+ cmd: authselect check
+ register: result_authselect_check_cmd
+ changed_when: false
+ ignore_errors: true
+
+ - name: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - 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: Lock Accounts After Failed Password Attempts - Ensure the "deny" option
+ from "pam_faillock.so" is not present in {{ pam_file_path }}
+ ansible.builtin.replace:
+ dest: '{{ pam_file_path }}'
+ regexp: (.*auth.*pam_faillock.so.*)\bdeny\b=?[0-9a-zA-Z]*(.*)
+ replace: \1\2
+ register: result_pam_option_removal
+
+ - name: Lock Accounts After Failed Password Attempts - 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_faillock_conf_check.stat.exists
+ tags:
+ - CCE-80667-9
+ - CJIS-5.5.3
+ - DISA-STIG-RHEL-08-020010
+ - NIST-800-171-3.1.8
+ - NIST-800-53-AC-7(a)
+ - NIST-800-53-CM-6(a)
+ - PCI-DSS-Req-8.1.6
+ - accounts_passwords_pam_faillock_deny
+ - low_complexity
+ - low_disruption
+ - medium_severity
+ - no_reboot_needed
+ - restrict_strategy
+
+- name: Lock Accounts After Failed Password Attempts - Ensure the pam_faillock.so
 deny parameter in PAM files
 block:
 

bash remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_deny_root' differs:
--- old datastream
+++ new datastream
@@ -25,6 +25,7 @@
 sed -Ei 's/(auth.*)(\[default=die\])(.*pam_faillock.so)/\1required \3/g' "$pam_file"
 done
 fi
+AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth")
 FAILLOCK_CONF="/etc/security/faillock.conf"
 if [ -f $FAILLOCK_CONF ]; then
 regex="^\s*even_deny_root"
@@ -32,8 +33,52 @@
 if ! grep -q $regex $FAILLOCK_CONF; then
 echo $line >> $FAILLOCK_CONF
 fi
+ for pam_file in "${AUTH_FILES[@]}"
+ do
+ 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
+ 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 "$pam_file")
+ PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
+ 
+ authselect apply-changes -b
+ fi
+ 
+ if grep -qP '^\s*auth\s.*\bpam_faillock.so\s.*\beven_deny_root\b' "$PAM_FILE_PATH"; then
+ sed -i -E --follow-symlinks 's/(.*auth.*pam_faillock.so.*)\beven_deny_root\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH"
+ fi
+ if [ -f /usr/bin/authselect ]; then
+ 
+ authselect apply-changes -b
+ fi
+ else
+ echo "$pam_file was not found" >&2
+ fi
+ done
 else
- AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth")
 for pam_file in "${AUTH_FILES[@]}"
 do
 if ! grep -qE '^\s*auth.*pam_faillock.so (preauth|authfail).*even_deny_root' "$pam_file"; then

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_deny_root' differs:
--- old datastream
+++ new datastream
@@ -213,6 +213,369 @@
 - restrict_strategy
 
 - name: Configure the root Account for Failed Password Attempts - Ensure the pam_faillock.so
+ even_deny_root parameter not in PAM files
+ block:
+
+ - name: Configure the root Account for Failed Password Attempts - Check if /etc/pam.d/system-auth
+ file is present
+ ansible.builtin.stat:
+ path: /etc/pam.d/system-auth
+ register: result_pam_file_present
+
+ - name: Configure the root Account for Failed Password Attempts - Check the proper
+ remediation for the system
+ block:
+
+ - name: Configure the root Account for Failed Password Attempts - Define the PAM
+ file to be edited as a local fact
+ ansible.builtin.set_fact:
+ pam_file_path: /etc/pam.d/system-auth
+
+ - name: Configure the root Account for Failed Password Attempts - Check if system
+ relies on authselect
+ ansible.builtin.stat:
+ path: /usr/bin/authselect
+ register: result_authselect_present
+
+ - name: Configure the root Account for Failed Password Attempts - Remediate using
+ authselect
+ block:
+
+ - name: Configure the root Account for Failed Password Attempts - Check integrity
+ of authselect current profile
+ ansible.builtin.command:
+ cmd: authselect check
+ register: result_authselect_check_cmd
+ changed_when: false
+ ignore_errors: true
+
+ - name: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - Ensure the "even_deny_root"
+ option from "pam_faillock.so" is not present in {{ pam_file_path }}
+ ansible.builtin.replace:
+ dest: '{{ pam_file_path }}'
+ regexp: (.*auth.*pam_faillock.so.*)\beven_deny_root\b=?[0-9a-zA-Z]*(.*)
+ replace: \1\2
+ register: result_pam_option_removal
+
+ - name: Configure the root Account for Failed Password Attempts - 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
+
+ - name: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - Check the proper
+ remediation for the system
+ block:
+
+ - name: Configure the root Account for Failed Password Attempts - Define the PAM
+ file to be edited as a local fact
+ ansible.builtin.set_fact:
+ pam_file_path: /etc/pam.d/password-auth
+
+ - name: Configure the root Account for Failed Password Attempts - Check if system
+ relies on authselect
+ ansible.builtin.stat:
+ path: /usr/bin/authselect
+ register: result_authselect_present
+
+ - name: Configure the root Account for Failed Password Attempts - Remediate using
+ authselect
+ block:
+
+ - name: Configure the root Account for Failed Password Attempts - Check integrity
+ of authselect current profile
+ ansible.builtin.command:
+ cmd: authselect check
+ register: result_authselect_check_cmd
+ changed_when: false
+ ignore_errors: true
+
+ - name: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - 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: Configure the root Account for Failed Password Attempts - Ensure the "even_deny_root"
+ option from "pam_faillock.so" is not present in {{ pam_file_path }}
+ ansible.builtin.replace:
+ dest: '{{ pam_file_path }}'
+ regexp: (.*auth.*pam_faillock.so.*)\beven_deny_root\b=?[0-9a-zA-Z]*(.*)
+ replace: \1\2
+ register: result_pam_option_removal
+
+ - name: Configure the root Account for Failed Password Attempts - 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_faillock_conf_check.stat.exists
+ tags:
+ - CCE-80668-7
+ - DISA-STIG-RHEL-08-020022
+ - NIST-800-53-AC-7(b)
+ - NIST-800-53-CM-6(a)
+ - NIST-800-53-IA-5(c)
+ - accounts_passwords_pam_faillock_deny_root
+ - low_complexity
+ - low_disruption
+ - medium_severity
+ - no_reboot_needed
+ - restrict_strategy
+
+- name: Configure the root Account for Failed Password Attempts - Ensure the pam_faillock.so
 even_deny_root parameter in PAM files
 block:
 

bash remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_enforce_local' differs:
--- old datastream
+++ new datastream
@@ -25,6 +25,7 @@
 sed -Ei 's/(auth.*)(\[default=die\])(.*pam_faillock.so)/\1required \3/g' "$pam_file"
 done
 fi
+AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth")
 FAILLOCK_CONF="/etc/security/faillock.conf"
 if [ -f $FAILLOCK_CONF ]; then
 regex="^\s*local_users_only"
@@ -32,8 +33,52 @@
 if ! grep -q $regex $FAILLOCK_CONF; then
 echo $line >> $FAILLOCK_CONF
 fi
+ for pam_file in "${AUTH_FILES[@]}"
+ do
+ 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
+ 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 "$pam_file")
+ PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
+ 
+ authselect apply-changes -b
+ fi
+ 
+ if grep -qP '^\s*auth\s.*\bpam_faillock.so\s.*\blocal_users_only\b' "$PAM_FILE_PATH"; then
+ sed -i -E --follow-symlinks 's/(.*auth.*pam_faillock.so.*)\blocal_users_only\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH"
+ fi
+ if [ -f /usr/bin/authselect ]; then
+ 
+ authselect apply-changes -b
+ fi
+ else
+ echo "$pam_file was not found" >&2
+ fi
+ done
 else
- AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth")
 for pam_file in "${AUTH_FILES[@]}"
 do
 if ! grep -qE '^\s*auth.*pam_faillock.so (preauth|authfail).*local_users_only' "$pam_file"; then

ansible remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_enforce_local' differs:
--- old datastream
+++ new datastream
@@ -194,6 +194,364 @@
 - restrict_strategy
 
 - name: Enforce pam_faillock for Local Accounts Only - Ensure the pam_faillock.so
+ local_users_only parameter not in PAM files
+ block:
+
+ - name: Enforce pam_faillock for Local Accounts Only - Check if /etc/pam.d/system-auth
+ file is present
+ ansible.builtin.stat:
+ path: /etc/pam.d/system-auth
+ register: result_pam_file_present
+
+ - name: Enforce pam_faillock for Local Accounts Only - Check the proper remediation
+ for the system
+ block:
+
+ - name: Enforce pam_faillock for Local Accounts Only - Define the PAM file to
+ be edited as a local fact
+ ansible.builtin.set_fact:
+ pam_file_path: /etc/pam.d/system-auth
+
+ - name: Enforce pam_faillock for Local Accounts Only - Check if system relies
+ on authselect
+ ansible.builtin.stat:
+ path: /usr/bin/authselect
+ register: result_authselect_present
+
+ - name: Enforce pam_faillock for Local Accounts Only - Remediate using authselect
+ block:
+
+ - name: Enforce pam_faillock for Local Accounts Only - Check integrity of authselect
+ current profile
+ ansible.builtin.command:
+ cmd: authselect check
+ register: result_authselect_check_cmd
+ changed_when: false
+ ignore_errors: true
+
+ - name: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - Ensure the "local_users_only"
+ option from "pam_faillock.so" is not present in {{ pam_file_path }}
+ ansible.builtin.replace:
+ dest: '{{ pam_file_path }}'
+ regexp: (.*auth.*pam_faillock.so.*)\blocal_users_only\b=?[0-9a-zA-Z]*(.*)
+ replace: \1\2
+ register: result_pam_option_removal
+
+ - name: Enforce pam_faillock for Local Accounts Only - 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
+
+ - name: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - Check the proper remediation
+ for the system
+ block:
+
+ - name: Enforce pam_faillock for Local Accounts Only - Define the PAM file to
+ be edited as a local fact
+ ansible.builtin.set_fact:
+ pam_file_path: /etc/pam.d/password-auth
+
+ - name: Enforce pam_faillock for Local Accounts Only - Check if system relies
+ on authselect
+ ansible.builtin.stat:
+ path: /usr/bin/authselect
+ register: result_authselect_present
+
+ - name: Enforce pam_faillock for Local Accounts Only - Remediate using authselect
+ block:
+
+ - name: Enforce pam_faillock for Local Accounts Only - Check integrity of authselect
+ current profile
+ ansible.builtin.command:
+ cmd: authselect check
+ register: result_authselect_check_cmd
+ changed_when: false
+ ignore_errors: true
+
+ - name: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - 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: Enforce pam_faillock for Local Accounts Only - Ensure the "local_users_only"
+ option from "pam_faillock.so" is not present in {{ pam_file_path }}
+ ansible.builtin.replace:
+ dest: '{{ pam_file_path }}'
+ regexp: (.*auth.*pam_faillock.so.*)\blocal_users_only\b=?[0-9a-zA-Z]*(.*)
+ replace: \1\2
+ register: result_pam_option_removal
+
+ - name: Enforce pam_faillock for Local Accounts Only - 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_faillock_conf_check.stat.exists
+ tags:
+ - CCE-83401-0
+ - NIST-800-53-AC-2(1)
+ - accounts_passwords_pam_faillock_enforce_local
+ - low_complexity
+ - low_disruption
+ - medium_severity
+ - no_reboot_needed
+ - restrict_strategy
+
+- name: Enforce pam_faillock for Local Accounts Only - Ensure the pam_faillock.so
 local_users_only parameter in PAM files
 block:
 

bash remediation for rule 'xccdf_org.ssgproject.content_rule_accounts_passwords_pam_faillock_interval' differs:
--- old datastream
+++ new datastream
@@ -28,6 +28,7 @@
 sed -Ei 's/(auth.*)(\[default=die\])(.*pam_faillock.so)/\1required \3/g' "$pam_file"
 done
 fi
+AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth")
 FAILLOCK_CONF="/etc/security/faillock.conf"
 if [ -f $FAILLOCK_CONF ]; then
 regex="^\s*fail_interval\s*="
@@ -35,10 +36,54 @@
 if ! grep -q $regex $FAILLOCK_CONF; then
 echo $line >> $FAILLOCK_CONF
 else
- sed -i --follow-symlinks 's/^\s*\(fail_interval\s*=\s*\)\([0-9]\+\)/\1'"$var_accounts_passwords_pam_faillock_fail_interval"'/g' $FAILLOCK_CONF
+ sed -i --follow-symlinks 's|^\s*\(fail_interval\s*=\s*\)\(\S\+\)|\1'"$var_accounts_passwords_pam_faillock_fail_interval"'|g' $FAILLOCK_CONF
 fi
+ for pam_file in "${AUTH_FILES[@]}"
+ do
+ 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
+ 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 "$pam_file")
+ PAM_FILE_PATH="/etc/authselect/$CURRENT_PROFILE/$PAM_FILE_NAME"
+ 
+ authselect apply-changes -b
+ fi
+ 
+ if grep -qP '^\s*auth\s.*\bpam_faillock.so\s.*\bfail_interval\b' "$PAM_FILE_PATH"; then
+ sed -i -E --follow-symlinks 's/(.*auth.*pam_faillock.so.*)\bfail_interval\b=?[[:alnum:]]*(.*)/\1\2/g' "$PAM_FILE_PATH"
+ fi
+ if [ -f /usr/bin/authselect ]; then
+ 
+ authselect apply-changes -b
+ fi
+ else
+ echo "$pam_file was not found" >&2
+ fi
+ done
 else
- AUTH_FILES=("/etc/pam.d/system-auth" "/etc/pam.d/password-auth")
 for pam_file in "${AUTH_FILES[@]}"
 do
 if ! grep -qE '^\s*auth.*pam_faillock.so (preauth|authfail).*fail_interval' "$pam_file"; then

ansible remediation for rule 'xccd

... The diff is trimmed here ...

@Mab879
Copy link
Member

Mab879 commented Jul 12, 2022

/ok-to-test

@openshift-ci openshift-ci bot added ok-to-test Used by openshift-ci bot. and removed needs-ok-to-test Used by openshift-ci bot. labels Jul 12, 2022
Copy link
Member

@marcusburghardt marcusburghardt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Xeicker . I just included some small comments.

Make them manage the edge cases:
    * When the user had set options in pam files, but faillock.conf
      was available
    * When the option is not a number
    * Remove pam option when the option doesn't have a value associated

Signed-off-by: Edgar Aguilar <edgar.aguilar@oracle.com>
These new tests validate the update on faillock macros

Signed-off-by: Edgar Aguilar <edgar.aguilar@oracle.com>
@marcusburghardt marcusburghardt self-assigned this Jul 15, 2022
@marcusburghardt marcusburghardt added the enhancement General enhancements to the project. label Jul 15, 2022
Copy link
Member

@marcusburghardt marcusburghardt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @Xeicker . I will just wait the tests to finish.

@marcusburghardt marcusburghardt added this to the 0.1.63 milestone Jul 15, 2022
@marcusburghardt marcusburghardt added Ansible Ansible remediation update. Bash Bash remediation update. labels Jul 15, 2022
@codeclimate
Copy link

codeclimate bot commented Jul 15, 2022

Code Climate has analyzed commit afa488d 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 42.7% (0.0% change).

View more on Code Climate.

@openshift-ci
Copy link

openshift-ci bot commented Jul 15, 2022

@Xeicker: The following tests failed, say /retest to rerun all failed tests or /retest-required to rerun all mandatory failed tests:

Test name Commit Details Required Rerun command
ci/prow/e2e-aws-ocp4-cis-node afa488d link true /test e2e-aws-ocp4-cis-node
ci/prow/e2e-aws-rhcos4-high afa488d link true /test e2e-aws-rhcos4-high
ci/prow/e2e-aws-rhcos4-moderate afa488d link true /test e2e-aws-rhcos4-moderate

Full PR test history. Your PR dashboard.

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here.

@marcusburghardt
Copy link
Member

Besides the CI tests I also tested critical PAM rules in local VMs and everything worked fine. Thanks @Xeicker

@marcusburghardt marcusburghardt merged commit e1545c4 into ComplianceAsCode:master Jul 15, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Ansible Ansible remediation update. Bash Bash remediation update. enhancement General enhancements to the project. ok-to-test Used by openshift-ci bot.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants