From 9ebba0cc3ea2a2d650a0a162185c1952aa54a746 Mon Sep 17 00:00:00 2001 From: ComplianceAsCode development team Date: Tue, 9 Aug 2022 11:01:33 -0400 Subject: [PATCH] Updated tasks/main.yml --- tasks/main.yml | 2760 +++++++++++++++++++++++++++++++++++------------- 1 file changed, 2005 insertions(+), 755 deletions(-) diff --git a/tasks/main.yml b/tasks/main.yml index 044855d..d7e4359 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -54,6 +54,7 @@ set_fact: package_manager_reinstall_cmd: dnf reinstall -y when: + - DISA_STIG_RHEL_07_010020 | bool - high_complexity | bool - high_severity | bool - medium_disruption | bool @@ -85,6 +86,7 @@ set_fact: package_manager_reinstall_cmd: yum reinstall -y when: + - DISA_STIG_RHEL_07_010020 | bool - high_complexity | bool - high_severity | bool - medium_disruption | bool @@ -121,6 +123,7 @@ failed_when: files_with_incorrect_hash.rc > 1 check_mode: false when: + - DISA_STIG_RHEL_07_010020 | bool - high_complexity | bool - high_severity | bool - medium_disruption | bool @@ -158,6 +161,7 @@ changed_when: false check_mode: false when: + - DISA_STIG_RHEL_07_010020 | bool - high_complexity | bool - high_severity | bool - medium_disruption | bool @@ -192,6 +196,7 @@ warn: false with_items: '{{ list_of_packages.results | map(attribute=''stdout_lines'') | list | unique }}' when: + - DISA_STIG_RHEL_07_010020 | bool - high_complexity | bool - high_severity | bool - medium_disruption | bool @@ -249,6 +254,7 @@ - restrict_strategy - rpm_verify_permissions when: + - DISA_STIG_RHEL_07_010010 | bool - high_complexity | bool - high_severity | bool - medium_disruption | bool @@ -266,6 +272,7 @@ changed_when: false check_mode: false when: + - DISA_STIG_RHEL_07_010010 | bool - high_complexity | bool - high_severity | bool - medium_disruption | bool @@ -300,6 +307,7 @@ warn: false with_items: '{{ list_of_packages.results | map(attribute=''stdout_lines'') | list | unique }}' when: + - DISA_STIG_RHEL_07_010010 | bool - high_complexity | bool - high_severity | bool - medium_disruption | bool @@ -333,6 +341,7 @@ name: aide state: present when: + - DISA_STIG_RHEL_07_020029 | bool - enable_strategy | bool - low_complexity | bool - low_disruption | bool @@ -460,6 +469,7 @@ with_items: - aide when: + - DISA_STIG_RHEL_07_020030 | bool - aide_periodic_cron_checking | bool - low_complexity | bool - low_disruption | bool @@ -486,6 +496,7 @@ set_fact: cron_pkg_name: cronie when: + - DISA_STIG_RHEL_07_020030 | bool - aide_periodic_cron_checking | bool - low_complexity | bool - low_disruption | bool @@ -513,6 +524,7 @@ set_fact: cron_pkg_name: cron when: + - DISA_STIG_RHEL_07_020030 | bool - aide_periodic_cron_checking | bool - low_complexity | bool - low_disruption | bool @@ -541,6 +553,7 @@ name: '{{ cron_pkg_name }}' state: present when: + - DISA_STIG_RHEL_07_020030 | bool - aide_periodic_cron_checking | bool - low_complexity | bool - low_disruption | bool @@ -572,6 +585,7 @@ user: root job: /usr/sbin/aide --check when: + - DISA_STIG_RHEL_07_020030 | bool - aide_periodic_cron_checking | bool - low_complexity | bool - low_disruption | bool @@ -612,6 +626,7 @@ - no_reboot_needed - unknown_strategy when: + - DISA_STIG_RHEL_07_010100 | bool - dconf_gnome_screensaver_idle_activation_enabled | bool - low_complexity | bool - medium_disruption | bool @@ -628,6 +643,7 @@ create: true no_extra_spaces: true when: + - DISA_STIG_RHEL_07_010100 | bool - dconf_gnome_screensaver_idle_activation_enabled | bool - low_complexity | bool - medium_disruption | bool @@ -658,6 +674,7 @@ line: /org/gnome/desktop/screensaver/idle-activation-enabled create: true when: + - DISA_STIG_RHEL_07_010100 | bool - dconf_gnome_screensaver_idle_activation_enabled | bool - low_complexity | bool - medium_disruption | bool @@ -684,6 +701,7 @@ - name: Dconf Update command: dconf update when: + - DISA_STIG_RHEL_07_010100 | bool - dconf_gnome_screensaver_idle_activation_enabled | bool - low_complexity | bool - medium_disruption | bool @@ -725,6 +743,7 @@ - no_reboot_needed - unknown_strategy when: + - DISA_STIG_RHEL_07_010070 | bool - dconf_gnome_screensaver_idle_delay | bool - low_complexity | bool - medium_disruption | bool @@ -741,6 +760,7 @@ create: true no_extra_spaces: true when: + - DISA_STIG_RHEL_07_010070 | bool - dconf_gnome_screensaver_idle_delay | bool - low_complexity | bool - medium_disruption | bool @@ -767,6 +787,7 @@ - name: Dconf Update command: dconf update when: + - DISA_STIG_RHEL_07_010070 | bool - dconf_gnome_screensaver_idle_delay | bool - low_complexity | bool - medium_disruption | bool @@ -807,6 +828,7 @@ - no_reboot_needed - unknown_strategy when: + - DISA_STIG_RHEL_07_010060 | bool - dconf_gnome_screensaver_lock_enabled | bool - low_complexity | bool - medium_disruption | bool @@ -817,6 +839,7 @@ - name: Dconf Update command: dconf update when: + - DISA_STIG_RHEL_07_010060 | bool - dconf_gnome_screensaver_lock_enabled | bool - low_complexity | bool - medium_disruption | bool @@ -849,6 +872,7 @@ create: true no_extra_spaces: true when: + - DISA_STIG_RHEL_07_010060 | bool - dconf_gnome_screensaver_lock_enabled | bool - low_complexity | bool - medium_disruption | bool @@ -857,6 +881,7 @@ - unknown_strategy | bool - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ansible_distribution != 'SLES' tags: - CCE-80112-6 - CJIS-5.5.5 @@ -878,6 +903,7 @@ line: /org/gnome/desktop/screensaver/lock-enabled create: true when: + - DISA_STIG_RHEL_07_010060 | bool - dconf_gnome_screensaver_lock_enabled | bool - low_complexity | bool - medium_disruption | bool @@ -886,6 +912,71 @@ - unknown_strategy | bool - '"gdm" in ansible_facts.packages' - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ansible_distribution != 'SLES' + tags: + - CCE-80112-6 + - CJIS-5.5.5 + - DISA-STIG-RHEL-07-010060 + - NIST-800-171-3.1.10 + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.1.8 + - dconf_gnome_screensaver_lock_enabled + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - unknown_strategy + +- name: Enable GNOME3 Screensaver Lock After Idle Period + ini_file: + dest: /etc/dconf/db/local.d/00-security-settings + section: org/gnome/desktop/lockdown + option: disable-lock-screen + value: 'false' + create: true + no_extra_spaces: true + when: + - DISA_STIG_RHEL_07_010060 | bool + - dconf_gnome_screensaver_lock_enabled | bool + - low_complexity | bool + - medium_disruption | bool + - medium_severity | bool + - no_reboot_needed | bool + - unknown_strategy | bool + - '"gdm" in ansible_facts.packages' + - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ansible_distribution == 'SLES' + tags: + - CCE-80112-6 + - CJIS-5.5.5 + - DISA-STIG-RHEL-07-010060 + - NIST-800-171-3.1.10 + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.1.8 + - dconf_gnome_screensaver_lock_enabled + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - unknown_strategy + +- name: Prevent user modification of GNOME disable-lock-screen + lineinfile: + path: /etc/dconf/db/local.d/locks/00-security-settings-lock + regexp: ^/org/gnome/desktop/lockdown/disable-lock-screen$ + line: /org/gnome/desktop/lockdown/disable-lock-screen + create: true + when: + - DISA_STIG_RHEL_07_010060 | bool + - dconf_gnome_screensaver_lock_enabled | bool + - low_complexity | bool + - medium_disruption | bool + - medium_severity | bool + - no_reboot_needed | bool + - unknown_strategy | bool + - '"gdm" in ansible_facts.packages' + - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - ansible_distribution == 'SLES' tags: - CCE-80112-6 - CJIS-5.5.5 @@ -904,6 +995,7 @@ command: gsettings get org.gnome.desktop.lockdown disable-lock-screen register: cmd_out when: + - DISA_STIG_RHEL_07_010060 | bool - dconf_gnome_screensaver_lock_enabled | bool - low_complexity | bool - medium_disruption | bool @@ -930,6 +1022,7 @@ - name: Update GNOME3 screenserver disable-lock-screen false command: gsettings set org.gnome.desktop.lockdown disable-lock-screen false when: + - DISA_STIG_RHEL_07_010060 | bool - dconf_gnome_screensaver_lock_enabled | bool - low_complexity | bool - medium_disruption | bool @@ -956,6 +1049,7 @@ - name: Dconf Update command: dconf update when: + - DISA_STIG_RHEL_07_010060 | bool - dconf_gnome_screensaver_lock_enabled | bool - low_complexity | bool - medium_disruption | bool @@ -1116,6 +1210,7 @@ - medium_disruption - no_reboot_needed when: + - DISA_STIG_RHEL_07_020050 | bool - configure_strategy | bool - ensure_gpgcheck_globally_activated | bool - high_severity | bool @@ -1132,6 +1227,7 @@ no_extra_spaces: true create: false when: + - DISA_STIG_RHEL_07_020050 | bool - configure_strategy | bool - ensure_gpgcheck_globally_activated | bool - high_severity | bool @@ -1402,6 +1498,7 @@ - security_patches_up_to_date - skip_ansible_lint when: + - DISA_STIG_RHEL_07_020260 | bool - high_disruption | bool - low_complexity | bool - medium_severity | bool @@ -1427,6 +1524,7 @@ - low_severity - no_reboot_needed when: + - DISA_STIG_RHEL_07_040530 | bool - configure_strategy | bool - display_login_attempts | bool - low_complexity | bool @@ -1434,42 +1532,12 @@ - low_severity | bool - no_reboot_needed | bool -- name: Check for expected pam_lastlog.so entry - ansible.builtin.lineinfile: - path: /etc/pam.d/postlogin - create: false - regexp: ^\s*session.*required.*pam_lastlog.so\s\+showfailed\s*$ - state: absent - check_mode: true - changed_when: false - register: result_pam_lastlog_present - when: - - configure_strategy | bool - - display_login_attempts | bool - - low_complexity | bool - - low_disruption | bool - - low_severity | bool - - no_reboot_needed | bool - - '"pam" in ansible_facts.packages' - tags: - - CCE-27275-7 - - CJIS-5.5.2 - - DISA-STIG-RHEL-07-040530 - - NIST-800-53-AC-9(1) - - NIST-800-53-CM-6(a) - - PCI-DSS-Req-10.2.4 - - configure_strategy - - display_login_attempts - - low_complexity - - low_disruption - - low_severity - - no_reboot_needed - -- name: Check if system relies on authselect +- name: Ensure PAM Displays Last Logon/Access Notification - Check if /etc/pam.d/postlogin file is present ansible.builtin.stat: - path: /usr/bin/authselect - register: result_authselect_present + path: /etc/pam.d/postlogin + register: result_pam_file_present when: + - DISA_STIG_RHEL_07_040530 | bool - configure_strategy | bool - display_login_attempts | bool - low_complexity | bool @@ -1491,116 +1559,197 @@ - low_severity - no_reboot_needed -- name: Remediation where authselect tool is present +- name: Ensure PAM Displays Last Logon/Access Notification - Check the proper remediation for the system block: - - name: Check the integrity of the current authselect profile - ansible.builtin.command: - cmd: authselect check - register: result_authselect_check_cmd - changed_when: false - ignore_errors: true - - name: 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 the authselect profile is not intact. - - It is not recommended to manually edit the PAM files when authselect 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: 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: Define the current authselect profile as a local fact + - name: Ensure PAM Displays Last Logon/Access Notification - Define the PAM file to be edited 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: 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 + pam_file_path: /etc/pam.d/postlogin + - name: Ensure PAM Displays Last Logon/Access Notification - Check if system relies on authselect + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + - name: Ensure PAM Displays Last Logon/Access Notification - Remediate using authselect + block: + - name: Ensure PAM Displays Last Logon/Access Notification - Check integrity of authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + ignore_errors: true + - name: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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_profile is not skipped - - result_authselect_profile.stdout is not match("custom/") - - name: 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 + - result_authselect_present.stat.exists + - name: Ensure PAM Displays Last Logon/Access Notification - Check if expected PAM module line is present in {{ pam_file_path + }} + ansible.builtin.lineinfile: + path: '{{ pam_file_path }}' + regexp: ^\s*session\s+required\s+pam_lastlog.so\s*.* + state: absent + check_mode: true changed_when: false + register: result_pam_line_present + - name: Ensure PAM Displays Last Logon/Access Notification - Include or update the PAM module line in {{ pam_file_path }} + block: + - name: Ensure PAM Displays Last Logon/Access Notification - Check if required PAM module line is present in {{ pam_file_path + }} with different control + ansible.builtin.lineinfile: + path: '{{ pam_file_path }}' + regexp: ^\s*session\s+.*\s+pam_lastlog.so\s* + state: absent + check_mode: true + changed_when: false + register: result_pam_line_other_control_present + - name: Ensure PAM Displays Last Logon/Access Notification - Ensure the correct control for the required PAM module line + in {{ pam_file_path }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: ^(\s*session\s+).*(\bpam_lastlog.so.*) + replace: \1required \2 + register: result_pam_module_edit + when: + - result_pam_line_other_control_present.found == 1 + - name: Ensure PAM Displays Last Logon/Access Notification - Ensure the required PAM module line is included in {{ pam_file_path + }} + ansible.builtin.lineinfile: + dest: '{{ pam_file_path }}' + insertafter: BOF + line: session required pam_lastlog.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: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - (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_authselect_profile is not skipped - - authselect_current_profile is not match("custom/") - - name: Check if any custom profile with the same name was already created in the past - ansible.builtin.stat: - path: /etc/authselect/{{ authselect_custom_profile }} - register: result_authselect_custom_profile_present + - result_pam_line_present.found is defined + - result_pam_line_present.found == 0 + - name: Ensure PAM Displays Last Logon/Access Notification - Check if the required PAM module option is present in {{ pam_file_path + }} + ansible.builtin.lineinfile: + path: '{{ pam_file_path }}' + regexp: ^\s*session\s+required\s+pam_lastlog.so\s*.*\sshowfailed\b + state: absent + check_mode: true changed_when: false - when: - - authselect_current_profile is not match("custom/") - - name: Create a custom profile based on the current profile - ansible.builtin.command: - cmd: authselect create-profile hardening -b sssd - when: - - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") - - not result_authselect_custom_profile_present.stat.exists - - name: Ensure the silent option is not present in the custom profile - ansible.builtin.replace: - dest: /etc/authselect/{{ authselect_custom_profile }}/postlogin - regexp: ^(session.*required.*pam_lastlog.so).*$ - replace: \g<1> showfailed - when: - - result_authselect_profile is not skipped - - name: Ensure the desired configuration is present in the custom profile + register: result_pam_module_showfailed_option_present + - name: Ensure PAM Displays Last Logon/Access Notification - Ensure the "showfailed" PAM option for "pam_lastlog.so" is + included in {{ pam_file_path }} ansible.builtin.lineinfile: - dest: /etc/authselect/{{ authselect_custom_profile }}/postlogin - insertbefore: ^session.* - firstmatch: true - line: session required pam_lastlog.so showfailed - when: - - result_authselect_profile is not skipped - - name: Ensure a backup of current authselect profile before selecting the custom profile - ansible.builtin.command: - cmd: authselect apply-changes -b --backup=before-pwhistory-hardening.backup - register: result_authselect_backup - 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: Ensure the custom profile is selected - ansible.builtin.command: - cmd: authselect select {{ authselect_custom_profile }} --force - 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: Restore the authselect features in the custom profile - ansible.builtin.command: - cmd: authselect enable-feature {{ item }} - loop: '{{ result_authselect_features.stdout_lines }}' + path: '{{ pam_file_path }}' + backrefs: true + regexp: ^(\s*session\s+required\s+pam_lastlog.so.*) + line: \1 showfailed + state: present + register: result_pam_showfailed_add when: - - result_authselect_profile is not skipped - - result_authselect_features is not skipped - - result_pam_authselect_select_profile is not skipped - - name: Ensure the custom profile changes are applied + - result_pam_module_showfailed_option_present.found == 0 + - name: Ensure PAM Displays Last Logon/Access Notification - Ensure authselect changes are applied ansible.builtin.command: - cmd: authselect apply-changes -b --backup=after-pwhistory-hardening.backup + cmd: authselect apply-changes -b when: - - result_authselect_check_cmd is success - - result_authselect_profile is not skipped + - result_authselect_present.stat.exists + - (result_pam_showfailed_add is defined and result_pam_showfailed_add.changed) or (result_pam_showfailed_edit is defined + and result_pam_showfailed_edit.changed) when: + - DISA_STIG_RHEL_07_040530 | bool - configure_strategy | bool - display_login_attempts | bool - low_complexity | bool @@ -1608,8 +1757,7 @@ - low_severity | bool - no_reboot_needed | bool - '"pam" in ansible_facts.packages' - - result_pam_lastlog_present.found == 0 - - result_authselect_present.stat.exists + - result_pam_file_present.stat.exists tags: - CCE-27275-7 - CJIS-5.5.2 @@ -1624,20 +1772,12 @@ - low_severity - no_reboot_needed -- name: Remediation where authselect tool is not present and PAM files are directly edited - block: - - name: Ensure the silent option is not present in PAM files - ansible.builtin.replace: - dest: /etc/pam.d/postlogin - regexp: ^(session.*required.*pam_lastlog.so).*$ - replace: \g<1> showfailed - - name: Ensure the desired configuration is present in PAM files - ansible.builtin.lineinfile: - dest: /etc/pam.d/postlogin - insertbefore: ^session.* - firstmatch: true - line: session required pam_lastlog.so showfailed +- name: Ensure PAM Displays Last Logon/Access Notification - Check if /etc/pam.d/postlogin file is present + ansible.builtin.stat: + path: /etc/pam.d/postlogin + register: result_pam_file_present when: + - DISA_STIG_RHEL_07_040530 | bool - configure_strategy | bool - display_login_attempts | bool - low_complexity | bool @@ -1645,8 +1785,6 @@ - low_severity | bool - no_reboot_needed | bool - '"pam" in ansible_facts.packages' - - result_pam_lastlog_present.found == 0 - - not result_authselect_present.stat.exists tags: - CCE-27275-7 - CJIS-5.5.2 @@ -1661,449 +1799,164 @@ - low_severity - no_reboot_needed -- name: Gather the package facts - package_facts: - manager: auto - tags: - - CCE-82030-8 - - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - - 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_unix_remember - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - when: - - accounts_password_pam_unix_remember | bool - - configure_strategy | bool - - low_complexity | bool - - medium_disruption | bool - - medium_severity | bool - - no_reboot_needed | bool - -- name: Check if system relies on authselect - ansible.builtin.stat: - path: /usr/bin/authselect - register: result_authselect_present - when: - - accounts_password_pam_unix_remember | bool - - configure_strategy | bool - - low_complexity | bool - - medium_disruption | bool - - medium_severity | bool - - no_reboot_needed | bool - - '"pam" in ansible_facts.packages' - tags: - - CCE-82030-8 - - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - - 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_unix_remember - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - -- name: Check the integrity of the current authselect profile - ansible.builtin.command: - cmd: authselect check - register: result_authselect_check_cmd - changed_when: false - ignore_errors: true - when: - - accounts_password_pam_unix_remember | bool - - configure_strategy | bool - - low_complexity | bool - - medium_disruption | bool - - medium_severity | bool - - no_reboot_needed | bool - - '"pam" in ansible_facts.packages' - - result_authselect_present.stat.exists - tags: - - CCE-82030-8 - - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - - 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_unix_remember - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - -- name: 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 the authselect profile is not intact. - - It is not recommended to manually edit the PAM files when authselect is available - - In cases where the default authselect profile does not cover a specific demand, a custom authselect profile is recommended. - success_msg: - - authselect integrity check passed - when: - - accounts_password_pam_unix_remember | bool - - configure_strategy | bool - - low_complexity | bool - - medium_disruption | bool - - medium_severity | bool - - no_reboot_needed | bool - - '"pam" in ansible_facts.packages' - tags: - - CCE-82030-8 - - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - - 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_unix_remember - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - -- name: Get authselect current profile - ansible.builtin.shell: - cmd: authselect current -r | awk '{ print $1 }' - register: result_authselect_profile - changed_when: false - when: - - accounts_password_pam_unix_remember | bool - - configure_strategy | bool - - low_complexity | bool - - medium_disruption | bool - - medium_severity | bool - - no_reboot_needed | bool - - '"pam" in ansible_facts.packages' - - result_authselect_present.stat.exists - - result_authselect_check_cmd is success - tags: - - CCE-82030-8 - - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - - 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_unix_remember - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - -- name: 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: - - accounts_password_pam_unix_remember | bool - - configure_strategy | bool - - low_complexity | bool - - medium_disruption | bool - - medium_severity | bool - - no_reboot_needed | bool - - '"pam" in ansible_facts.packages' - - result_authselect_profile is not skipped - - result_authselect_profile.stdout is match("custom/") - tags: - - CCE-82030-8 - - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - - 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_unix_remember - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - -- name: 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: - - accounts_password_pam_unix_remember | bool - - configure_strategy | bool - - low_complexity | bool - - medium_disruption | bool - - medium_severity | bool - - no_reboot_needed | bool - - '"pam" in ansible_facts.packages' - - result_authselect_profile is not skipped - - result_authselect_profile.stdout is not match("custom/") - tags: - - CCE-82030-8 - - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - - 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_unix_remember - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - -- name: 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: - - accounts_password_pam_unix_remember | bool - - configure_strategy | bool - - low_complexity | bool - - medium_disruption | bool - - medium_severity | bool - - no_reboot_needed | bool - - '"pam" in ansible_facts.packages' - - result_authselect_profile is not skipped - - authselect_current_profile is not match("custom/") - tags: - - CCE-82030-8 - - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - - 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_unix_remember - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - -- name: Check if any custom profile with the same name was already created in the past - ansible.builtin.stat: - path: /etc/authselect/{{ authselect_custom_profile }} - register: result_authselect_custom_profile_present - changed_when: false - when: - - accounts_password_pam_unix_remember | bool - - configure_strategy | bool - - low_complexity | bool - - medium_disruption | bool - - medium_severity | bool - - no_reboot_needed | bool - - '"pam" in ansible_facts.packages' - - result_authselect_present.stat.exists - - authselect_current_profile is not match("custom/") - tags: - - CCE-82030-8 - - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - - 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_unix_remember - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - -- name: Create a custom profile based on the current profile - ansible.builtin.command: - cmd: authselect create-profile hardening -b sssd - register: result_authselect_create_profile - when: - - accounts_password_pam_unix_remember | bool - - configure_strategy | bool - - low_complexity | bool - - medium_disruption | bool - - medium_severity | bool - - no_reboot_needed | bool - - '"pam" in ansible_facts.packages' - - result_authselect_present.stat.exists - - result_authselect_check_cmd is success - - authselect_current_profile is not match("custom/") - - not result_authselect_custom_profile_present.stat.exists - tags: - - CCE-82030-8 - - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - - 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_unix_remember - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure the desired configuration is updated in the custom profile - ansible.builtin.replace: - dest: '{{ item }}' - regexp: (.*pam_pwhistory.so.*remember=)(\S+)(.*)$ - replace: \g<1>{{ var_password_pam_unix_remember }}\g<3> - loop: - - /etc/authselect/{{ authselect_custom_profile }}/system-auth - - /etc/authselect/{{ authselect_custom_profile }}/password-auth - when: - - accounts_password_pam_unix_remember | bool - - configure_strategy | bool - - low_complexity | bool - - medium_disruption | bool - - medium_severity | bool - - no_reboot_needed | bool - - '"pam" in ansible_facts.packages' - - result_authselect_profile is not skipped - - authselect_custom_profile is match("custom/") - tags: - - CCE-82030-8 - - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - - 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_unix_remember - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure the desired configuration in present in the custom profile - ansible.builtin.lineinfile: - dest: '{{ item }}' - insertafter: ^password.*requisite.*pam_pwquality.so.* - line: password requisite pam_pwhistory.so remember={{ var_password_pam_unix_remember }} use_authtok - loop: - - /etc/authselect/{{ authselect_custom_profile }}/system-auth - - /etc/authselect/{{ authselect_custom_profile }}/password-auth - when: - - accounts_password_pam_unix_remember | bool - - configure_strategy | bool - - low_complexity | bool - - medium_disruption | bool - - medium_severity | bool - - no_reboot_needed | bool - - '"pam" in ansible_facts.packages' - - result_authselect_profile is not skipped - - authselect_custom_profile is match("custom/") - tags: - - CCE-82030-8 - - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - - 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_unix_remember - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure a backup of current authselect profile before select the custom profile - ansible.builtin.command: - cmd: authselect apply-changes -b --backup=before-pwhistory-hardening.backup - register: result_authselect_backup - when: - - accounts_password_pam_unix_remember | bool - - configure_strategy | bool - - low_complexity | bool - - medium_disruption | bool - - medium_severity | bool - - no_reboot_needed | bool - - '"pam" in ansible_facts.packages' - - result_authselect_check_cmd is success - - result_authselect_profile is not skipped - - authselect_current_profile is not match("custom/") - - authselect_custom_profile is not match(authselect_current_profile) - tags: - - CCE-82030-8 - - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - - 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_unix_remember - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed - -- name: Ensure the custom profile is selected - ansible.builtin.command: - cmd: authselect select {{ authselect_custom_profile }} --force - register: result_pam_authselect_select_profile +- name: Ensure PAM Displays Last Logon/Access Notification - Check the proper remediation for the system + block: + - name: Ensure PAM Displays Last Logon/Access Notification - Define the PAM file to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/postlogin + - name: Ensure PAM Displays Last Logon/Access Notification - Check if system relies on authselect + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + - name: Ensure PAM Displays Last Logon/Access Notification - Remediate using authselect + block: + - name: Ensure PAM Displays Last Logon/Access Notification - Check integrity of authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + ignore_errors: true + - name: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - 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: Ensure PAM Displays Last Logon/Access Notification - Ensure the "silent" option from "pam_lastlog.so" is not present + in {{ pam_file_path }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*session.*pam_lastlog.so.*)\bsilent\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + - name: Ensure PAM Displays Last Logon/Access Notification - 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: - - accounts_password_pam_unix_remember | bool + - DISA_STIG_RHEL_07_040530 | bool - configure_strategy | bool + - display_login_attempts | bool - low_complexity | bool - - medium_disruption | bool - - medium_severity | bool + - low_disruption | bool + - low_severity | bool - no_reboot_needed | bool - '"pam" in ansible_facts.packages' - - result_authselect_check_cmd is success - - result_authselect_profile is not skipped - - authselect_current_profile is not match("custom/") - - authselect_custom_profile is not match(authselect_current_profile) + - result_pam_file_present.stat.exists tags: - - CCE-82030-8 - - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - - 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_unix_remember + - CCE-27275-7 + - CJIS-5.5.2 + - DISA-STIG-RHEL-07-040530 + - NIST-800-53-AC-9(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.2.4 - configure_strategy + - display_login_attempts - low_complexity - - medium_disruption - - medium_severity + - low_disruption + - low_severity - no_reboot_needed -- name: Restore the authselect features in the custom profile - ansible.builtin.command: - cmd: authselect enable-feature {{ item }} - register: result_pam_authselect_select_features - loop: '{{ result_authselect_features.stdout_lines }}' - when: - - accounts_password_pam_unix_remember | bool - - configure_strategy | bool - - low_complexity | bool - - medium_disruption | bool - - medium_severity | bool - - no_reboot_needed | bool - - '"pam" in ansible_facts.packages' - - result_authselect_profile is not skipped - - result_authselect_features is not skipped - - result_pam_authselect_select_profile is not skipped +- name: Gather the package facts + package_facts: + manager: auto tags: - CCE-82030-8 - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - NIST-800-171-3.5.8 - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) @@ -2114,10 +1967,6 @@ - medium_disruption - medium_severity - no_reboot_needed - -- name: Ensure the custom profile changes are applied - ansible.builtin.command: - cmd: authselect apply-changes -b --backup=after-pwhistory-hardening.backup when: - accounts_password_pam_unix_remember | bool - configure_strategy | bool @@ -2125,29 +1974,11 @@ - medium_disruption | bool - medium_severity | bool - no_reboot_needed | bool - - '"pam" in ansible_facts.packages' - - result_authselect_check_cmd is success - - result_authselect_profile is not skipped - tags: - - CCE-82030-8 - - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - - 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_unix_remember - - configure_strategy - - low_complexity - - medium_disruption - - medium_severity - - no_reboot_needed -- name: Do not allow users to reuse recent passwords - system-auth (change) - replace: - dest: /etc/pam.d/system-auth - regexp: ^(password\s+sufficient\s+pam_unix\.so\s.*remember\s*=\s*)(\S+)(.*)$ - replace: \g<1>{{ var_password_pam_unix_remember }}\g<3> +- name: Limit Password Reuse - Check if /etc/pam.d/system-auth file is present + ansible.builtin.stat: + path: /etc/pam.d/system-auth + register: result_pam_file_present when: - accounts_password_pam_unix_remember | bool - configure_strategy | bool @@ -2156,11 +1987,9 @@ - medium_severity | bool - no_reboot_needed | bool - '"pam" in ansible_facts.packages' - - not result_authselect_present.stat.exists tags: - CCE-82030-8 - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - NIST-800-171-3.5.8 - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) @@ -2172,11 +2001,194 @@ - medium_severity - no_reboot_needed -- name: Do not allow users to reuse recent passwords - system-auth (add) - replace: - dest: /etc/pam.d/system-auth - regexp: ^password\s+sufficient\s+pam_unix\.so\s(?!.*remember\s*=\s*).*$ - replace: \g<0> remember={{ var_password_pam_unix_remember }} +- name: Limit Password Reuse - Check the proper remediation for the system + block: + - name: Limit Password Reuse - Define the PAM file to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/system-auth + - name: Limit Password Reuse - Check if system relies on authselect + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + - name: Limit Password Reuse - Remediate using authselect + block: + - name: Limit Password Reuse - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - Include or update the PAM module line in {{ pam_file_path }} + block: + - name: Limit Password Reuse - 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 - 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 - Ensure the required PAM module line is included in {{ pam_file_path }} + ansible.builtin.lineinfile: + dest: '{{ pam_file_path }}' + insertafter: ^password.*requisite.*pam_pwquality.so + 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 - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - (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 - 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 - 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_unix_remember }} + state: present + register: result_pam_remember_add + when: + - result_pam_module_remember_option_present.found == 0 + - name: Limit Password Reuse - 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_unix_remember }} \3 + register: result_pam_remember_edit + when: + - result_pam_module_remember_option_present.found > 0 + - name: Limit Password Reuse - 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: - accounts_password_pam_unix_remember | bool - configure_strategy | bool @@ -2185,11 +2197,10 @@ - medium_severity | bool - no_reboot_needed | bool - '"pam" in ansible_facts.packages' - - not result_authselect_present.stat.exists + - result_pam_file_present.stat.exists tags: - CCE-82030-8 - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - NIST-800-171-3.5.8 - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) @@ -2201,11 +2212,10 @@ - medium_severity - no_reboot_needed -- name: Do not allow users to reuse recent passwords - system-auth (change) - replace: - dest: /etc/pam.d/system-auth - regexp: ^(password\s+(?:(?:requisite)|(?:required))\s+pam_pwhistory\.so\s.*remember\s*=\s*)(\S+)(.*)$ - replace: \g<1>{{ var_password_pam_unix_remember }}\g<3> +- name: Limit Password Reuse - Check if /etc/pam.d/password-auth file is present + ansible.builtin.stat: + path: /etc/pam.d/password-auth + register: result_pam_file_present when: - accounts_password_pam_unix_remember | bool - configure_strategy | bool @@ -2214,11 +2224,9 @@ - medium_severity | bool - no_reboot_needed | bool - '"pam" in ansible_facts.packages' - - not result_authselect_present.stat.exists tags: - CCE-82030-8 - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - NIST-800-171-3.5.8 - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) @@ -2230,11 +2238,194 @@ - medium_severity - no_reboot_needed -- name: Do not allow users to reuse recent passwords - system-auth (add) - replace: - dest: /etc/pam.d/system-auth - regexp: ^password\s+(?:(?:requisite)|(?:required))\s+pam_pwhistory\.so\s(?!.*remember\s*=\s*).*$ - replace: \g<0> remember={{ var_password_pam_unix_remember }} +- name: Limit Password Reuse - Check the proper remediation for the system + block: + - name: Limit Password Reuse - 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 - Check if system relies on authselect + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + - name: Limit Password Reuse - Remediate using authselect + block: + - name: Limit Password Reuse - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - 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 - Include or update the PAM module line in {{ pam_file_path }} + block: + - name: Limit Password Reuse - 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 - 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 - Ensure the required PAM module line is included in {{ pam_file_path }} + ansible.builtin.lineinfile: + dest: '{{ pam_file_path }}' + insertafter: ^password.*requisite.*pam_pwquality.so + 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 - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - (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 - 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 - 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_unix_remember }} + state: present + register: result_pam_remember_add + when: + - result_pam_module_remember_option_present.found == 0 + - name: Limit Password Reuse - 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_unix_remember }} \3 + register: result_pam_remember_edit + when: + - result_pam_module_remember_option_present.found > 0 + - name: Limit Password Reuse - 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: - accounts_password_pam_unix_remember | bool - configure_strategy | bool @@ -2243,11 +2434,10 @@ - medium_severity | bool - no_reboot_needed | bool - '"pam" in ansible_facts.packages' - - not result_authselect_present.stat.exists + - result_pam_file_present.stat.exists tags: - CCE-82030-8 - CJIS-5.6.2.1.1 - - DISA-STIG-RHEL-07-010270 - NIST-800-171-3.5.8 - NIST-800-53-IA-5(1)(e) - NIST-800-53-IA-5(f) @@ -2277,6 +2467,7 @@ - no_reboot_needed - restrict_strategy when: + - DISA_STIG_RHEL_07_010320 | bool - accounts_passwords_pam_faillock_deny | bool - low_complexity | bool - low_disruption | bool @@ -2289,6 +2480,7 @@ path: /usr/bin/authselect register: result_authselect_present when: + - DISA_STIG_RHEL_07_010320 | bool - accounts_passwords_pam_faillock_deny | bool - low_complexity | bool - low_disruption | bool @@ -2338,14 +2530,21 @@ changed_when: false when: - result_authselect_check_cmd is success - - name: Lock Accounts After Failed Password Attempts - Ensure with-faillock feature is enabled using authselect tool + - name: Lock Accounts After Failed Password Attempts - Ensure "with-faillock" feature is enabled using authselect tool ansible.builtin.command: cmd: authselect enable-feature with-faillock - register: result_authselect_cmd + register: result_authselect_enable_feature_cmd when: - result_authselect_check_cmd is success - result_authselect_features.stdout is not search("with-faillock") + - name: Lock Accounts After Failed Password Attempts - 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: + - DISA_STIG_RHEL_07_010320 | bool - accounts_passwords_pam_faillock_deny | bool - low_complexity | bool - low_disruption | bool @@ -2394,7 +2593,7 @@ ansible.builtin.lineinfile: path: '{{ item }}' line: auth required pam_faillock.so authfail - insertafter: ^auth.*sufficient.*pam_unix.so.* + insertbefore: ^auth.*required.*pam_deny.so.* state: present loop: - /etc/pam.d/system-auth @@ -2413,6 +2612,7 @@ when: - result_pam_faillock_is_enabled.found == 0 when: + - DISA_STIG_RHEL_07_010320 | bool - accounts_passwords_pam_faillock_deny | bool - low_complexity | bool - low_disruption | bool @@ -2441,6 +2641,7 @@ path: /etc/security/faillock.conf register: result_faillock_conf_check when: + - DISA_STIG_RHEL_07_010320 | bool - accounts_passwords_pam_faillock_deny | bool - low_complexity | bool - low_disruption | bool @@ -2470,6 +2671,298 @@ line: deny = {{ var_accounts_passwords_pam_faillock_deny }} state: present when: + - DISA_STIG_RHEL_07_010320 | bool + - accounts_passwords_pam_faillock_deny | bool + - low_complexity | bool + - low_disruption | bool + - medium_severity | bool + - no_reboot_needed | bool + - restrict_strategy | bool + - '"pam" in ansible_facts.packages' + - result_faillock_conf_check.stat.exists + tags: + - CCE-27350-8 + - CJIS-5.5.3 + - DISA-STIG-RHEL-07-010320 + - 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 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: + - DISA_STIG_RHEL_07_010320 | bool - accounts_passwords_pam_faillock_deny | bool - low_complexity | bool - low_disruption | bool @@ -2557,6 +3050,7 @@ when: - result_pam_faillock_deny_parameter_is_present.found > 0 when: + - DISA_STIG_RHEL_07_010320 | bool - accounts_passwords_pam_faillock_deny | bool - low_complexity | bool - low_disruption | bool @@ -2598,6 +3092,7 @@ - no_reboot_needed - restrict_strategy when: + - DISA_STIG_RHEL_07_010320 | bool - accounts_passwords_pam_faillock_unlock_time | bool - low_complexity | bool - low_disruption | bool @@ -2610,6 +3105,7 @@ path: /usr/bin/authselect register: result_authselect_present when: + - DISA_STIG_RHEL_07_010320 | bool - accounts_passwords_pam_faillock_unlock_time | bool - low_complexity | bool - low_disruption | bool @@ -2659,14 +3155,21 @@ changed_when: false when: - result_authselect_check_cmd is success - - name: Set Lockout Time for Failed Password Attempts - Ensure with-faillock feature is enabled using authselect tool + - name: Set Lockout Time for Failed Password Attempts - Ensure "with-faillock" feature is enabled using authselect tool ansible.builtin.command: cmd: authselect enable-feature with-faillock - register: result_authselect_cmd + register: result_authselect_enable_feature_cmd when: - result_authselect_check_cmd is success - result_authselect_features.stdout is not search("with-faillock") + - name: Set Lockout Time for Failed Password Attempts - 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: + - DISA_STIG_RHEL_07_010320 | bool - accounts_passwords_pam_faillock_unlock_time | bool - low_complexity | bool - low_disruption | bool @@ -2715,7 +3218,7 @@ ansible.builtin.lineinfile: path: '{{ item }}' line: auth required pam_faillock.so authfail - insertafter: ^auth.*sufficient.*pam_unix.so.* + insertbefore: ^auth.*required.*pam_deny.so.* state: present loop: - /etc/pam.d/system-auth @@ -2734,6 +3237,7 @@ when: - result_pam_faillock_is_enabled.found == 0 when: + - DISA_STIG_RHEL_07_010320 | bool - accounts_passwords_pam_faillock_unlock_time | bool - low_complexity | bool - low_disruption | bool @@ -2762,6 +3266,7 @@ path: /etc/security/faillock.conf register: result_faillock_conf_check when: + - DISA_STIG_RHEL_07_010320 | bool - accounts_passwords_pam_faillock_unlock_time | bool - low_complexity | bool - low_disruption | bool @@ -2791,6 +3296,300 @@ line: unlock_time = {{ var_accounts_passwords_pam_faillock_unlock_time }} state: present when: + - DISA_STIG_RHEL_07_010320 | bool + - accounts_passwords_pam_faillock_unlock_time | bool + - low_complexity | bool + - low_disruption | bool + - medium_severity | bool + - no_reboot_needed | bool + - restrict_strategy | bool + - '"pam" in ansible_facts.packages' + - result_faillock_conf_check.stat.exists + tags: + - CCE-26884-7 + - CJIS-5.5.3 + - DISA-STIG-RHEL-07-010320 + - NIST-800-171-3.1.8 + - NIST-800-53-AC-7(b) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-8.1.7 + - accounts_passwords_pam_faillock_unlock_time + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + +- name: Set Lockout Time for Failed Password Attempts - Ensure the pam_faillock.so unlock_time parameter not in PAM files + block: + - name: Set Lockout Time 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: Set Lockout Time for Failed Password Attempts - Check the proper remediation for the system + block: + - name: Set Lockout Time 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: Set Lockout Time for Failed Password Attempts - Check if system relies on authselect + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + - name: Set Lockout Time for Failed Password Attempts - Remediate using authselect + block: + - name: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time for Failed Password Attempts - Ensure the "unlock_time" option from "pam_faillock.so" is not + present in {{ pam_file_path }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*auth.*pam_faillock.so.*)\bunlock_time\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + - name: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time for Failed Password Attempts - Check the proper remediation for the system + block: + - name: Set Lockout Time 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: Set Lockout Time for Failed Password Attempts - Check if system relies on authselect + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + - name: Set Lockout Time for Failed Password Attempts - Remediate using authselect + block: + - name: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time 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: Set Lockout Time for Failed Password Attempts - Ensure the "unlock_time" option from "pam_faillock.so" is not + present in {{ pam_file_path }} + ansible.builtin.replace: + dest: '{{ pam_file_path }}' + regexp: (.*auth.*pam_faillock.so.*)\bunlock_time\b=?[0-9a-zA-Z]*(.*) + replace: \1\2 + register: result_pam_option_removal + - name: Set Lockout Time 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: + - DISA_STIG_RHEL_07_010320 | bool - accounts_passwords_pam_faillock_unlock_time | bool - low_complexity | bool - low_disruption | bool @@ -2878,6 +3677,7 @@ when: - result_pam_faillock_unlock_time_parameter_is_present.found > 0 when: + - DISA_STIG_RHEL_07_010320 | bool - accounts_passwords_pam_faillock_unlock_time | bool - low_complexity | bool - low_disruption | bool @@ -2919,6 +3719,7 @@ - no_reboot_needed - restrict_strategy when: + - DISA_STIG_RHEL_07_010140 | bool - accounts_password_pam_dcredit | bool - low_complexity | bool - low_disruption | bool @@ -2933,6 +3734,7 @@ regexp: ^#?\s*dcredit line: dcredit = {{ var_password_pam_dcredit }} when: + - DISA_STIG_RHEL_07_010140 | bool - accounts_password_pam_dcredit | bool - low_complexity | bool - low_disruption | bool @@ -2973,6 +3775,7 @@ - no_reboot_needed - restrict_strategy when: + - DISA_STIG_RHEL_07_010130 | bool - accounts_password_pam_lcredit | bool - low_complexity | bool - low_disruption | bool @@ -2987,6 +3790,7 @@ regexp: ^#?\s*lcredit line: lcredit = {{ var_password_pam_lcredit }} when: + - DISA_STIG_RHEL_07_010130 | bool - accounts_password_pam_lcredit | bool - low_complexity | bool - low_disruption | bool @@ -3028,6 +3832,7 @@ - no_reboot_needed - restrict_strategy when: + - DISA_STIG_RHEL_07_010280 | bool - accounts_password_pam_minlen | bool - low_complexity | bool - low_disruption | bool @@ -3042,6 +3847,7 @@ regexp: ^#?\s*minlen line: minlen = {{ var_password_pam_minlen }} when: + - DISA_STIG_RHEL_07_010280 | bool - accounts_password_pam_minlen | bool - low_complexity | bool - low_disruption | bool @@ -3083,6 +3889,7 @@ - no_reboot_needed - restrict_strategy when: + - DISA_STIG_RHEL_07_010120 | bool - accounts_password_pam_ucredit | bool - low_complexity | bool - low_disruption | bool @@ -3097,6 +3904,7 @@ regexp: ^#?\s*ucredit line: ucredit = {{ var_password_pam_ucredit }} when: + - DISA_STIG_RHEL_07_010120 | bool - accounts_password_pam_ucredit | bool - low_complexity | bool - low_disruption | bool @@ -3138,6 +3946,7 @@ - restrict_strategy - set_password_hashing_algorithm_libuserconf when: + - DISA_STIG_RHEL_07_010220 | bool - low_complexity | bool - low_disruption | bool - medium_severity | bool @@ -3154,6 +3963,7 @@ state: present create: true when: + - DISA_STIG_RHEL_07_010220 | bool - low_complexity | bool - low_disruption | bool - medium_severity | bool @@ -3196,6 +4006,7 @@ - restrict_strategy - set_password_hashing_algorithm_logindefs when: + - DISA_STIG_RHEL_07_010210 | bool - low_complexity | bool - low_disruption | bool - medium_severity | bool @@ -3211,28 +4022,290 @@ state: present create: true when: + - DISA_STIG_RHEL_07_010210 | bool + - low_complexity | bool + - low_disruption | bool + - medium_severity | bool + - no_reboot_needed | bool + - restrict_strategy | bool + - set_password_hashing_algorithm_logindefs | bool + - '"shadow-utils" in ansible_facts.packages' + tags: + - CCE-82050-6 + - CJIS-5.6.2.2 + - DISA-STIG-RHEL-07-010210 + - NIST-800-171-3.13.11 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(c) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.1 + - low_complexity + - low_disruption + - medium_severity + - no_reboot_needed + - restrict_strategy + - set_password_hashing_algorithm_logindefs + +- name: Gather the package facts + package_facts: + manager: auto + tags: + - CCE-82043-1 + - CJIS-5.6.2.2 + - DISA-STIG-RHEL-07-010200 + - NIST-800-171-3.13.11 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(c) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.1 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - set_password_hashing_algorithm_systemauth + when: + - DISA_STIG_RHEL_07_010200 | bool + - configure_strategy | bool + - low_complexity | bool + - medium_disruption | bool + - medium_severity | bool + - no_reboot_needed | bool + - set_password_hashing_algorithm_systemauth | bool + +- name: Set PAM's Password Hashing Algorithm - Check if /etc/pam.d/system-auth file is present + ansible.builtin.stat: + path: /etc/pam.d/system-auth + register: result_pam_file_present + when: + - DISA_STIG_RHEL_07_010200 | bool + - configure_strategy | bool + - low_complexity | bool + - medium_disruption | bool + - medium_severity | bool + - no_reboot_needed | bool + - set_password_hashing_algorithm_systemauth | bool + - '"pam" in ansible_facts.packages' + tags: + - CCE-82043-1 + - CJIS-5.6.2.2 + - DISA-STIG-RHEL-07-010200 + - NIST-800-171-3.13.11 + - NIST-800-53-CM-6(a) + - NIST-800-53-IA-5(1)(c) + - NIST-800-53-IA-5(c) + - PCI-DSS-Req-8.2.1 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - set_password_hashing_algorithm_systemauth + +- name: Set PAM's Password Hashing Algorithm - Check the proper remediation for the system + block: + - name: Set PAM's Password Hashing Algorithm - Define the PAM file to be edited as a local fact + ansible.builtin.set_fact: + pam_file_path: /etc/pam.d/system-auth + - name: Set PAM's Password Hashing Algorithm - Check if system relies on authselect + ansible.builtin.stat: + path: /usr/bin/authselect + register: result_authselect_present + - name: Set PAM's Password Hashing Algorithm - Remediate using authselect + block: + - name: Set PAM's Password Hashing Algorithm - Check integrity of authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + ignore_errors: true + - name: Set PAM's Password Hashing Algorithm - 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: Set PAM's Password Hashing Algorithm - 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: Set PAM's Password Hashing Algorithm - 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: Set PAM's Password Hashing Algorithm - 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: Set PAM's Password Hashing Algorithm - 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: Set PAM's Password Hashing Algorithm - 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: Set PAM's Password Hashing Algorithm - 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: Set PAM's Password Hashing Algorithm - 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: Set PAM's Password Hashing Algorithm - 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: Set PAM's Password Hashing Algorithm - 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: Set PAM's Password Hashing Algorithm - 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: Set PAM's Password Hashing Algorithm - 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: Set PAM's Password Hashing Algorithm - Check if expected PAM module line is present in {{ pam_file_path }} + ansible.builtin.lineinfile: + path: '{{ pam_file_path }}' + regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.* + state: absent + check_mode: true + changed_when: false + register: result_pam_line_present + - name: Set PAM's Password Hashing Algorithm - Include or update the PAM module line in {{ pam_file_path }} + block: + - name: Set PAM's Password Hashing Algorithm - 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_unix.so\s* + state: absent + check_mode: true + changed_when: false + register: result_pam_line_other_control_present + - name: Set PAM's Password Hashing Algorithm - 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_unix.so.*) + replace: \1sufficient \2 + register: result_pam_module_edit + when: + - result_pam_line_other_control_present.found == 1 + - name: Set PAM's Password Hashing Algorithm - Ensure the required PAM module line is included in {{ pam_file_path }} + ansible.builtin.lineinfile: + dest: '{{ pam_file_path }}' + line: password sufficient pam_unix.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: Set PAM's Password Hashing Algorithm - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - (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: Set PAM's Password Hashing Algorithm - Check if the required PAM module option is present in {{ pam_file_path }} + ansible.builtin.lineinfile: + path: '{{ pam_file_path }}' + regexp: ^\s*password\s+sufficient\s+pam_unix.so\s*.*\ssha512\b + state: absent + check_mode: true + changed_when: false + register: result_pam_module_sha512_option_present + - name: Set PAM's Password Hashing Algorithm - Ensure the "sha512" PAM option for "pam_unix.so" is included in {{ pam_file_path + }} + ansible.builtin.lineinfile: + path: '{{ pam_file_path }}' + backrefs: true + regexp: ^(\s*password\s+sufficient\s+pam_unix.so.*) + line: \1 sha512 + state: present + register: result_pam_sha512_add + when: + - result_pam_module_sha512_option_present.found == 0 + - name: Set PAM's Password Hashing Algorithm - Ensure authselect changes are applied + ansible.builtin.command: + cmd: authselect apply-changes -b + when: + - result_authselect_present.stat.exists + - (result_pam_sha512_add is defined and result_pam_sha512_add.changed) or (result_pam_sha512_edit is defined and result_pam_sha512_edit.changed) + when: + - DISA_STIG_RHEL_07_010200 | bool + - configure_strategy | bool - low_complexity | bool - - low_disruption | bool + - medium_disruption | bool - medium_severity | bool - no_reboot_needed | bool - - restrict_strategy | bool - - set_password_hashing_algorithm_logindefs | bool - - '"shadow-utils" in ansible_facts.packages' + - set_password_hashing_algorithm_systemauth | bool + - '"pam" in ansible_facts.packages' + - result_pam_file_present.stat.exists tags: - - CCE-82050-6 + - CCE-82043-1 - CJIS-5.6.2.2 - - DISA-STIG-RHEL-07-010210 + - DISA-STIG-RHEL-07-010200 - NIST-800-171-3.13.11 - NIST-800-53-CM-6(a) - NIST-800-53-IA-5(1)(c) - NIST-800-53-IA-5(c) - PCI-DSS-Req-8.2.1 + - configure_strategy - low_complexity - - low_disruption + - medium_disruption - medium_severity - no_reboot_needed - - restrict_strategy - - set_password_hashing_algorithm_logindefs + - set_password_hashing_algorithm_systemauth - name: Gather the package facts package_facts: @@ -3253,6 +4326,7 @@ - no_reboot_needed - restrict_strategy when: + - DISA_STIG_RHEL_07_010310 | bool - account_disable_post_pw_expiration | bool - low_complexity | bool - low_disruption | bool @@ -3267,6 +4341,7 @@ regexp: ^INACTIVE line: INACTIVE={{ var_account_disable_post_pw_expiration }} when: + - DISA_STIG_RHEL_07_010310 | bool - account_disable_post_pw_expiration | bool - low_complexity | bool - low_disruption | bool @@ -3309,6 +4384,7 @@ - no_reboot_needed - restrict_strategy when: + - DISA_STIG_RHEL_07_010250 | bool - accounts_maximum_age_login_defs | bool - low_complexity | bool - low_disruption | bool @@ -3323,6 +4399,7 @@ regexp: ^#?PASS_MAX_DAYS line: PASS_MAX_DAYS {{ var_accounts_maximum_age_login_defs }} when: + - DISA_STIG_RHEL_07_010250 | bool - accounts_maximum_age_login_defs | bool - low_complexity | bool - low_disruption | bool @@ -3346,11 +4423,12 @@ - no_reboot_needed - restrict_strategy -- name: Check if system relies on authselect +- name: Prevent Login to Accounts With Empty Password - Check if system relies on authselect ansible.builtin.stat: path: /usr/bin/authselect register: result_authselect_present when: + - DISA_STIG_RHEL_07_010290 | bool - configure_strategy | bool - high_severity | bool - low_complexity | bool @@ -3375,114 +4453,48 @@ - no_empty_passwords - no_reboot_needed -- name: Check integrity of authselect current profile - ansible.builtin.command: - cmd: authselect check - register: result_authselect_check_cmd - changed_when: false - ignore_errors: true - when: - - configure_strategy | bool - - high_severity | bool - - low_complexity | bool - - medium_disruption | bool - - no_empty_passwords | bool - - no_reboot_needed | bool - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - result_authselect_present.stat.exists - tags: - - CCE-27286-4 - - CJIS-5.5.2 - - DISA-STIG-RHEL-07-010290 - - NIST-800-171-3.1.1 - - NIST-800-171-3.1.5 - - NIST-800-53-CM-6(a) - - NIST-800-53-IA-5(1)(a) - - NIST-800-53-IA-5(c) - - PCI-DSS-Req-8.2.3 - - configure_strategy - - high_severity - - low_complexity - - medium_disruption - - no_empty_passwords - - no_reboot_needed - -- name: Get authselect current features - ansible.builtin.shell: - cmd: authselect current | tail -n+3 | awk '{ print $2 }' - register: result_authselect_features - changed_when: false - when: - - configure_strategy | bool - - high_severity | bool - - low_complexity | bool - - medium_disruption | bool - - no_empty_passwords | bool - - no_reboot_needed | bool - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - result_authselect_present.stat.exists - - result_authselect_check_cmd is success - tags: - - CCE-27286-4 - - CJIS-5.5.2 - - DISA-STIG-RHEL-07-010290 - - NIST-800-171-3.1.1 - - NIST-800-171-3.1.5 - - NIST-800-53-CM-6(a) - - NIST-800-53-IA-5(1)(a) - - NIST-800-53-IA-5(c) - - PCI-DSS-Req-8.2.3 - - configure_strategy - - high_severity - - low_complexity - - medium_disruption - - no_empty_passwords - - no_reboot_needed - -- name: Ensure nullok property is absent via authselect tool - ansible.builtin.command: - cmd: authselect enable-feature without-nullok - register: result_authselect_cmd - when: - - configure_strategy | bool - - high_severity | bool - - low_complexity | bool - - medium_disruption | bool - - no_empty_passwords | bool - - no_reboot_needed | bool - - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] - - result_authselect_present.stat.exists - - result_authselect_check_cmd is success - - result_authselect_features.stdout is not search("without-nullok") - tags: - - CCE-27286-4 - - CJIS-5.5.2 - - DISA-STIG-RHEL-07-010290 - - NIST-800-171-3.1.1 - - NIST-800-171-3.1.5 - - NIST-800-53-CM-6(a) - - NIST-800-53-IA-5(1)(a) - - NIST-800-53-IA-5(c) - - PCI-DSS-Req-8.2.3 - - configure_strategy - - high_severity - - low_complexity - - medium_disruption - - no_empty_passwords - - no_reboot_needed - -- name: Informative message based on the authselect integrity check result - ansible.builtin.assert: - that: +- name: Prevent Login to Accounts With Empty Password - Remediate using authselect + block: + - name: Prevent Login to Accounts With Empty Password - Check integrity of authselect current profile + ansible.builtin.command: + cmd: authselect check + register: result_authselect_check_cmd + changed_when: false + ignore_errors: true + - name: Prevent Login to Accounts With Empty Password - 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: Prevent Login to Accounts With Empty Password - 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 - fail_msg: - - authselect integrity check failed. Remediation aborted! - - This remediation could not be applied because the authselect profile is not intact. - - It is not recommended to manually edit the PAM files when authselect 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: Prevent Login to Accounts With Empty Password - Ensure "without-nullok" feature is enabled using authselect tool + ansible.builtin.command: + cmd: authselect enable-feature without-nullok + register: result_authselect_enable_feature_cmd + when: + - result_authselect_check_cmd is success + - result_authselect_features.stdout is not search("without-nullok") + - name: Prevent Login to Accounts With Empty Password - 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: + - DISA_STIG_RHEL_07_010290 | bool - configure_strategy | bool - high_severity | bool - low_complexity | bool @@ -3490,6 +4502,7 @@ - no_empty_passwords | bool - no_reboot_needed | bool - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + - result_authselect_present.stat.exists tags: - CCE-27286-4 - CJIS-5.5.2 @@ -3507,14 +4520,15 @@ - no_empty_passwords - no_reboot_needed -- name: Ensure nullok property is absent by directly editing pam files - replace: +- name: Prevent Login to Accounts With Empty Password - Remediate directly editing PAM files + ansible.builtin.replace: dest: '{{ item }}' regexp: nullok loop: - /etc/pam.d/system-auth - /etc/pam.d/password-auth when: + - DISA_STIG_RHEL_07_010290 | bool - configure_strategy | bool - high_severity | bool - low_complexity | bool @@ -3567,6 +4581,7 @@ - no_reboot_needed - service_auditd_enabled when: + - DISA_STIG_RHEL_07_030000 | bool - enable_strategy | bool - low_complexity | bool - low_disruption | bool @@ -3588,6 +4603,7 @@ when: - '"audit" in ansible_facts.packages' when: + - DISA_STIG_RHEL_07_030000 | bool - enable_strategy | bool - low_complexity | bool - low_disruption | bool @@ -4135,6 +5151,7 @@ - reboot_required - restrict_strategy when: + - DISA_STIG_RHEL_07_030740 | bool - audit_rules_media_export | bool - low_complexity | bool - low_disruption | bool @@ -4146,6 +5163,7 @@ set_fact: audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }} when: + - DISA_STIG_RHEL_07_030740 | bool - audit_rules_media_export | bool - low_complexity | bool - low_disruption | bool @@ -4260,6 +5278,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030740 | bool - audit_rules_media_export | bool - low_complexity | bool - low_disruption | bool @@ -4374,6 +5393,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030740 | bool - audit_rules_media_export | bool - low_complexity | bool - low_disruption | bool @@ -6215,6 +7235,7 @@ - no_reboot_needed - restrict_strategy when: + - DISA_STIG_RHEL_07_030700 | bool - audit_rules_sysadmin_actions | bool - low_complexity | bool - low_disruption | bool @@ -6230,6 +7251,7 @@ patterns: '*.rules' register: find_audit_sysadmin_actions when: + - DISA_STIG_RHEL_07_030700 | bool - audit_rules_sysadmin_actions | bool - low_complexity | bool - low_disruption | bool @@ -6261,6 +7283,7 @@ all_sysadmin_actions_files: - /etc/audit/rules.d/actions.rules when: + - DISA_STIG_RHEL_07_030700 | bool - audit_rules_sysadmin_actions | bool - low_complexity | bool - low_disruption | bool @@ -6293,6 +7316,7 @@ all_sysadmin_actions_files: - '{{ find_audit_sysadmin_actions.files | map(attribute=''path'') | list | first }}' when: + - DISA_STIG_RHEL_07_030700 | bool - audit_rules_sysadmin_actions | bool - low_complexity | bool - low_disruption | bool @@ -6326,6 +7350,7 @@ line: -w /etc/sudoers -p wa -k actions create: true when: + - DISA_STIG_RHEL_07_030700 | bool - audit_rules_sysadmin_actions | bool - low_complexity | bool - low_disruption | bool @@ -6358,6 +7383,7 @@ line: -w /etc/sudoers.d/ -p wa -k actions create: true when: + - DISA_STIG_RHEL_07_030700 | bool - audit_rules_sysadmin_actions | bool - low_complexity | bool - low_disruption | bool @@ -6390,6 +7416,7 @@ line: -w /etc/sudoers -p wa -k actions create: true when: + - DISA_STIG_RHEL_07_030700 | bool - audit_rules_sysadmin_actions | bool - low_complexity | bool - low_disruption | bool @@ -6422,6 +7449,7 @@ line: -w /etc/sudoers.d/ -p wa -k actions create: true when: + - DISA_STIG_RHEL_07_030700 | bool - audit_rules_sysadmin_actions | bool - low_complexity | bool - low_disruption | bool @@ -6467,6 +7495,7 @@ - reboot_required - restrict_strategy when: + - DISA_STIG_RHEL_07_030410 | bool - audit_rules_dac_modification_chmod | bool - low_complexity | bool - low_disruption | bool @@ -6478,6 +7507,7 @@ set_fact: audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }} when: + - DISA_STIG_RHEL_07_030410 | bool - audit_rules_dac_modification_chmod | bool - low_complexity | bool - low_disruption | bool @@ -6597,6 +7627,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030410 | bool - audit_rules_dac_modification_chmod | bool - low_complexity | bool - low_disruption | bool @@ -6716,6 +7747,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030410 | bool - audit_rules_dac_modification_chmod | bool - low_complexity | bool - low_disruption | bool @@ -6759,6 +7791,7 @@ - reboot_required - restrict_strategy when: + - DISA_STIG_RHEL_07_030370 | bool - audit_rules_dac_modification_chown | bool - low_complexity | bool - low_disruption | bool @@ -6770,6 +7803,7 @@ set_fact: audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }} when: + - DISA_STIG_RHEL_07_030370 | bool - audit_rules_dac_modification_chown | bool - low_complexity | bool - low_disruption | bool @@ -6891,6 +7925,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030370 | bool - audit_rules_dac_modification_chown | bool - low_complexity | bool - low_disruption | bool @@ -7012,6 +8047,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030370 | bool - audit_rules_dac_modification_chown | bool - low_complexity | bool - low_disruption | bool @@ -7055,6 +8091,7 @@ - reboot_required - restrict_strategy when: + - DISA_STIG_RHEL_07_030410 | bool - audit_rules_dac_modification_fchmod | bool - low_complexity | bool - low_disruption | bool @@ -7066,6 +8103,7 @@ set_fact: audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }} when: + - DISA_STIG_RHEL_07_030410 | bool - audit_rules_dac_modification_fchmod | bool - low_complexity | bool - low_disruption | bool @@ -7185,6 +8223,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030410 | bool - audit_rules_dac_modification_fchmod | bool - low_complexity | bool - low_disruption | bool @@ -7304,6 +8343,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030410 | bool - audit_rules_dac_modification_fchmod | bool - low_complexity | bool - low_disruption | bool @@ -7347,6 +8387,7 @@ - reboot_required - restrict_strategy when: + - DISA_STIG_RHEL_07_030410 | bool - audit_rules_dac_modification_fchmodat | bool - low_complexity | bool - low_disruption | bool @@ -7358,6 +8399,7 @@ set_fact: audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }} when: + - DISA_STIG_RHEL_07_030410 | bool - audit_rules_dac_modification_fchmodat | bool - low_complexity | bool - low_disruption | bool @@ -7477,6 +8519,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030410 | bool - audit_rules_dac_modification_fchmodat | bool - low_complexity | bool - low_disruption | bool @@ -7596,6 +8639,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030410 | bool - audit_rules_dac_modification_fchmodat | bool - low_complexity | bool - low_disruption | bool @@ -7639,6 +8683,7 @@ - reboot_required - restrict_strategy when: + - DISA_STIG_RHEL_07_030370 | bool - audit_rules_dac_modification_fchown | bool - low_complexity | bool - low_disruption | bool @@ -7650,6 +8695,7 @@ set_fact: audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }} when: + - DISA_STIG_RHEL_07_030370 | bool - audit_rules_dac_modification_fchown | bool - low_complexity | bool - low_disruption | bool @@ -7771,6 +8817,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030370 | bool - audit_rules_dac_modification_fchown | bool - low_complexity | bool - low_disruption | bool @@ -7892,6 +8939,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030370 | bool - audit_rules_dac_modification_fchown | bool - low_complexity | bool - low_disruption | bool @@ -7935,6 +8983,7 @@ - reboot_required - restrict_strategy when: + - DISA_STIG_RHEL_07_030370 | bool - audit_rules_dac_modification_fchownat | bool - low_complexity | bool - low_disruption | bool @@ -7946,6 +8995,7 @@ set_fact: audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }} when: + - DISA_STIG_RHEL_07_030370 | bool - audit_rules_dac_modification_fchownat | bool - low_complexity | bool - low_disruption | bool @@ -8067,6 +9117,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030370 | bool - audit_rules_dac_modification_fchownat | bool - low_complexity | bool - low_disruption | bool @@ -8188,6 +9239,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030370 | bool - audit_rules_dac_modification_fchownat | bool - low_complexity | bool - low_disruption | bool @@ -8231,6 +9283,7 @@ - reboot_required - restrict_strategy when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_fremovexattr | bool - low_complexity | bool - low_disruption | bool @@ -8242,6 +9295,7 @@ set_fact: audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }} when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_fremovexattr | bool - low_complexity | bool - low_disruption | bool @@ -8367,6 +9421,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_fremovexattr | bool - low_complexity | bool - low_disruption | bool @@ -8492,6 +9547,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_fremovexattr | bool - low_complexity | bool - low_disruption | bool @@ -8535,6 +9591,7 @@ - reboot_required - restrict_strategy when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_fsetxattr | bool - low_complexity | bool - low_disruption | bool @@ -8546,6 +9603,7 @@ set_fact: audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }} when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_fsetxattr | bool - low_complexity | bool - low_disruption | bool @@ -8671,6 +9729,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_fsetxattr | bool - low_complexity | bool - low_disruption | bool @@ -8796,6 +9855,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_fsetxattr | bool - low_complexity | bool - low_disruption | bool @@ -8839,6 +9899,7 @@ - reboot_required - restrict_strategy when: + - DISA_STIG_RHEL_07_030370 | bool - audit_rules_dac_modification_lchown | bool - low_complexity | bool - low_disruption | bool @@ -8850,6 +9911,7 @@ set_fact: audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }} when: + - DISA_STIG_RHEL_07_030370 | bool - audit_rules_dac_modification_lchown | bool - low_complexity | bool - low_disruption | bool @@ -8971,6 +10033,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030370 | bool - audit_rules_dac_modification_lchown | bool - low_complexity | bool - low_disruption | bool @@ -9092,6 +10155,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030370 | bool - audit_rules_dac_modification_lchown | bool - low_complexity | bool - low_disruption | bool @@ -9135,6 +10199,7 @@ - reboot_required - restrict_strategy when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_lremovexattr | bool - low_complexity | bool - low_disruption | bool @@ -9146,6 +10211,7 @@ set_fact: audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }} when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_lremovexattr | bool - low_complexity | bool - low_disruption | bool @@ -9271,6 +10337,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_lremovexattr | bool - low_complexity | bool - low_disruption | bool @@ -9396,6 +10463,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_lremovexattr | bool - low_complexity | bool - low_disruption | bool @@ -9439,6 +10507,7 @@ - reboot_required - restrict_strategy when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_lsetxattr | bool - low_complexity | bool - low_disruption | bool @@ -9450,6 +10519,7 @@ set_fact: audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }} when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_lsetxattr | bool - low_complexity | bool - low_disruption | bool @@ -9575,6 +10645,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_lsetxattr | bool - low_complexity | bool - low_disruption | bool @@ -9700,6 +10771,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_lsetxattr | bool - low_complexity | bool - low_disruption | bool @@ -9743,6 +10815,7 @@ - reboot_required - restrict_strategy when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_removexattr | bool - low_complexity | bool - low_disruption | bool @@ -9754,6 +10827,7 @@ set_fact: audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }} when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_removexattr | bool - low_complexity | bool - low_disruption | bool @@ -9879,6 +10953,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_removexattr | bool - low_complexity | bool - low_disruption | bool @@ -10004,6 +11079,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_removexattr | bool - low_complexity | bool - low_disruption | bool @@ -10047,6 +11123,7 @@ - reboot_required - restrict_strategy when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_setxattr | bool - low_complexity | bool - low_disruption | bool @@ -10058,6 +11135,7 @@ set_fact: audit_arch: b{{ ansible_architecture | regex_replace('.*(\d\d$)','\1') }} when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_setxattr | bool - low_complexity | bool - low_disruption | bool @@ -10183,6 +11261,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_setxattr | bool - low_complexity | bool - low_disruption | bool @@ -10308,6 +11387,7 @@ state: present when: syscalls_found | length == 0 when: + - DISA_STIG_RHEL_07_030440 | bool - audit_rules_dac_modification_setxattr | bool - low_complexity | bool - low_disruption | bool @@ -12154,6 +13234,7 @@ - no_reboot_needed - restrict_strategy when: + - DISA_STIG_RHEL_07_030350 | bool - auditd_data_retention_action_mail_acct | bool - low_complexity | bool - low_disruption | bool @@ -12168,6 +13249,7 @@ state: present create: true when: + - DISA_STIG_RHEL_07_030350 | bool - auditd_data_retention_action_mail_acct | bool - low_complexity | bool - low_disruption | bool @@ -12198,7 +13280,6 @@ tags: - CCE-27370-6 - CJIS-5.4.1.1 - - DISA-STIG-RHEL-07-030340 - NIST-800-171-3.3.1 - NIST-800-53-AU-5(1) - NIST-800-53-AU-5(2) @@ -12238,7 +13319,6 @@ tags: - CCE-27370-6 - CJIS-5.4.1.1 - - DISA-STIG-RHEL-07-030340 - NIST-800-171-3.3.1 - NIST-800-53-AU-5(1) - NIST-800-53-AU-5(2) @@ -12435,6 +13515,7 @@ - no_reboot_needed - restrict_strategy when: + - DISA_STIG_RHEL_07_030340 | bool - auditd_data_retention_space_left_action | bool - low_complexity | bool - low_disruption | bool @@ -12450,6 +13531,7 @@ state: present create: true when: + - DISA_STIG_RHEL_07_030340 | bool - auditd_data_retention_space_left_action | bool - low_complexity | bool - low_disruption | bool @@ -12581,6 +13663,172 @@ - medium_severity - no_reboot_needed +- name: Set rsyslog logfile configuration facts + set_fact: + rsyslog_etc_config: /etc/rsyslog.conf + desired_perm_mode: '600' + when: + - configure_strategy | bool + - low_complexity | bool + - medium_disruption | bool + - medium_severity | bool + - no_reboot_needed | bool + - rsyslog_files_permissions | bool + - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + tags: + - CCE-80191-0 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_permissions + +- name: Get IncludeConfig directive + shell: 'set -o pipefail + + grep -e ''$IncludeConfig'' {{ rsyslog_etc_config }} | cut -d '' '' -f 2 || true + + ' + register: include_config_output + changed_when: false + when: + - configure_strategy | bool + - low_complexity | bool + - medium_disruption | bool + - medium_severity | bool + - no_reboot_needed | bool + - rsyslog_files_permissions | bool + - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + tags: + - CCE-80191-0 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_permissions + +- name: Get include files directives + shell: 'set -o pipefail + + grep -oP ''^\s*include\s*\(\s*file.*'' {{ rsyslog_etc_config }} |cut -d"\"" -f 2 || true + + ' + register: include_files_output + changed_when: false + when: + - configure_strategy | bool + - low_complexity | bool + - medium_disruption | bool + - medium_severity | bool + - no_reboot_needed | bool + - rsyslog_files_permissions | bool + - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + tags: + - CCE-80191-0 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_permissions + +- name: List all config files + shell: find "$(dirname "{{ item }}" )" -maxdepth 1 -name "$(basename "{{ item }}")" + loop: '{{ include_config_output.stdout_lines + include_files_output.stdout_lines }}' + register: rsyslog_config_files + changed_when: false + when: + - configure_strategy | bool + - low_complexity | bool + - medium_disruption | bool + - medium_severity | bool + - no_reboot_needed | bool + - rsyslog_files_permissions | bool + - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + tags: + - CCE-80191-0 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_permissions + +- name: Extract log files + shell: 'set -o pipefail + + grep -oP ''^[^(\s|#|\$)]+[\s]+.*[\s]+-?(/+[^:;\s]+);*\.*$'' {{ item }} |awk ''{print $NF}''|sed -e ''s/^-//'' || true + + ' + loop: '{{ rsyslog_config_files.results|map(attribute=''stdout_lines'')|list|flatten|unique + [ rsyslog_etc_config ] }}' + register: log_files + changed_when: false + when: + - configure_strategy | bool + - low_complexity | bool + - medium_disruption | bool + - medium_severity | bool + - no_reboot_needed | bool + - rsyslog_files_permissions | bool + - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + tags: + - CCE-80191-0 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_permissions + +- name: Setup log files permissions + ignore_errors: true + file: + path: '{{ item }}' + mode: '{{ desired_perm_mode }}' + loop: '{{ log_files.results|map(attribute=''stdout_lines'')|list|flatten|unique }}' + when: + - configure_strategy | bool + - low_complexity | bool + - medium_disruption | bool + - medium_severity | bool + - no_reboot_needed | bool + - rsyslog_files_permissions | bool + - ansible_virtualization_type not in ["docker", "lxc", "openvz", "podman", "container"] + tags: + - CCE-80191-0 + - NIST-800-53-AC-6(1) + - NIST-800-53-CM-6(a) + - PCI-DSS-Req-10.5.1 + - PCI-DSS-Req-10.5.2 + - configure_strategy + - low_complexity + - medium_disruption + - medium_severity + - no_reboot_needed + - rsyslog_files_permissions + - name: Configure daily log rotation in /etc/logrotate.conf lineinfile: create: true @@ -13377,6 +14625,7 @@ insertbefore: ^[#\s]*Match validate: /usr/sbin/sshd -t -f %s when: + - DISA_STIG_RHEL_07_040340 | bool - low_complexity | bool - low_disruption | bool - medium_severity | bool @@ -13430,6 +14679,7 @@ insertbefore: ^[#\s]*Match validate: /usr/sbin/sshd -t -f %s when: + - DISA_STIG_RHEL_07_040320 | bool - low_complexity | bool - low_disruption | bool - medium_severity | bool