| Server IP : 178.212.43.201 / Your IP : 10.100.0.33 Web Server : Apache/2.4.37 (Oracle Linux Server) OpenSSL/1.1.1k System : Linux spa0007.srv.paxillus.pl 5.4.17-2136.355.3.1.el8uek.x86_64 #3 SMP Sat May 9 17:11:55 PDT 2026 x86_64 User : apache ( 48) PHP Version : 7.4.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : ON Directory : /usr/share/scap-security-guide/ansible/ |
Upload File : |
---
###############################################################################
#
# Ansible Playbook for ANSSI-BP-028 (minimal)
#
# Profile Description:
# This profile contains configurations that align to ANSSI-BP-028 v2.0 at the minimal hardening level.
# ANSSI is the French National Information Security Agency, and stands for Agence nationale de la sécurité des systèmes d'information.
# ANSSI-BP-028 is a configuration recommendation for GNU/Linux systems.
# A copy of the ANSSI-BP-028 can be found at the ANSSI website:
# https://www.ssi.gouv.fr/administration/guide/recommandations-de-securite-relatives-a-un-systeme-gnulinux/
#
# Profile ID: xccdf_org.ssgproject.content_profile_anssi_bp28_minimal
# Benchmark ID: xccdf_org.ssgproject.content_benchmark_OL-8
# Benchmark Version: 0.1.80
# XCCDF Version: 1.2
#
# This file can be generated by OpenSCAP using:
# $ oscap xccdf generate fix --profile xccdf_org.ssgproject.content_profile_anssi_bp28_minimal --fix-type ansible ssg-ol8-ds.xml
#
# This Ansible Playbook is generated from an XCCDF profile without preliminary evaluation.
# It attempts to fix every selected rule, even if the system is already compliant.
#
# How to apply this Ansible Playbook:
# $ ansible-playbook -i "localhost," -c local playbook.yml
# $ ansible-playbook -i "192.168.1.155," playbook.yml
# $ ansible-playbook -i inventory.ini playbook.yml
#
###############################################################################
- name: Ansible Playbook for xccdf_org.ssgproject.content_profile_anssi_bp28_minimal
hosts: all
vars:
var_authselect_profile: minimal
var_password_pam_unix_remember: '2'
var_accounts_passwords_pam_faillock_deny: '3'
var_accounts_passwords_pam_faillock_fail_interval: '900'
var_accounts_passwords_pam_faillock_unlock_time: '900'
var_password_pam_dcredit: '-1'
var_password_pam_lcredit: '-1'
var_password_pam_minclass: '4'
var_password_pam_minlen: '15'
var_password_pam_ocredit: '-1'
var_password_pam_retry: '3'
var_password_pam_ucredit: '-1'
var_password_hashing_algorithm_pam: sha512
var_accounts_password_minlen_login_defs: '15'
var_password_pam_unix_rounds: '65536'
tasks:
- name: Gather the package facts
ansible.builtin.package_facts:
manager: auto
tags:
- always
- name: Ensure dnf-automatic is installed
ansible.builtin.package:
name: dnf-automatic
state: present
when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages
and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
tags:
- enable_strategy
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- package_dnf-automatic_installed
- name: Security patches are up to date
ansible.builtin.package:
name: '*'
state: latest
tags:
- CJIS-5.10.4.1
- DISA-STIG-OL08-00-010010
- NIST-800-53-CM-6(a)
- NIST-800-53-SI-2(5)
- NIST-800-53-SI-2(c)
- PCI-DSS-Req-6.2
- PCI-DSSv4-6.3
- PCI-DSSv4-6.3.3
- high_disruption
- low_complexity
- medium_severity
- patch_strategy
- reboot_required
- security_patches_up_to_date
- skip_ansible_lint
- name: 'Uninstall DHCP Server Package: Ensure dhcp is removed'
ansible.builtin.package:
name: dhcp
state: absent
tags:
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.4
- disable_strategy
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- package_dhcp_removed
- name: 'Uninstall Sendmail Package: Ensure sendmail is removed'
ansible.builtin.package:
name: sendmail
state: absent
when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
tags:
- DISA-STIG-OL08-00-040002
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- disable_strategy
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- package_sendmail_removed
- name: 'Uninstall xinetd Package: Ensure xinetd is removed'
ansible.builtin.package:
name: xinetd
state: absent
when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
tags:
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.4
- disable_strategy
- low_complexity
- low_disruption
- low_severity
- no_reboot_needed
- package_xinetd_removed
- name: 'Remove NIS Client: Ensure ypbind is removed'
ansible.builtin.package:
name: ypbind
state: absent
tags:
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.4
- disable_strategy
- low_complexity
- low_disruption
- no_reboot_needed
- package_ypbind_removed
- unknown_severity
- name: 'Uninstall ypserv Package: Ensure ypserv is removed'
ansible.builtin.package:
name: ypserv
state: absent
tags:
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- NIST-800-53-IA-5(1)(c)
- PCI-DSS-Req-2.2.2
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.4
- disable_strategy
- high_severity
- low_complexity
- low_disruption
- no_reboot_needed
- package_ypserv_removed
- name: 'Uninstall rsh-server Package: Ensure rsh-server is removed'
ansible.builtin.package:
name: rsh-server
state: absent
tags:
- DISA-STIG-OL08-00-040010
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- NIST-800-53-IA-5(1)(c)
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.4
- disable_strategy
- high_severity
- low_complexity
- low_disruption
- no_reboot_needed
- package_rsh-server_removed
- name: 'Uninstall rsh Package: Ensure rsh is removed'
ansible.builtin.package:
name: rsh
state: absent
tags:
- NIST-800-171-3.1.13
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.4
- disable_strategy
- low_complexity
- low_disruption
- no_reboot_needed
- package_rsh_removed
- unknown_severity
- name: 'Uninstall telnet-server Package: Ensure telnet-server is removed'
ansible.builtin.package:
name: telnet-server
state: absent
tags:
- DISA-STIG-OL08-00-040000
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- PCI-DSS-Req-2.2.2
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.4
- disable_strategy
- high_severity
- low_complexity
- low_disruption
- no_reboot_needed
- package_telnet-server_removed
- name: 'Remove telnet Clients: Ensure telnet is removed'
ansible.builtin.package:
name: telnet
state: absent
tags:
- NIST-800-171-3.1.13
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.4
- disable_strategy
- low_complexity
- low_disruption
- low_severity
- no_reboot_needed
- package_telnet_removed
- name: 'Uninstall tftp-server Package: Ensure tftp-server is removed'
ansible.builtin.package:
name: tftp-server
state: absent
tags:
- DISA-STIG-OL08-00-040190
- NIST-800-53-CM-6(a)
- NIST-800-53-CM-7(a)
- NIST-800-53-CM-7(b)
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.4
- disable_strategy
- high_severity
- low_complexity
- low_disruption
- no_reboot_needed
- package_tftp-server_removed
- name: 'Remove tftp Daemon: Ensure tftp is removed'
ansible.builtin.package:
name: tftp
state: absent
tags:
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.4
- disable_strategy
- low_complexity
- low_disruption
- low_severity
- no_reboot_needed
- package_tftp_removed
- name: Gather the package facts
ansible.builtin.package_facts:
manager: auto
tags:
- always
- name: Gather the service facts
ansible.builtin.service_facts: null
tags:
- always
- name: Configure dnf-automatic to Install Available Updates Automatically
community.general.ini_file:
dest: /etc/dnf/automatic.conf
section: commands
option: apply_updates
value: 'yes'
create: true
when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages
and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
tags:
- NIST-800-53-CM-6(a)
- NIST-800-53-SI-2(5)
- NIST-800-53-SI-2(c)
- dnf-automatic_apply_updates
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- unknown_strategy
- name: Configure dnf-automatic to Install Only Security Updates
community.general.ini_file:
dest: /etc/dnf/automatic.conf
section: commands
option: upgrade_type
value: security
create: true
when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages
and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
tags:
- NIST-800-53-CM-6(a)
- NIST-800-53-SI-2(5)
- NIST-800-53-SI-2(c)
- dnf-automatic_security_updates_only
- low_complexity
- low_severity
- medium_disruption
- no_reboot_needed
- unknown_strategy
- name: Ensure GPG check is globally activated
community.general.ini_file:
dest: /etc/yum.conf
section: main
option: gpgcheck
value: 1
no_extra_spaces: true
create: false
when: '"yum" in ansible_facts.packages'
tags:
- CJIS-5.10.4.1
- NIST-800-171-3.4.8
- NIST-800-53-CM-11(a)
- NIST-800-53-CM-11(b)
- NIST-800-53-CM-5(3)
- NIST-800-53-CM-6(a)
- NIST-800-53-SA-12
- NIST-800-53-SA-12(10)
- NIST-800-53-SC-12
- NIST-800-53-SC-12(3)
- NIST-800-53-SI-7
- PCI-DSS-Req-6.2
- PCI-DSSv4-6.3
- PCI-DSSv4-6.3.3
- configure_strategy
- ensure_gpgcheck_globally_activated
- high_severity
- low_complexity
- medium_disruption
- no_reboot_needed
- name: Ensure GPG check Enabled for Local Packages (yum)
block:
- name: Check stats of yum
ansible.builtin.stat:
path: /etc/yum.conf
register: pkg
- name: Check if config file of yum is a symlink
ansible.builtin.set_fact:
pkg_config_file_symlink: '{{ pkg.stat.lnk_target if pkg.stat.lnk_target is
match("^/.*") else "/etc/yum.conf" | dirname ~ "/" ~ pkg.stat.lnk_target
}}'
when: pkg.stat.lnk_target is defined
- name: Ensure GPG check Enabled for Local Packages (yum)
community.general.ini_file:
dest: '{{ pkg_config_file_symlink | default("/etc/yum.conf") }}'
section: main
option: localpkg_gpgcheck
value: 1
no_extra_spaces: true
create: true
when: '"yum" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-010371
- NIST-800-171-3.4.8
- NIST-800-53-CM-11(a)
- NIST-800-53-CM-11(b)
- NIST-800-53-CM-5(3)
- NIST-800-53-CM-6(a)
- NIST-800-53-SA-12
- NIST-800-53-SA-12(10)
- ensure_gpgcheck_local_packages
- high_severity
- low_complexity
- medium_disruption
- no_reboot_needed
- unknown_strategy
- name: Grep for yum repo section names
ansible.builtin.shell: |
set -o pipefail
grep -HEr '^\[.+\]' -r /etc/yum.repos.d/
register: repo_grep_results
failed_when: repo_grep_results.rc not in [0, 1]
changed_when: false
tags:
- CJIS-5.10.4.1
- NIST-800-171-3.4.8
- NIST-800-53-CM-11(a)
- NIST-800-53-CM-11(b)
- NIST-800-53-CM-5(3)
- NIST-800-53-CM-6(a)
- NIST-800-53-SA-12
- NIST-800-53-SA-12(10)
- NIST-800-53-SC-12
- NIST-800-53-SC-12(3)
- NIST-800-53-SI-7
- PCI-DSS-Req-6.2
- PCI-DSSv4-6.3
- PCI-DSSv4-6.3.3
- enable_strategy
- ensure_gpgcheck_never_disabled
- high_severity
- low_complexity
- medium_disruption
- no_reboot_needed
- name: Set gpgcheck=1 for each yum repo
community.general.ini_file:
path: '{{ item[0] }}'
section: '{{ item[1] }}'
option: gpgcheck
value: '1'
no_extra_spaces: true
loop: '{{ repo_grep_results.stdout |regex_findall( ''(.+\.repo):\[(.+)\]\n?''
) if repo_grep_results is not skipped else [] }}'
when: repo_grep_results is not skipped
tags:
- CJIS-5.10.4.1
- NIST-800-171-3.4.8
- NIST-800-53-CM-11(a)
- NIST-800-53-CM-11(b)
- NIST-800-53-CM-5(3)
- NIST-800-53-CM-6(a)
- NIST-800-53-SA-12
- NIST-800-53-SA-12(10)
- NIST-800-53-SC-12
- NIST-800-53-SC-12(3)
- NIST-800-53-SI-7
- PCI-DSS-Req-6.2
- PCI-DSSv4-6.3
- PCI-DSSv4-6.3.3
- enable_strategy
- ensure_gpgcheck_never_disabled
- high_severity
- low_complexity
- medium_disruption
- no_reboot_needed
- name: Ensure Oracle Linux GPG Key Installed - Read GPG key directory permission
ansible.builtin.stat:
path: /etc/pki/rpm-gpg/
register: gpg_key_directory_permission
check_mode: false
tags:
- DISA-STIG-OL08-00-010019
- NIST-800-53-CM-11(a)
- NIST-800-53-CM-11(b)
- NIST-800-53-CM-5(3)
- NIST-800-53-CM-6(a)
- NIST-800-53-SC-12
- NIST-800-53-SC-12(3)
- NIST-800-53-SI-7
- PCI-DSS-Req-6.2
- ensure_oracle_gpgkey_installed
- high_severity
- medium_complexity
- medium_disruption
- no_reboot_needed
- restrict_strategy
- name: Ensure Oracle Linux GPG Key Installed - Retrieve GPG key fingerprints information
ansible.builtin.command: gpg --show-keys --with-fingerprint --with-colons "/etc/pki/rpm-gpg/RPM-GPG-KEY-oracle"
changed_when: false
register: gpg_fingerprints
check_mode: false
tags:
- DISA-STIG-OL08-00-010019
- NIST-800-53-CM-11(a)
- NIST-800-53-CM-11(b)
- NIST-800-53-CM-5(3)
- NIST-800-53-CM-6(a)
- NIST-800-53-SC-12
- NIST-800-53-SC-12(3)
- NIST-800-53-SI-7
- PCI-DSS-Req-6.2
- ensure_oracle_gpgkey_installed
- high_severity
- medium_complexity
- medium_disruption
- no_reboot_needed
- restrict_strategy
- name: Ensure Oracle Linux GPG Key Installed - Set fact for installed fingerprints
ansible.builtin.set_fact:
gpg_installed_fingerprints: |-
{{ gpg_fingerprints.stdout | regex_findall('^pub.*
(?:^fpr[:]*)([0-9A-Fa-f]*)', '\1') | list }}
tags:
- DISA-STIG-OL08-00-010019
- NIST-800-53-CM-11(a)
- NIST-800-53-CM-11(b)
- NIST-800-53-CM-5(3)
- NIST-800-53-CM-6(a)
- NIST-800-53-SC-12
- NIST-800-53-SC-12(3)
- NIST-800-53-SI-7
- PCI-DSS-Req-6.2
- ensure_oracle_gpgkey_installed
- high_severity
- medium_complexity
- medium_disruption
- no_reboot_needed
- restrict_strategy
- name: Ensure Oracle Linux GPG Key Installed - Set fact for valid fingerprints
ansible.builtin.set_fact:
gpg_valid_fingerprints:
- 76FD3DB13AB67410B89DB10E82562EA9AD986DA3
- ''
tags:
- DISA-STIG-OL08-00-010019
- NIST-800-53-CM-11(a)
- NIST-800-53-CM-11(b)
- NIST-800-53-CM-5(3)
- NIST-800-53-CM-6(a)
- NIST-800-53-SC-12
- NIST-800-53-SC-12(3)
- NIST-800-53-SI-7
- PCI-DSS-Req-6.2
- ensure_oracle_gpgkey_installed
- high_severity
- medium_complexity
- medium_disruption
- no_reboot_needed
- restrict_strategy
- name: Ensure Oracle Linux GPG Key Installed - Import Oracle GPG key securely
ansible.builtin.rpm_key:
state: present
key: /etc/pki/rpm-gpg/RPM-GPG-KEY-oracle
when:
- gpg_key_directory_permission.stat.mode <= '0755'
- (gpg_installed_fingerprints | difference(gpg_valid_fingerprints)) | length ==
0
- gpg_installed_fingerprints | length > 0
tags:
- DISA-STIG-OL08-00-010019
- NIST-800-53-CM-11(a)
- NIST-800-53-CM-11(b)
- NIST-800-53-CM-5(3)
- NIST-800-53-CM-6(a)
- NIST-800-53-SC-12
- NIST-800-53-SC-12(3)
- NIST-800-53-SI-7
- PCI-DSS-Req-6.2
- ensure_oracle_gpgkey_installed
- high_severity
- medium_complexity
- medium_disruption
- no_reboot_needed
- restrict_strategy
- name: Enable timer dnf-automatic
block:
- name: Enable timer dnf-automatic
ansible.builtin.systemd:
name: dnf-automatic.timer
enabled: 'yes'
state: started
when:
- '"dnf-automatic" in ansible_facts.packages'
when: ( not ( "kernel" in ansible_facts.packages and "rpm-ostree" in ansible_facts.packages
and "bootc" in ansible_facts.packages and not "openshift-kubelet" in ansible_facts.packages
and "ostree" in ansible_proc_cmdline ) and not ( ansible_virtualization_type
in ["docker", "lxc", "openvz", "podman", "container"] ) )
tags:
- NIST-800-53-CM-6(a)
- NIST-800-53-SI-2(5)
- NIST-800-53-SI-2(c)
- enable_strategy
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- timer_dnf-automatic_enabled
- name: Enable authselect - Check Current authselect Profile
ansible.builtin.command:
cmd: authselect current
register: result_authselect_current
changed_when: false
failed_when: false
when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
tags:
- NIST-800-53-AC-3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.4
- configure_strategy
- enable_authselect
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Enable authselect - Try to Select an authselect Profile
ansible.builtin.command:
cmd: authselect select "{{ var_authselect_profile }}"
register: result_authselect_select
changed_when: result_authselect_select.rc == 0
failed_when: false
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- result_authselect_current.rc != 0
tags:
- NIST-800-53-AC-3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.4
- configure_strategy
- enable_authselect
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Enable authselect - Verify If pam Has Been Altered
ansible.builtin.command:
cmd: rpm -qV pam
register: result_altered_authselect
changed_when: false
failed_when: false
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- result_authselect_select is not skipped
- result_authselect_select.rc != 0
tags:
- NIST-800-53-AC-3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.4
- configure_strategy
- enable_authselect
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Enable authselect - Informative Message Based on authselect Integrity Check
ansible.builtin.assert:
that:
- result_authselect_current.rc == 0 or result_altered_authselect is skipped
or result_altered_authselect.rc == 0
fail_msg:
- authselect is not used but files from the 'pam' package have been altered,
so the authselect configuration won't be forced.
when: ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
tags:
- NIST-800-53-AC-3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.4
- configure_strategy
- enable_authselect
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Enable authselect - Force authselect Profile Selection
ansible.builtin.command:
cmd: authselect select --force "{{ var_authselect_profile }}"
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- result_authselect_current.rc != 0
- result_authselect_select.rc != 0
- result_altered_authselect.rc == 0
tags:
- NIST-800-53-AC-3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.4
- configure_strategy
- enable_authselect
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Limit Password Reuse - Check if system relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- CJIS-5.6.2.1.1
- 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
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.7
- accounts_password_pam_unix_remember
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Limit Password Reuse - Collect the available authselect features
ansible.builtin.command:
cmd: authselect list-features sssd
register: result_authselect_available_features
changed_when: false
check_mode: false
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
- result_authselect_present.stat.exists
tags:
- CJIS-5.6.2.1.1
- 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
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.7
- accounts_password_pam_unix_remember
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Limit Password Reuse - Enable pam_pwhistory.so using authselect feature
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
check_mode: false
failed_when: false
- name: Limit Password Reuse - Informative message based on the authselect integrity
check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Limit Password Reuse - Get authselect current features
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_check_cmd is success
- name: Limit Password Reuse - Ensure "with-pwhistory" feature is enabled using
authselect tool
ansible.builtin.command:
cmd: authselect enable-feature with-pwhistory
register: result_authselect_enable_feature_cmd
when:
- result_authselect_check_cmd is success
- result_authselect_features.stdout is not search("with-pwhistory")
- name: Limit Password Reuse - 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:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
- result_authselect_present.stat.exists
- result_authselect_available_features.stdout is search("with-pwhistory")
tags:
- CJIS-5.6.2.1.1
- 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
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.7
- accounts_password_pam_unix_remember
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Limit Password Reuse - Enable pam_pwhistory.so in appropriate PAM files
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 tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Limit Password Reuse - Ensure authselect custom profile is used if authselect
is present
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
check_mode: false
failed_when: false
- name: Limit Password Reuse - Informative message based on the authselect integrity
check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- 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
check_mode: 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:
- result_authselect_profile is not skipped
- 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Limit Password Reuse - Create an authselect custom profile based on
sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Limit Password Reuse - Define a fact for control already filtered in case
filters are used
ansible.builtin.set_fact:
pam_module_control: requisite
- 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+{{ pam_module_control | regex_escape() }}\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: \1{{ pam_module_control }} \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 {{ pam_module_control }} 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 is defined
- 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
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
- |
(result_authselect_available_features.stdout is defined and result_authselect_available_features.stdout is not search("with-pwhistory")) or result_authselect_available_features is not defined
tags:
- CJIS-5.6.2.1.1
- 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
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.7
- accounts_password_pam_unix_remember
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Limit Password Reuse - Check the presence of /etc/security/pwhistory.conf
file
ansible.builtin.stat:
path: /etc/security/pwhistory.conf
register: result_pwhistory_conf_check
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- CJIS-5.6.2.1.1
- 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
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.7
- accounts_password_pam_unix_remember
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Limit Password Reuse - pam_pwhistory.so parameters are configured in /etc/security/pwhistory.conf
file
block:
- name: Limit Password Reuse - Ensure the pam_pwhistory.so remember parameter
in /etc/security/pwhistory.conf
ansible.builtin.lineinfile:
path: /etc/security/pwhistory.conf
regexp: ^\s*remember\s*=
line: remember = {{ var_password_pam_unix_remember }}
state: present
- name: Limit Password Reuse - Ensure the pam_pwhistory.so remember parameter
is removed from PAM files
block:
- 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_auth_file_present
- 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 tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Limit Password Reuse - Ensure authselect custom profile is used if
authselect is present
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
check_mode: false
failed_when: false
- name: Limit Password Reuse - Informative message based on the authselect
integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile
was not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect
tool is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- 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
check_mode: 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:
- result_authselect_profile is not skipped
- 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Limit Password Reuse - Create an authselect custom profile based
on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Limit Password Reuse - Define a fact for control already filtered
in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Limit Password Reuse - Check if {{ pam_file_path }} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- name: Limit Password Reuse - Ensure the "remember" option from "pam_pwhistory.so"
is not present in {{ pam_file_path }}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: (.*password.*pam_pwhistory.so.*)\bremember\b=?[0-9a-zA-Z]*(.*)
replace: \1\2
register: result_pam_option_removal
when:
- result_pam_file_present.stat.exists
- 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_option_removal is changed
when:
- result_pam_auth_file_present.stat.exists
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
- result_pwhistory_conf_check.stat.exists
tags:
- CJIS-5.6.2.1.1
- 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
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.7
- accounts_password_pam_unix_remember
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Limit Password Reuse - pam_pwhistory.so parameters are configured in PAM
files
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 tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Limit Password Reuse - Ensure authselect custom profile is used if authselect
is present
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
check_mode: false
failed_when: false
- name: Limit Password Reuse - Informative message based on the authselect integrity
check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- 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
check_mode: 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:
- result_authselect_profile is not skipped
- 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Limit Password Reuse - Create an authselect custom profile based on
sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Limit Password Reuse - Define a fact for control already filtered in case
filters are used
ansible.builtin.set_fact:
pam_module_control: requisite
- 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+{{ pam_module_control | regex_escape() }}\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: \1{{ pam_module_control }} \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 }}'
line: password {{ pam_module_control }} 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 is defined
- 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 - Define a fact for control already filtered in case
filters are used
ansible.builtin.set_fact:
pam_module_control: requisite
- 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+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s*.*\sremember\b
state: absent
check_mode: true
changed_when: false
register: result_pam_module_accounts_password_pam_unix_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+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so.*)
line: \1 remember={{ var_password_pam_unix_remember }}
state: present
register: result_pam_accounts_password_pam_unix_remember_add
when:
- result_pam_module_accounts_password_pam_unix_remember_option_present.found
is defined
- result_pam_module_accounts_password_pam_unix_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+{{ pam_module_control | regex_escape() }}\s+pam_pwhistory.so\s+.*)(remember)=[0-9a-zA-Z]*\s*(.*)
line: \1\2={{ var_password_pam_unix_remember }} \3
register: result_pam_accounts_password_pam_unix_remember_edit
when:
- result_pam_module_accounts_password_pam_unix_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:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
- not result_pwhistory_conf_check.stat.exists
tags:
- CJIS-5.6.2.1.1
- 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
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.7
- accounts_password_pam_unix_remember
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Lock Accounts After Failed Password Attempts - Check if system relies on
authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020011
- NIST-800-171-3.1.8
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.1.6
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.4
- accounts_passwords_pam_faillock_deny
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Lock Accounts After Failed Password Attempts - Remediation where authselect
tool is present
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
check_mode: false
failed_when: false
- name: Lock Accounts After Failed Password Attempts - Informative message based
on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Lock Accounts After Failed Password Attempts - Get authselect current
features
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_check_cmd is success
- 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_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:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- result_authselect_present.stat.exists
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020011
- NIST-800-171-3.1.8
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.1.6
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.4
- accounts_passwords_pam_faillock_deny
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Lock Accounts After Failed Password Attempts - Remediation where authselect
tool is not present
block:
- name: Lock Accounts After Failed Password Attempts - Check if pam_faillock.so
is already enabled
ansible.builtin.lineinfile:
path: /etc/pam.d/system-auth
regexp: .*auth.*pam_faillock\.so (preauth|authfail)
state: absent
check_mode: true
changed_when: false
register: result_pam_faillock_is_enabled
- name: Lock Accounts After Failed Password Attempts - Enable pam_faillock.so
preauth editing PAM files
ansible.builtin.lineinfile:
path: '{{ item }}'
line: auth required pam_faillock.so preauth
insertbefore: ^auth.*sufficient.*pam_unix\.so.*
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_is_enabled.found == 0
- name: Lock Accounts After Failed Password Attempts - Enable pam_faillock.so
authfail editing PAM files
ansible.builtin.lineinfile:
path: '{{ item }}'
line: auth required pam_faillock.so authfail
insertbefore: ^auth.*required.*pam_deny\.so.*
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_is_enabled.found == 0
- name: Lock Accounts After Failed Password Attempts - Enable pam_faillock.so
account section editing PAM files
ansible.builtin.lineinfile:
path: '{{ item }}'
line: account required pam_faillock.so
insertbefore: ^account.*required.*pam_unix\.so.*
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_is_enabled.found == 0
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- not result_authselect_present.stat.exists
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020011
- NIST-800-171-3.1.8
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.1.6
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.4
- accounts_passwords_pam_faillock_deny
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Lock Accounts After Failed Password Attempts - Check the presence of /etc/security/faillock.conf
file
ansible.builtin.stat:
path: /etc/security/faillock.conf
register: result_faillock_conf_check
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020011
- NIST-800-171-3.1.8
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.1.6
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.4
- accounts_passwords_pam_faillock_deny
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Lock Accounts After Failed Password Attempts - Ensure the pam_faillock.so
deny parameter in /etc/security/faillock.conf
ansible.builtin.lineinfile:
path: /etc/security/faillock.conf
regexp: ^\s*deny\s*=
line: deny = {{ var_accounts_passwords_pam_faillock_deny }}
state: present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- result_faillock_conf_check.stat.exists
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020011
- NIST-800-171-3.1.8
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.1.6
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.4
- 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_auth_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 tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Lock Accounts After Failed Password Attempts - Ensure authselect custom
profile is used if authselect is present
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
check_mode: false
failed_when: false
- name: Lock Accounts After Failed Password Attempts - Informative message
based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile
was not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect
tool is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- 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
check_mode: 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:
- result_authselect_profile is not skipped
- 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Lock Accounts After Failed Password Attempts - Create an authselect
custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Lock Accounts After Failed Password Attempts - Define a fact for control
already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Lock Accounts After Failed Password Attempts - Check if {{ pam_file_path
}} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- 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
when:
- result_pam_file_present.stat.exists
- 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_auth_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_password_auth_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 tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Lock Accounts After Failed Password Attempts - Ensure authselect custom
profile is used if authselect is present
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
check_mode: false
failed_when: false
- name: Lock Accounts After Failed Password Attempts - Informative message
based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile
was not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect
tool is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- 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
check_mode: 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:
- result_authselect_profile is not skipped
- 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Lock Accounts After Failed Password Attempts - Create an authselect
custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Lock Accounts After Failed Password Attempts - Define a fact for control
already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Lock Accounts After Failed Password Attempts - Check if {{ pam_file_path
}} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- 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
when:
- result_pam_file_present.stat.exists
- 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_password_auth_file_present.stat.exists
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- result_faillock_conf_check.stat.exists
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020011
- NIST-800-171-3.1.8
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.1.6
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.4
- accounts_passwords_pam_faillock_deny
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Lock Accounts After Failed Password Attempts - Ensure the pam_faillock.so
deny parameter in PAM files
block:
- name: Lock Accounts After Failed Password Attempts - Check if pam_faillock.so
deny parameter is already enabled in pam files
ansible.builtin.lineinfile:
path: /etc/pam.d/system-auth
regexp: .*auth.*pam_faillock\.so (preauth|authfail).*deny
state: absent
check_mode: true
changed_when: false
register: result_pam_faillock_deny_parameter_is_present
- name: Lock Accounts After Failed Password Attempts - Ensure the inclusion of
pam_faillock.so preauth deny parameter in auth section
ansible.builtin.lineinfile:
path: '{{ item }}'
backrefs: true
regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so preauth.*)
line: \1required\3 deny={{ var_accounts_passwords_pam_faillock_deny }}
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_deny_parameter_is_present.found == 0
- name: Lock Accounts After Failed Password Attempts - Ensure the inclusion of
pam_faillock.so authfail deny parameter in auth section
ansible.builtin.lineinfile:
path: '{{ item }}'
backrefs: true
regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so authfail.*)
line: \1required\3 deny={{ var_accounts_passwords_pam_faillock_deny }}
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_deny_parameter_is_present.found == 0
- name: Lock Accounts After Failed Password Attempts - Ensure the desired value
for pam_faillock.so preauth deny parameter in auth section
ansible.builtin.lineinfile:
path: '{{ item }}'
backrefs: true
regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so preauth.*)(deny)=[0-9]+(.*)
line: \1required\3\4={{ var_accounts_passwords_pam_faillock_deny }}\5
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_deny_parameter_is_present.found > 0
- name: Lock Accounts After Failed Password Attempts - Ensure the desired value
for pam_faillock.so authfail deny parameter in auth section
ansible.builtin.lineinfile:
path: '{{ item }}'
backrefs: true
regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so authfail.*)(deny)=[0-9]+(.*)
line: \1required\3\4={{ var_accounts_passwords_pam_faillock_deny }}\5
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_deny_parameter_is_present.found > 0
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- not result_faillock_conf_check.stat.exists
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020011
- NIST-800-171-3.1.8
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.1.6
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.4
- accounts_passwords_pam_faillock_deny
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Configure the root Account for Failed Password Attempts - Check if system
relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
tags:
- DISA-STIG-OL08-00-020023
- NIST-800-53-AC-7(b)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(c)
- accounts_passwords_pam_faillock_deny_root
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Configure the root Account for Failed Password Attempts - Remediation where
authselect tool is present
block:
- name: Configure the root Account for Failed Password Attempts - Check integrity
of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Configure the root Account for Failed Password Attempts - Informative
message based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Configure the root Account for Failed Password Attempts - Get authselect
current features
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_check_cmd is success
- name: Configure the root Account 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_enable_feature_cmd
when:
- result_authselect_check_cmd is success
- result_authselect_features.stdout is not search("with-faillock")
- name: Configure the root Account for Failed Password Attempts - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b
when:
- result_authselect_enable_feature_cmd is not skipped
- result_authselect_enable_feature_cmd is success
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- result_authselect_present.stat.exists
tags:
- DISA-STIG-OL08-00-020023
- NIST-800-53-AC-7(b)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(c)
- accounts_passwords_pam_faillock_deny_root
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Configure the root Account for Failed Password Attempts - Remediation where
authselect tool is not present
block:
- name: Configure the root Account for Failed Password Attempts - Check if pam_faillock.so
is already enabled
ansible.builtin.lineinfile:
path: /etc/pam.d/system-auth
regexp: .*auth.*pam_faillock\.so (preauth|authfail)
state: absent
check_mode: true
changed_when: false
register: result_pam_faillock_is_enabled
- name: Configure the root Account for Failed Password Attempts - Enable pam_faillock.so
preauth editing PAM files
ansible.builtin.lineinfile:
path: '{{ item }}'
line: auth required pam_faillock.so preauth
insertbefore: ^auth.*sufficient.*pam_unix\.so.*
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_is_enabled.found == 0
- name: Configure the root Account for Failed Password Attempts - Enable pam_faillock.so
authfail editing PAM files
ansible.builtin.lineinfile:
path: '{{ item }}'
line: auth required pam_faillock.so authfail
insertbefore: ^auth.*required.*pam_deny\.so.*
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_is_enabled.found == 0
- name: Configure the root Account for Failed Password Attempts - Enable pam_faillock.so
account section editing PAM files
ansible.builtin.lineinfile:
path: '{{ item }}'
line: account required pam_faillock.so
insertbefore: ^account.*required.*pam_unix\.so.*
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_is_enabled.found == 0
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- not result_authselect_present.stat.exists
tags:
- DISA-STIG-OL08-00-020023
- NIST-800-53-AC-7(b)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(c)
- accounts_passwords_pam_faillock_deny_root
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Configure the root Account for Failed Password Attempts - Check the presence
of /etc/security/faillock.conf file
ansible.builtin.stat:
path: /etc/security/faillock.conf
register: result_faillock_conf_check
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
tags:
- DISA-STIG-OL08-00-020023
- NIST-800-53-AC-7(b)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(c)
- accounts_passwords_pam_faillock_deny_root
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Configure the root Account for Failed Password Attempts - Ensure the pam_faillock.so
even_deny_root parameter in /etc/security/faillock.conf
ansible.builtin.lineinfile:
path: /etc/security/faillock.conf
regexp: ^\s*even_deny_root
line: even_deny_root
state: present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- result_faillock_conf_check.stat.exists
tags:
- DISA-STIG-OL08-00-020023
- NIST-800-53-AC-7(b)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(c)
- accounts_passwords_pam_faillock_deny_root
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Configure the root Account for Failed Password Attempts - Ensure the pam_faillock.so
even_deny_root parameter not in PAM files
block:
- name: Configure the root Account for Failed Password Attempts - Check if /etc/pam.d/system-auth
file is present
ansible.builtin.stat:
path: /etc/pam.d/system-auth
register: result_pam_auth_file_present
- name: Configure the root Account for Failed Password Attempts - Check the proper
remediation for the system
block:
- name: Configure the root Account for Failed Password Attempts - Define the
PAM file to be edited as a local fact
ansible.builtin.set_fact:
pam_file_path: /etc/pam.d/system-auth
- name: Configure the root Account for Failed Password Attempts - Check if system
relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Configure the root Account for Failed Password Attempts - Ensure authselect
custom profile is used if authselect is present
block:
- name: Configure the root Account for Failed Password Attempts - Check integrity
of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Configure the root Account for Failed Password Attempts - Informative
message based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile
was not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect
tool is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Configure the root Account for Failed Password Attempts - Get authselect
current profile
ansible.builtin.shell:
cmd: authselect current -r | awk '{ print $1 }'
register: result_authselect_profile
changed_when: false
when:
- result_authselect_check_cmd is success
- name: Configure the root Account for Failed Password Attempts - Define the
current authselect profile as a local fact
ansible.builtin.set_fact:
authselect_current_profile: '{{ result_authselect_profile.stdout }}'
authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
when:
- result_authselect_profile is not skipped
- result_authselect_profile.stdout is match("custom/")
- name: Configure the root Account for Failed Password Attempts - Define the
new authselect custom profile as a local fact
ansible.builtin.set_fact:
authselect_current_profile: '{{ result_authselect_profile.stdout }}'
authselect_custom_profile: custom/hardening
when:
- result_authselect_profile is not skipped
- result_authselect_profile.stdout is not match("custom/")
- name: Configure the root Account for Failed Password Attempts - Get authselect
current features to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Configure the root Account for Failed Password Attempts - Check if
any custom profile with the same name was already created
ansible.builtin.stat:
path: /etc/authselect/{{ authselect_custom_profile }}
register: result_authselect_custom_profile_present
changed_when: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Configure the root Account for Failed Password Attempts - Create an
authselect custom profile based on the current profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b {{ authselect_current_profile
}}
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Configure the root Account for Failed Password Attempts - Create an
authselect custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Configure the root Account for Failed Password Attempts - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- authselect_custom_profile is not match(authselect_current_profile)
- name: Configure the root Account for Failed Password Attempts - Ensure the
authselect custom profile is selected
ansible.builtin.command:
cmd: authselect select {{ authselect_custom_profile }}
register: result_pam_authselect_select_profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- authselect_custom_profile is not match(authselect_current_profile)
- name: Configure the root Account for Failed Password Attempts - Restore
the authselect features in the custom profile
ansible.builtin.command:
cmd: authselect enable-feature {{ item }}
loop: '{{ result_authselect_features.stdout_lines }}'
register: result_pam_authselect_restore_features
when:
- result_authselect_profile is not skipped
- result_authselect_features is not skipped
- result_pam_authselect_select_profile is not skipped
- name: Configure the root Account for Failed Password Attempts - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- result_pam_authselect_restore_features is not skipped
- name: Configure the root Account for Failed Password Attempts - Change the
PAM file to be edited according to the custom authselect profile
ansible.builtin.set_fact:
pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
| basename }}
when:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Configure the root Account for Failed Password Attempts - Define a fact
for control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Configure the root Account for Failed Password Attempts - Check if {{
pam_file_path }} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- name: Configure the root Account for Failed Password Attempts - Ensure the
"even_deny_root" option from "pam_faillock.so" is not present in {{ pam_file_path
}}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: (.*auth.*pam_faillock.so.*)\beven_deny_root\b=?[0-9a-zA-Z]*(.*)
replace: \1\2
register: result_pam_option_removal
when:
- result_pam_file_present.stat.exists
- name: Configure the root Account for Failed Password Attempts - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b
when:
- result_authselect_present.stat.exists
- result_pam_option_removal is changed
when:
- result_pam_auth_file_present.stat.exists
- name: Configure the root Account for Failed Password Attempts - Check if /etc/pam.d/password-auth
file is present
ansible.builtin.stat:
path: /etc/pam.d/password-auth
register: result_pam_password_auth_file_present
- name: Configure the root Account for Failed Password Attempts - Check the proper
remediation for the system
block:
- name: Configure the root Account for Failed Password Attempts - Define the
PAM file to be edited as a local fact
ansible.builtin.set_fact:
pam_file_path: /etc/pam.d/password-auth
- name: Configure the root Account for Failed Password Attempts - Check if system
relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Configure the root Account for Failed Password Attempts - Ensure authselect
custom profile is used if authselect is present
block:
- name: Configure the root Account for Failed Password Attempts - Check integrity
of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Configure the root Account for Failed Password Attempts - Informative
message based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile
was not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect
tool is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Configure the root Account for Failed Password Attempts - Get authselect
current profile
ansible.builtin.shell:
cmd: authselect current -r | awk '{ print $1 }'
register: result_authselect_profile
changed_when: false
when:
- result_authselect_check_cmd is success
- name: Configure the root Account for Failed Password Attempts - Define the
current authselect profile as a local fact
ansible.builtin.set_fact:
authselect_current_profile: '{{ result_authselect_profile.stdout }}'
authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
when:
- result_authselect_profile is not skipped
- result_authselect_profile.stdout is match("custom/")
- name: Configure the root Account for Failed Password Attempts - Define the
new authselect custom profile as a local fact
ansible.builtin.set_fact:
authselect_current_profile: '{{ result_authselect_profile.stdout }}'
authselect_custom_profile: custom/hardening
when:
- result_authselect_profile is not skipped
- result_authselect_profile.stdout is not match("custom/")
- name: Configure the root Account for Failed Password Attempts - Get authselect
current features to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Configure the root Account for Failed Password Attempts - Check if
any custom profile with the same name was already created
ansible.builtin.stat:
path: /etc/authselect/{{ authselect_custom_profile }}
register: result_authselect_custom_profile_present
changed_when: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Configure the root Account for Failed Password Attempts - Create an
authselect custom profile based on the current profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b {{ authselect_current_profile
}}
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Configure the root Account for Failed Password Attempts - Create an
authselect custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Configure the root Account for Failed Password Attempts - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- authselect_custom_profile is not match(authselect_current_profile)
- name: Configure the root Account for Failed Password Attempts - Ensure the
authselect custom profile is selected
ansible.builtin.command:
cmd: authselect select {{ authselect_custom_profile }}
register: result_pam_authselect_select_profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- authselect_custom_profile is not match(authselect_current_profile)
- name: Configure the root Account for Failed Password Attempts - Restore
the authselect features in the custom profile
ansible.builtin.command:
cmd: authselect enable-feature {{ item }}
loop: '{{ result_authselect_features.stdout_lines }}'
register: result_pam_authselect_restore_features
when:
- result_authselect_profile is not skipped
- result_authselect_features is not skipped
- result_pam_authselect_select_profile is not skipped
- name: Configure the root Account for Failed Password Attempts - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- result_pam_authselect_restore_features is not skipped
- name: Configure the root Account for Failed Password Attempts - Change the
PAM file to be edited according to the custom authselect profile
ansible.builtin.set_fact:
pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
| basename }}
when:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Configure the root Account for Failed Password Attempts - Define a fact
for control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Configure the root Account for Failed Password Attempts - Check if {{
pam_file_path }} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- name: Configure the root Account for Failed Password Attempts - Ensure the
"even_deny_root" option from "pam_faillock.so" is not present in {{ pam_file_path
}}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: (.*auth.*pam_faillock.so.*)\beven_deny_root\b=?[0-9a-zA-Z]*(.*)
replace: \1\2
register: result_pam_option_removal
when:
- result_pam_file_present.stat.exists
- name: Configure the root Account for Failed Password Attempts - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b
when:
- result_authselect_present.stat.exists
- result_pam_option_removal is changed
when:
- result_pam_password_auth_file_present.stat.exists
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- result_faillock_conf_check.stat.exists
tags:
- DISA-STIG-OL08-00-020023
- NIST-800-53-AC-7(b)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(c)
- accounts_passwords_pam_faillock_deny_root
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Configure the root Account for Failed Password Attempts - Ensure the pam_faillock.so
even_deny_root parameter in PAM files
block:
- name: Configure the root Account for Failed Password Attempts - Check if pam_faillock.so
even_deny_root parameter is already enabled in pam files
ansible.builtin.lineinfile:
path: /etc/pam.d/system-auth
regexp: .*auth.*pam_faillock\.so (preauth|authfail).*even_deny_root
state: absent
check_mode: true
changed_when: false
register: result_pam_faillock_even_deny_root_parameter_is_present
- name: Configure the root Account for Failed Password Attempts - Ensure the inclusion
of pam_faillock.so preauth even_deny_root parameter in auth section
ansible.builtin.lineinfile:
path: '{{ item }}'
backrefs: true
regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so preauth.*)
line: \1required\3 even_deny_root
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_even_deny_root_parameter_is_present.found == 0
- name: Configure the root Account for Failed Password Attempts - Ensure the inclusion
of pam_faillock.so authfail even_deny_root parameter in auth section
ansible.builtin.lineinfile:
path: '{{ item }}'
backrefs: true
regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so authfail.*)
line: \1required\3 even_deny_root
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_even_deny_root_parameter_is_present.found == 0
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- not result_faillock_conf_check.stat.exists
tags:
- DISA-STIG-OL08-00-020023
- NIST-800-53-AC-7(b)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(c)
- accounts_passwords_pam_faillock_deny_root
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Set Interval For Counting Failed Password Attempts - Check if system relies
on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
tags:
- DISA-STIG-OL08-00-020013
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- accounts_passwords_pam_faillock_interval
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Set Interval For Counting Failed Password Attempts - Remediation where authselect
tool is present
block:
- name: Set Interval For Counting Failed Password Attempts - Check integrity of
authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Set Interval For Counting Failed Password Attempts - Informative message
based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Set Interval For Counting Failed Password Attempts - Get authselect current
features
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_check_cmd is success
- name: Set Interval For Counting Failed Password Attempts - Ensure "with-faillock"
feature is enabled using authselect tool
ansible.builtin.command:
cmd: authselect enable-feature with-faillock
register: result_authselect_enable_feature_cmd
when:
- result_authselect_check_cmd is success
- result_authselect_features.stdout is not search("with-faillock")
- name: Set Interval For Counting 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:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- result_authselect_present.stat.exists
tags:
- DISA-STIG-OL08-00-020013
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- accounts_passwords_pam_faillock_interval
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Set Interval For Counting Failed Password Attempts - Remediation where authselect
tool is not present
block:
- name: Set Interval For Counting Failed Password Attempts - Check if pam_faillock.so
is already enabled
ansible.builtin.lineinfile:
path: /etc/pam.d/system-auth
regexp: .*auth.*pam_faillock\.so (preauth|authfail)
state: absent
check_mode: true
changed_when: false
register: result_pam_faillock_is_enabled
- name: Set Interval For Counting Failed Password Attempts - Enable pam_faillock.so
preauth editing PAM files
ansible.builtin.lineinfile:
path: '{{ item }}'
line: auth required pam_faillock.so preauth
insertbefore: ^auth.*sufficient.*pam_unix\.so.*
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_is_enabled.found == 0
- name: Set Interval For Counting Failed Password Attempts - Enable pam_faillock.so
authfail editing PAM files
ansible.builtin.lineinfile:
path: '{{ item }}'
line: auth required pam_faillock.so authfail
insertbefore: ^auth.*required.*pam_deny\.so.*
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_is_enabled.found == 0
- name: Set Interval For Counting Failed Password Attempts - Enable pam_faillock.so
account section editing PAM files
ansible.builtin.lineinfile:
path: '{{ item }}'
line: account required pam_faillock.so
insertbefore: ^account.*required.*pam_unix\.so.*
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_is_enabled.found == 0
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- not result_authselect_present.stat.exists
tags:
- DISA-STIG-OL08-00-020013
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- accounts_passwords_pam_faillock_interval
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Set Interval For Counting Failed Password Attempts - Check the presence
of /etc/security/faillock.conf file
ansible.builtin.stat:
path: /etc/security/faillock.conf
register: result_faillock_conf_check
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
tags:
- DISA-STIG-OL08-00-020013
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- accounts_passwords_pam_faillock_interval
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Set Interval For Counting Failed Password Attempts - Ensure the pam_faillock.so
fail_interval parameter in /etc/security/faillock.conf
ansible.builtin.lineinfile:
path: /etc/security/faillock.conf
regexp: ^\s*fail_interval\s*=
line: fail_interval = {{ var_accounts_passwords_pam_faillock_fail_interval }}
state: present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- result_faillock_conf_check.stat.exists
tags:
- DISA-STIG-OL08-00-020013
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- accounts_passwords_pam_faillock_interval
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Set Interval For Counting Failed Password Attempts - Ensure the pam_faillock.so
fail_interval parameter not in PAM files
block:
- name: Set Interval For Counting 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_auth_file_present
- name: Set Interval For Counting Failed Password Attempts - Check the proper
remediation for the system
block:
- name: Set Interval For Counting 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 Interval For Counting Failed Password Attempts - Check if system
relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Set Interval For Counting Failed Password Attempts - Ensure authselect
custom profile is used if authselect is present
block:
- name: Set Interval For Counting Failed Password Attempts - Check integrity
of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Set Interval For Counting Failed Password Attempts - Informative message
based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile
was not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect
tool is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Set Interval For Counting 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 Interval For Counting 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 Interval For Counting 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 Interval For Counting 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
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Set Interval For Counting 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:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Set Interval For Counting 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Set Interval For Counting Failed Password Attempts - Create an authselect
custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Set Interval For Counting 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 Interval For Counting 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 Interval For Counting 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 Interval For Counting 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 Interval For Counting 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Set Interval For Counting Failed Password Attempts - Define a fact for
control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Set Interval For Counting Failed Password Attempts - Check if {{ pam_file_path
}} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- name: Set Interval For Counting Failed Password Attempts - Ensure the "fail_interval"
option from "pam_faillock.so" is not present in {{ pam_file_path }}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: (.*auth.*pam_faillock.so.*)\bfail_interval\b=?[0-9a-zA-Z]*(.*)
replace: \1\2
register: result_pam_option_removal
when:
- result_pam_file_present.stat.exists
- name: Set Interval For Counting 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_auth_file_present.stat.exists
- name: Set Interval For Counting 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_password_auth_file_present
- name: Set Interval For Counting Failed Password Attempts - Check the proper
remediation for the system
block:
- name: Set Interval For Counting 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 Interval For Counting Failed Password Attempts - Check if system
relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Set Interval For Counting Failed Password Attempts - Ensure authselect
custom profile is used if authselect is present
block:
- name: Set Interval For Counting Failed Password Attempts - Check integrity
of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Set Interval For Counting Failed Password Attempts - Informative message
based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile
was not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect
tool is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Set Interval For Counting 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 Interval For Counting 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 Interval For Counting 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 Interval For Counting 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
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Set Interval For Counting 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:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Set Interval For Counting 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Set Interval For Counting Failed Password Attempts - Create an authselect
custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Set Interval For Counting 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 Interval For Counting 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 Interval For Counting 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 Interval For Counting 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 Interval For Counting 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Set Interval For Counting Failed Password Attempts - Define a fact for
control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Set Interval For Counting Failed Password Attempts - Check if {{ pam_file_path
}} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- name: Set Interval For Counting Failed Password Attempts - Ensure the "fail_interval"
option from "pam_faillock.so" is not present in {{ pam_file_path }}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: (.*auth.*pam_faillock.so.*)\bfail_interval\b=?[0-9a-zA-Z]*(.*)
replace: \1\2
register: result_pam_option_removal
when:
- result_pam_file_present.stat.exists
- name: Set Interval For Counting 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_password_auth_file_present.stat.exists
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- result_faillock_conf_check.stat.exists
tags:
- DISA-STIG-OL08-00-020013
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- accounts_passwords_pam_faillock_interval
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Set Interval For Counting Failed Password Attempts - Ensure the pam_faillock.so
fail_interval parameter in PAM files
block:
- name: Set Interval For Counting Failed Password Attempts - Check if pam_faillock.so
fail_interval parameter is already enabled in pam files
ansible.builtin.lineinfile:
path: /etc/pam.d/system-auth
regexp: .*auth.*pam_faillock\.so (preauth|authfail).*fail_interval
state: absent
check_mode: true
changed_when: false
register: result_pam_faillock_fail_interval_parameter_is_present
- name: Set Interval For Counting Failed Password Attempts - Ensure the inclusion
of pam_faillock.so preauth fail_interval parameter in auth section
ansible.builtin.lineinfile:
path: '{{ item }}'
backrefs: true
regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so preauth.*)
line: \1required\3 fail_interval={{ var_accounts_passwords_pam_faillock_fail_interval
}}
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_fail_interval_parameter_is_present.found == 0
- name: Set Interval For Counting Failed Password Attempts - Ensure the inclusion
of pam_faillock.so authfail fail_interval parameter in auth section
ansible.builtin.lineinfile:
path: '{{ item }}'
backrefs: true
regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so authfail.*)
line: \1required\3 fail_interval={{ var_accounts_passwords_pam_faillock_fail_interval
}}
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_fail_interval_parameter_is_present.found == 0
- name: Set Interval For Counting Failed Password Attempts - Ensure the desired
value for pam_faillock.so preauth fail_interval parameter in auth section
ansible.builtin.lineinfile:
path: '{{ item }}'
backrefs: true
regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so preauth.*)(fail_interval)=[0-9]+(.*)
line: \1required\3\4={{ var_accounts_passwords_pam_faillock_fail_interval
}}\5
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_fail_interval_parameter_is_present.found > 0
- name: Set Interval For Counting Failed Password Attempts - Ensure the desired
value for pam_faillock.so authfail fail_interval parameter in auth section
ansible.builtin.lineinfile:
path: '{{ item }}'
backrefs: true
regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so authfail.*)(fail_interval)=[0-9]+(.*)
line: \1required\3\4={{ var_accounts_passwords_pam_faillock_fail_interval
}}\5
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_fail_interval_parameter_is_present.found > 0
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- not result_faillock_conf_check.stat.exists
tags:
- DISA-STIG-OL08-00-020013
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- accounts_passwords_pam_faillock_interval
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Set Lockout Time for Failed Password Attempts - Check if system relies on
authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020015
- NIST-800-171-3.1.8
- NIST-800-53-AC-7(b)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.1.7
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.4
- 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 - Remediation where authselect
tool is present
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
check_mode: false
failed_when: false
- name: Set Lockout Time for Failed Password Attempts - Informative message based
on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Set Lockout Time for Failed Password Attempts - Get authselect current
features
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: 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
ansible.builtin.command:
cmd: authselect enable-feature with-faillock
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:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- result_authselect_present.stat.exists
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020015
- NIST-800-171-3.1.8
- NIST-800-53-AC-7(b)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.1.7
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.4
- 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 - Remediation where authselect
tool is not present
block:
- name: Set Lockout Time for Failed Password Attempts - Check if pam_faillock.so
is already enabled
ansible.builtin.lineinfile:
path: /etc/pam.d/system-auth
regexp: .*auth.*pam_faillock\.so (preauth|authfail)
state: absent
check_mode: true
changed_when: false
register: result_pam_faillock_is_enabled
- name: Set Lockout Time for Failed Password Attempts - Enable pam_faillock.so
preauth editing PAM files
ansible.builtin.lineinfile:
path: '{{ item }}'
line: auth required pam_faillock.so preauth
insertbefore: ^auth.*sufficient.*pam_unix\.so.*
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_is_enabled.found == 0
- name: Set Lockout Time for Failed Password Attempts - Enable pam_faillock.so
authfail editing PAM files
ansible.builtin.lineinfile:
path: '{{ item }}'
line: auth required pam_faillock.so authfail
insertbefore: ^auth.*required.*pam_deny\.so.*
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_is_enabled.found == 0
- name: Set Lockout Time for Failed Password Attempts - Enable pam_faillock.so
account section editing PAM files
ansible.builtin.lineinfile:
path: '{{ item }}'
line: account required pam_faillock.so
insertbefore: ^account.*required.*pam_unix\.so.*
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_is_enabled.found == 0
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- not result_authselect_present.stat.exists
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020015
- NIST-800-171-3.1.8
- NIST-800-53-AC-7(b)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.1.7
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.4
- 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 - Check the presence of /etc/security/faillock.conf
file
ansible.builtin.stat:
path: /etc/security/faillock.conf
register: result_faillock_conf_check
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020015
- NIST-800-171-3.1.8
- NIST-800-53-AC-7(b)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.1.7
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.4
- 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 in /etc/security/faillock.conf
ansible.builtin.lineinfile:
path: /etc/security/faillock.conf
regexp: ^\s*unlock_time\s*=
line: unlock_time = {{ var_accounts_passwords_pam_faillock_unlock_time }}
state: present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- result_faillock_conf_check.stat.exists
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020015
- NIST-800-171-3.1.8
- NIST-800-53-AC-7(b)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.1.7
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.4
- 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_auth_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 tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Set Lockout Time for Failed Password Attempts - Ensure authselect custom
profile is used if authselect is present
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
check_mode: false
failed_when: false
- name: Set Lockout Time for Failed Password Attempts - Informative message
based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile
was not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect
tool is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- 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
check_mode: 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:
- result_authselect_profile is not skipped
- 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Set Lockout Time for Failed Password Attempts - Create an authselect
custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Set Lockout Time for Failed Password Attempts - Define a fact for control
already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Set Lockout Time for Failed Password Attempts - Check if {{ pam_file_path
}} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- 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
when:
- result_pam_file_present.stat.exists
- 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_auth_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_password_auth_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 tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Set Lockout Time for Failed Password Attempts - Ensure authselect custom
profile is used if authselect is present
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
check_mode: false
failed_when: false
- name: Set Lockout Time for Failed Password Attempts - Informative message
based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile
was not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect
tool is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- 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
check_mode: 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:
- result_authselect_profile is not skipped
- 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Set Lockout Time for Failed Password Attempts - Create an authselect
custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Set Lockout Time for Failed Password Attempts - Define a fact for control
already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Set Lockout Time for Failed Password Attempts - Check if {{ pam_file_path
}} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- 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
when:
- result_pam_file_present.stat.exists
- 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_password_auth_file_present.stat.exists
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- result_faillock_conf_check.stat.exists
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020015
- NIST-800-171-3.1.8
- NIST-800-53-AC-7(b)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.1.7
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.4
- 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 in PAM files
block:
- name: Set Lockout Time for Failed Password Attempts - Check if pam_faillock.so
unlock_time parameter is already enabled in pam files
ansible.builtin.lineinfile:
path: /etc/pam.d/system-auth
regexp: .*auth.*pam_faillock\.so (preauth|authfail).*unlock_time
state: absent
check_mode: true
changed_when: false
register: result_pam_faillock_unlock_time_parameter_is_present
- name: Set Lockout Time for Failed Password Attempts - Ensure the inclusion of
pam_faillock.so preauth unlock_time parameter in auth section
ansible.builtin.lineinfile:
path: '{{ item }}'
backrefs: true
regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so preauth.*)
line: \1required\3 unlock_time={{ var_accounts_passwords_pam_faillock_unlock_time
}}
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_unlock_time_parameter_is_present.found == 0
- name: Set Lockout Time for Failed Password Attempts - Ensure the inclusion of
pam_faillock.so authfail unlock_time parameter in auth section
ansible.builtin.lineinfile:
path: '{{ item }}'
backrefs: true
regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so authfail.*)
line: \1required\3 unlock_time={{ var_accounts_passwords_pam_faillock_unlock_time
}}
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_unlock_time_parameter_is_present.found == 0
- name: Set Lockout Time for Failed Password Attempts - Ensure the desired value
for pam_faillock.so preauth unlock_time parameter in auth section
ansible.builtin.lineinfile:
path: '{{ item }}'
backrefs: true
regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so preauth.*)(unlock_time)=[0-9]+(.*)
line: \1required\3\4={{ var_accounts_passwords_pam_faillock_unlock_time }}\5
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_unlock_time_parameter_is_present.found > 0
- name: Set Lockout Time for Failed Password Attempts - Ensure the desired value
for pam_faillock.so authfail unlock_time parameter in auth section
ansible.builtin.lineinfile:
path: '{{ item }}'
backrefs: true
regexp: (^\s*auth\s+)([\w\[].*\b)(\s+pam_faillock.so authfail.*)(unlock_time)=[0-9]+(.*)
line: \1required\3\4={{ var_accounts_passwords_pam_faillock_unlock_time }}\5
state: present
loop:
- /etc/pam.d/system-auth
- /etc/pam.d/password-auth
when:
- result_pam_faillock_unlock_time_parameter_is_present.found > 0
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.2', '>=') and "pam" in ansible_facts.packages )
- not result_faillock_conf_check.stat.exists
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020015
- NIST-800-171-3.1.8
- NIST-800-53-AC-7(b)
- NIST-800-53-CM-6(a)
- PCI-DSS-Req-8.1.7
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.4
- accounts_passwords_pam_faillock_unlock_time
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Find
pwquality.conf.d files
ansible.builtin.find:
paths: /etc/security/pwquality.conf.d/
patterns: '*.conf'
register: pwquality_conf_d_files
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020130
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_dcredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Ensure
dcredit is not set in pwquality.conf.d
ansible.builtin.lineinfile:
path: '{{ item.path }}'
regexp: ^\s*\bdcredit\b.*
state: absent
with_items: '{{ pwquality_conf_d_files.files }}'
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020130
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_dcredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Check
if /etc/pam.d/system-auth file is present
ansible.builtin.stat:
path: /etc/pam.d/system-auth
register: result_pam_auth_file_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020130
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_dcredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Check
the proper remediation for the system
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters -
Define the PAM file to be edited as a local fact
ansible.builtin.set_fact:
pam_file_path: /etc/pam.d/system-auth
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters -
Check if system relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters -
Ensure authselect custom profile is used if authselect is present
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters
- Check integrity of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters
- Informative message based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters
- 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 Enforces Password Requirements - Minimum Digit Characters
- 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 Enforces Password Requirements - Minimum Digit Characters
- 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 Enforces Password Requirements - Minimum Digit Characters
- Get authselect current features to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters
- 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:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters
- 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters
- Create an authselect custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters
- 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 Enforces Password Requirements - Minimum Digit Characters
- 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 Enforces Password Requirements - Minimum Digit Characters
- 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 Enforces Password Requirements - Minimum Digit Characters
- 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 Enforces Password Requirements - Minimum Digit Characters
- 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters -
Define a fact for control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters -
Check if {{ pam_file_path }} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters -
Ensure the "dcredit" option from "pam_pwquality.so" is not present in {{ pam_file_path
}}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: (.*password.*pam_pwquality.so.*)\bdcredit\b=?[0-9a-zA-Z]*(.*)
replace: \1\2
register: result_pam_option_removal
when:
- result_pam_file_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters -
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:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
- result_pam_auth_file_present.stat.exists
tags:
- DISA-STIG-OL08-00-020130
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_dcredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Check
if /etc/pam.d/password-auth file is present
ansible.builtin.stat:
path: /etc/pam.d/password-auth
register: result_pam_password_auth_file_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020130
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_dcredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Check
the proper remediation for the system
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters -
Define the PAM file to be edited as a local fact
ansible.builtin.set_fact:
pam_file_path: /etc/pam.d/password-auth
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters -
Check if system relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters -
Ensure authselect custom profile is used if authselect is present
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters
- Check integrity of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters
- Informative message based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters
- 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 Enforces Password Requirements - Minimum Digit Characters
- 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 Enforces Password Requirements - Minimum Digit Characters
- 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 Enforces Password Requirements - Minimum Digit Characters
- Get authselect current features to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters
- 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:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters
- 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters
- Create an authselect custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters
- 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 Enforces Password Requirements - Minimum Digit Characters
- 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 Enforces Password Requirements - Minimum Digit Characters
- 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 Enforces Password Requirements - Minimum Digit Characters
- 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 Enforces Password Requirements - Minimum Digit Characters
- 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters -
Define a fact for control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters -
Check if {{ pam_file_path }} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters -
Ensure the "dcredit" option from "pam_pwquality.so" is not present in {{ pam_file_path
}}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: (.*password.*pam_pwquality.so.*)\bdcredit\b=?[0-9a-zA-Z]*(.*)
replace: \1\2
register: result_pam_option_removal
when:
- result_pam_file_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters -
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:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
- result_pam_password_auth_file_present.stat.exists
tags:
- DISA-STIG-OL08-00-020130
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_dcredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Digit Characters - Ensure
PAM variable dcredit is set accordingly
ansible.builtin.lineinfile:
create: true
dest: /etc/security/pwquality.conf
regexp: ^#?\s*dcredit
line: dcredit = {{ var_password_pam_dcredit }}
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020130
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_dcredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Find pwquality.conf.d files
ansible.builtin.find:
paths: /etc/security/pwquality.conf.d/
patterns: '*.conf'
register: pwquality_conf_d_files
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020120
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_lcredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Ensure lcredit is not set in pwquality.conf.d
ansible.builtin.lineinfile:
path: '{{ item.path }}'
regexp: ^\s*\blcredit\b.*
state: absent
with_items: '{{ pwquality_conf_d_files.files }}'
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020120
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_lcredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Check if /etc/pam.d/system-auth file is present
ansible.builtin.stat:
path: /etc/pam.d/system-auth
register: result_pam_auth_file_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020120
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_lcredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Check the proper remediation for the system
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Define the PAM file to be edited as a local fact
ansible.builtin.set_fact:
pam_file_path: /etc/pam.d/system-auth
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Check if system relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Ensure authselect custom profile is used if authselect is present
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Check integrity of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Informative message based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- 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 Enforces Password Requirements - Minimum Lowercase Characters
- 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 Enforces Password Requirements - Minimum Lowercase Characters
- 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 Enforces Password Requirements - Minimum Lowercase Characters
- Get authselect current features to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- 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:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Create an authselect custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- 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 Enforces Password Requirements - Minimum Lowercase Characters
- 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 Enforces Password Requirements - Minimum Lowercase Characters
- 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 Enforces Password Requirements - Minimum Lowercase Characters
- 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 Enforces Password Requirements - Minimum Lowercase Characters
- 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Define a fact for control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Check if {{ pam_file_path }} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Ensure the "lcredit" option from "pam_pwquality.so" is not present in {{
pam_file_path }}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: (.*password.*pam_pwquality.so.*)\blcredit\b=?[0-9a-zA-Z]*(.*)
replace: \1\2
register: result_pam_option_removal
when:
- result_pam_file_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- 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:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
- result_pam_auth_file_present.stat.exists
tags:
- DISA-STIG-OL08-00-020120
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_lcredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Check if /etc/pam.d/password-auth file is present
ansible.builtin.stat:
path: /etc/pam.d/password-auth
register: result_pam_password_auth_file_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020120
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_lcredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Check the proper remediation for the system
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Define the PAM file to be edited as a local fact
ansible.builtin.set_fact:
pam_file_path: /etc/pam.d/password-auth
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Check if system relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Ensure authselect custom profile is used if authselect is present
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Check integrity of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Informative message based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- 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 Enforces Password Requirements - Minimum Lowercase Characters
- 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 Enforces Password Requirements - Minimum Lowercase Characters
- 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 Enforces Password Requirements - Minimum Lowercase Characters
- Get authselect current features to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- 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:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Create an authselect custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- 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 Enforces Password Requirements - Minimum Lowercase Characters
- 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 Enforces Password Requirements - Minimum Lowercase Characters
- 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 Enforces Password Requirements - Minimum Lowercase Characters
- 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 Enforces Password Requirements - Minimum Lowercase Characters
- 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Define a fact for control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Check if {{ pam_file_path }} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Ensure the "lcredit" option from "pam_pwquality.so" is not present in {{
pam_file_path }}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: (.*password.*pam_pwquality.so.*)\blcredit\b=?[0-9a-zA-Z]*(.*)
replace: \1\2
register: result_pam_option_removal
when:
- result_pam_file_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- 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:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
- result_pam_password_auth_file_present.stat.exists
tags:
- DISA-STIG-OL08-00-020120
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_lcredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Lowercase Characters
- Ensure PAM variable lcredit is set accordingly
ansible.builtin.lineinfile:
create: true
dest: /etc/security/pwquality.conf
regexp: ^#?\s*lcredit
line: lcredit = {{ var_password_pam_lcredit }}
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020120
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_lcredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Find pwquality.conf.d files
ansible.builtin.find:
paths: /etc/security/pwquality.conf.d/
patterns: '*.conf'
register: pwquality_conf_d_files
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020160
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- accounts_password_pam_minclass
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Ensure minclass is not set in pwquality.conf.d
ansible.builtin.lineinfile:
path: '{{ item.path }}'
regexp: ^\s*\bminclass\b.*
state: absent
with_items: '{{ pwquality_conf_d_files.files }}'
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020160
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- accounts_password_pam_minclass
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Check if /etc/pam.d/system-auth file is present
ansible.builtin.stat:
path: /etc/pam.d/system-auth
register: result_pam_auth_file_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020160
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- accounts_password_pam_minclass
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Check the proper remediation for the system
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Define the PAM file to be edited as a local fact
ansible.builtin.set_fact:
pam_file_path: /etc/pam.d/system-auth
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Check if system relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Ensure authselect custom profile is used if authselect is present
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Check integrity of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Informative message based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- 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 Enforces Password Requirements - Minimum Different Categories
- 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 Enforces Password Requirements - Minimum Different Categories
- 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 Enforces Password Requirements - Minimum Different Categories
- Get authselect current features to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- 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:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Create an authselect custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- 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 Enforces Password Requirements - Minimum Different Categories
- 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 Enforces Password Requirements - Minimum Different Categories
- 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 Enforces Password Requirements - Minimum Different Categories
- 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 Enforces Password Requirements - Minimum Different Categories
- 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Define a fact for control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Check if {{ pam_file_path }} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Ensure the "minclass" option from "pam_pwquality.so" is not present in {{
pam_file_path }}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: (.*password.*pam_pwquality.so.*)\bminclass\b=?[0-9a-zA-Z]*(.*)
replace: \1\2
register: result_pam_option_removal
when:
- result_pam_file_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- 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:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
- result_pam_auth_file_present.stat.exists
tags:
- DISA-STIG-OL08-00-020160
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- accounts_password_pam_minclass
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Check if /etc/pam.d/password-auth file is present
ansible.builtin.stat:
path: /etc/pam.d/password-auth
register: result_pam_password_auth_file_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020160
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- accounts_password_pam_minclass
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Check the proper remediation for the system
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Define the PAM file to be edited as a local fact
ansible.builtin.set_fact:
pam_file_path: /etc/pam.d/password-auth
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Check if system relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Ensure authselect custom profile is used if authselect is present
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Check integrity of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Informative message based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- 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 Enforces Password Requirements - Minimum Different Categories
- 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 Enforces Password Requirements - Minimum Different Categories
- 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 Enforces Password Requirements - Minimum Different Categories
- Get authselect current features to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- 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:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Create an authselect custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- 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 Enforces Password Requirements - Minimum Different Categories
- 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 Enforces Password Requirements - Minimum Different Categories
- 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 Enforces Password Requirements - Minimum Different Categories
- 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 Enforces Password Requirements - Minimum Different Categories
- 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Define a fact for control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Check if {{ pam_file_path }} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Ensure the "minclass" option from "pam_pwquality.so" is not present in {{
pam_file_path }}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: (.*password.*pam_pwquality.so.*)\bminclass\b=?[0-9a-zA-Z]*(.*)
replace: \1\2
register: result_pam_option_removal
when:
- result_pam_file_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- 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:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
- result_pam_password_auth_file_present.stat.exists
tags:
- DISA-STIG-OL08-00-020160
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- accounts_password_pam_minclass
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Different Categories
- Ensure PAM variable minclass is set accordingly
ansible.builtin.lineinfile:
create: true
dest: /etc/security/pwquality.conf
regexp: ^#?\s*minclass
line: minclass = {{ var_password_pam_minclass }}
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020160
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- accounts_password_pam_minclass
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Find pwquality.conf.d
files
ansible.builtin.find:
paths: /etc/security/pwquality.conf.d/
patterns: '*.conf'
register: pwquality_conf_d_files
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- CJIS-5.6.2.1.1
- DISA-STIG-OL08-00-020230
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_minlen
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure minlen
is not set in pwquality.conf.d
ansible.builtin.lineinfile:
path: '{{ item.path }}'
regexp: ^\s*\bminlen\b.*
state: absent
with_items: '{{ pwquality_conf_d_files.files }}'
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- CJIS-5.6.2.1.1
- DISA-STIG-OL08-00-020230
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_minlen
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Check if /etc/pam.d/system-auth
file is present
ansible.builtin.stat:
path: /etc/pam.d/system-auth
register: result_pam_auth_file_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- CJIS-5.6.2.1.1
- DISA-STIG-OL08-00-020230
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_minlen
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Check the proper
remediation for the system
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Define the
PAM file to be edited as a local fact
ansible.builtin.set_fact:
pam_file_path: /etc/pam.d/system-auth
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Check if
system relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure authselect
custom profile is used if authselect is present
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Check integrity
of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Informative
message based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Ensure PAM Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - Get authselect
current features to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Length - 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:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Length - 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Create
an authselect custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Define a
fact for control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Check if
{{ pam_file_path }} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure the
"minlen" option from "pam_pwquality.so" is not present in {{ pam_file_path
}}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: (.*password.*pam_pwquality.so.*)\bminlen\b=?[0-9a-zA-Z]*(.*)
replace: \1\2
register: result_pam_option_removal
when:
- result_pam_file_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Length - 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:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
- result_pam_auth_file_present.stat.exists
tags:
- CJIS-5.6.2.1.1
- DISA-STIG-OL08-00-020230
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_minlen
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Check if /etc/pam.d/password-auth
file is present
ansible.builtin.stat:
path: /etc/pam.d/password-auth
register: result_pam_password_auth_file_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- CJIS-5.6.2.1.1
- DISA-STIG-OL08-00-020230
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_minlen
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Check the proper
remediation for the system
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Define the
PAM file to be edited as a local fact
ansible.builtin.set_fact:
pam_file_path: /etc/pam.d/password-auth
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Check if
system relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure authselect
custom profile is used if authselect is present
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Check integrity
of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Informative
message based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Ensure PAM Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - Get authselect
current features to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Length - 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:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Length - 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Create
an authselect custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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 Enforces Password Requirements - Minimum Length - 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Define a
fact for control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Check if
{{ pam_file_path }} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure the
"minlen" option from "pam_pwquality.so" is not present in {{ pam_file_path
}}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: (.*password.*pam_pwquality.so.*)\bminlen\b=?[0-9a-zA-Z]*(.*)
replace: \1\2
register: result_pam_option_removal
when:
- result_pam_file_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Length - 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:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
- result_pam_password_auth_file_present.stat.exists
tags:
- CJIS-5.6.2.1.1
- DISA-STIG-OL08-00-020230
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_minlen
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Length - Ensure PAM
variable minlen is set accordingly
ansible.builtin.lineinfile:
create: true
dest: /etc/security/pwquality.conf
regexp: ^#?\s*minlen
line: minlen = {{ var_password_pam_minlen }}
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- CJIS-5.6.2.1.1
- DISA-STIG-OL08-00-020230
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.6
- accounts_password_pam_minlen
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters -
Find pwquality.conf.d files
ansible.builtin.find:
paths: /etc/security/pwquality.conf.d/
patterns: '*.conf'
register: pwquality_conf_d_files
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020280
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- accounts_password_pam_ocredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters -
Ensure ocredit is not set in pwquality.conf.d
ansible.builtin.lineinfile:
path: '{{ item.path }}'
regexp: ^\s*\bocredit\b.*
state: absent
with_items: '{{ pwquality_conf_d_files.files }}'
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020280
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- accounts_password_pam_ocredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters -
Check if /etc/pam.d/system-auth file is present
ansible.builtin.stat:
path: /etc/pam.d/system-auth
register: result_pam_auth_file_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020280
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- accounts_password_pam_ocredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters -
Check the proper remediation for the system
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- Define the PAM file to be edited as a local fact
ansible.builtin.set_fact:
pam_file_path: /etc/pam.d/system-auth
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- Check if system relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- Ensure authselect custom profile is used if authselect is present
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- Check integrity of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- Informative message based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- 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 Enforces Password Requirements - Minimum Special Characters
- 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 Enforces Password Requirements - Minimum Special Characters
- 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 Enforces Password Requirements - Minimum Special Characters
- Get authselect current features to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- 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:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- Create an authselect custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- 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 Enforces Password Requirements - Minimum Special Characters
- 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 Enforces Password Requirements - Minimum Special Characters
- 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 Enforces Password Requirements - Minimum Special Characters
- 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 Enforces Password Requirements - Minimum Special Characters
- 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- Define a fact for control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- Check if {{ pam_file_path }} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- Ensure the "ocredit" option from "pam_pwquality.so" is not present in {{
pam_file_path }}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: (.*password.*pam_pwquality.so.*)\bocredit\b=?[0-9a-zA-Z]*(.*)
replace: \1\2
register: result_pam_option_removal
when:
- result_pam_file_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- 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:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
- result_pam_auth_file_present.stat.exists
tags:
- DISA-STIG-OL08-00-020280
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- accounts_password_pam_ocredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters -
Check if /etc/pam.d/password-auth file is present
ansible.builtin.stat:
path: /etc/pam.d/password-auth
register: result_pam_password_auth_file_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020280
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- accounts_password_pam_ocredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters -
Check the proper remediation for the system
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- Define the PAM file to be edited as a local fact
ansible.builtin.set_fact:
pam_file_path: /etc/pam.d/password-auth
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- Check if system relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- Ensure authselect custom profile is used if authselect is present
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- Check integrity of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- Informative message based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- 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 Enforces Password Requirements - Minimum Special Characters
- 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 Enforces Password Requirements - Minimum Special Characters
- 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 Enforces Password Requirements - Minimum Special Characters
- Get authselect current features to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- 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:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- Create an authselect custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- 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 Enforces Password Requirements - Minimum Special Characters
- 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 Enforces Password Requirements - Minimum Special Characters
- 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 Enforces Password Requirements - Minimum Special Characters
- 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 Enforces Password Requirements - Minimum Special Characters
- 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- Define a fact for control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- Check if {{ pam_file_path }} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- Ensure the "ocredit" option from "pam_pwquality.so" is not present in {{
pam_file_path }}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: (.*password.*pam_pwquality.so.*)\bocredit\b=?[0-9a-zA-Z]*(.*)
replace: \1\2
register: result_pam_option_removal
when:
- result_pam_file_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters
- 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:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
- result_pam_password_auth_file_present.stat.exists
tags:
- DISA-STIG-OL08-00-020280
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- accounts_password_pam_ocredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Special Characters -
Ensure PAM variable ocredit is set accordingly
ansible.builtin.lineinfile:
create: true
dest: /etc/security/pwquality.conf
regexp: ^#?\s*ocredit
line: ocredit = {{ var_password_pam_ocredit }}
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020280
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- accounts_password_pam_ocredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Define a fact for control already filtered in case filters
are used
ansible.builtin.set_fact:
pam_module_control: requisite
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.4', '<') and "libpwquality" in ansible_facts.packages )
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020102
- DISA-STIG-OL08-00-020103
- DISA-STIG-OL08-00-020104
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(4)
- accounts_password_pam_retry
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Check if expected PAM module line is present in /etc/pam.d/password-auth
ansible.builtin.lineinfile:
path: /etc/pam.d/password-auth
regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s*.*
state: absent
check_mode: true
changed_when: false
register: result_pam_line_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.4', '<') and "libpwquality" in ansible_facts.packages )
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020102
- DISA-STIG-OL08-00-020103
- DISA-STIG-OL08-00-020104
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(4)
- accounts_password_pam_retry
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Include or update the PAM module line in /etc/pam.d/password-auth
block:
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Check if required PAM module line is present in /etc/pam.d/password-auth
with different control
ansible.builtin.lineinfile:
path: /etc/pam.d/password-auth
regexp: ^\s*password\s+.*\s+pam_pwquality.so\s*
state: absent
check_mode: true
changed_when: false
register: result_pam_line_other_control_present
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Ensure the correct control for the required PAM module
line in /etc/pam.d/password-auth
ansible.builtin.replace:
dest: /etc/pam.d/password-auth
regexp: ^(\s*password\s+).*(\bpam_pwquality.so.*)
replace: \1{{ pam_module_control }} \2
register: result_pam_module_edit
when:
- result_pam_line_other_control_present.found == 1
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Ensure the required PAM module line is included in
/etc/pam.d/password-auth
ansible.builtin.lineinfile:
dest: /etc/pam.d/password-auth
insertafter: ^\s*account
line: password {{ pam_module_control }} pam_pwquality.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 Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Ensure authselect changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b
when:
- result_authselect_present is defined
- 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:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.4', '<') and "libpwquality" in ansible_facts.packages )
- result_pam_line_present.found is defined
- result_pam_line_present.found == 0
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020102
- DISA-STIG-OL08-00-020103
- DISA-STIG-OL08-00-020104
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(4)
- accounts_password_pam_retry
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Define a fact for control already filtered in case filters
are used
ansible.builtin.set_fact:
pam_module_control: requisite
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.4', '<') and "libpwquality" in ansible_facts.packages )
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020102
- DISA-STIG-OL08-00-020103
- DISA-STIG-OL08-00-020104
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(4)
- accounts_password_pam_retry
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Check if the required PAM module option is present in
/etc/pam.d/password-auth
ansible.builtin.lineinfile:
path: /etc/pam.d/password-auth
regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s*.*\sretry\b
state: absent
check_mode: true
changed_when: false
register: result_pam_module_accounts_password_pam_retry_option_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.4', '<') and "libpwquality" in ansible_facts.packages )
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020102
- DISA-STIG-OL08-00-020103
- DISA-STIG-OL08-00-020104
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(4)
- accounts_password_pam_retry
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Ensure the "retry" PAM option for "pam_pwquality.so"
is included in /etc/pam.d/password-auth
ansible.builtin.lineinfile:
path: /etc/pam.d/password-auth
backrefs: true
regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so.*)
line: \1 retry={{ var_password_pam_retry }}
state: present
register: result_pam_accounts_password_pam_retry_add
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.4', '<') and "libpwquality" in ansible_facts.packages )
- result_pam_module_accounts_password_pam_retry_option_present.found is defined
- result_pam_module_accounts_password_pam_retry_option_present.found == 0
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020102
- DISA-STIG-OL08-00-020103
- DISA-STIG-OL08-00-020104
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(4)
- accounts_password_pam_retry
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Ensure the required value for "retry" PAM option from
"pam_pwquality.so" in /etc/pam.d/password-auth
ansible.builtin.lineinfile:
path: /etc/pam.d/password-auth
backrefs: true
regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s+.*)(retry)=[0-9a-zA-Z]*\s*(.*)
line: \1\2={{ var_password_pam_retry }} \3
register: result_pam_accounts_password_pam_retry_edit
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.4', '<') and "libpwquality" in ansible_facts.packages )
- result_pam_module_accounts_password_pam_retry_option_present.found > 0
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020102
- DISA-STIG-OL08-00-020103
- DISA-STIG-OL08-00-020104
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(4)
- accounts_password_pam_retry
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Define a fact for control already filtered in case filters
are used
ansible.builtin.set_fact:
pam_module_control: requisite
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.4', '<') and "libpwquality" in ansible_facts.packages )
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020102
- DISA-STIG-OL08-00-020103
- DISA-STIG-OL08-00-020104
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(4)
- accounts_password_pam_retry
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Check if expected PAM module line is present in /etc/pam.d/system-auth
ansible.builtin.lineinfile:
path: /etc/pam.d/system-auth
regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s*.*
state: absent
check_mode: true
changed_when: false
register: result_pam_line_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.4', '<') and "libpwquality" in ansible_facts.packages )
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020102
- DISA-STIG-OL08-00-020103
- DISA-STIG-OL08-00-020104
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(4)
- accounts_password_pam_retry
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Include or update the PAM module line in /etc/pam.d/system-auth
block:
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Check if required PAM module line is present in /etc/pam.d/system-auth
with different control
ansible.builtin.lineinfile:
path: /etc/pam.d/system-auth
regexp: ^\s*password\s+.*\s+pam_pwquality.so\s*
state: absent
check_mode: true
changed_when: false
register: result_pam_line_other_control_present
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Ensure the correct control for the required PAM module
line in /etc/pam.d/system-auth
ansible.builtin.replace:
dest: /etc/pam.d/system-auth
regexp: ^(\s*password\s+).*(\bpam_pwquality.so.*)
replace: \1{{ pam_module_control }} \2
register: result_pam_module_edit
when:
- result_pam_line_other_control_present.found == 1
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Ensure the required PAM module line is included in
/etc/pam.d/system-auth
ansible.builtin.lineinfile:
dest: /etc/pam.d/system-auth
insertafter: ^\s*account
line: password {{ pam_module_control }} pam_pwquality.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 Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Ensure authselect changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b
when:
- result_authselect_present is defined
- 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:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.4', '<') and "libpwquality" in ansible_facts.packages )
- result_pam_line_present.found is defined
- result_pam_line_present.found == 0
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020102
- DISA-STIG-OL08-00-020103
- DISA-STIG-OL08-00-020104
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(4)
- accounts_password_pam_retry
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Define a fact for control already filtered in case filters
are used
ansible.builtin.set_fact:
pam_module_control: requisite
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.4', '<') and "libpwquality" in ansible_facts.packages )
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020102
- DISA-STIG-OL08-00-020103
- DISA-STIG-OL08-00-020104
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(4)
- accounts_password_pam_retry
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Check if the required PAM module option is present in
/etc/pam.d/system-auth
ansible.builtin.lineinfile:
path: /etc/pam.d/system-auth
regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s*.*\sretry\b
state: absent
check_mode: true
changed_when: false
register: result_pam_module_accounts_password_pam_retry_option_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.4', '<') and "libpwquality" in ansible_facts.packages )
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020102
- DISA-STIG-OL08-00-020103
- DISA-STIG-OL08-00-020104
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(4)
- accounts_password_pam_retry
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Ensure the "retry" PAM option for "pam_pwquality.so"
is included in /etc/pam.d/system-auth
ansible.builtin.lineinfile:
path: /etc/pam.d/system-auth
backrefs: true
regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so.*)
line: \1 retry={{ var_password_pam_retry }}
state: present
register: result_pam_accounts_password_pam_retry_add
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.4', '<') and "libpwquality" in ansible_facts.packages )
- result_pam_module_accounts_password_pam_retry_option_present.found is defined
- result_pam_module_accounts_password_pam_retry_option_present.found == 0
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020102
- DISA-STIG-OL08-00-020103
- DISA-STIG-OL08-00-020104
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(4)
- accounts_password_pam_retry
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Ensure PAM Enforces Password Requirements - Authentication Retry Prompts
Permitted Per-Session - Ensure the required value for "retry" PAM option from
"pam_pwquality.so" in /etc/pam.d/system-auth
ansible.builtin.lineinfile:
path: /etc/pam.d/system-auth
backrefs: true
regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_pwquality.so\s+.*)(retry)=[0-9a-zA-Z]*\s*(.*)
line: \1\2={{ var_password_pam_retry }} \3
register: result_pam_accounts_password_pam_retry_edit
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- ( ansible_distribution == 'OracleLinux' and ansible_distribution_version is
version('8.4', '<') and "libpwquality" in ansible_facts.packages )
- result_pam_module_accounts_password_pam_retry_option_present.found > 0
tags:
- CJIS-5.5.3
- DISA-STIG-OL08-00-020102
- DISA-STIG-OL08-00-020103
- DISA-STIG-OL08-00-020104
- NIST-800-53-AC-7(a)
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(4)
- accounts_password_pam_retry
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Find pwquality.conf.d files
ansible.builtin.find:
paths: /etc/security/pwquality.conf.d/
patterns: '*.conf'
register: pwquality_conf_d_files
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020110
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- accounts_password_pam_ucredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Ensure ucredit is not set in pwquality.conf.d
ansible.builtin.lineinfile:
path: '{{ item.path }}'
regexp: ^\s*\bucredit\b.*
state: absent
with_items: '{{ pwquality_conf_d_files.files }}'
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020110
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- accounts_password_pam_ucredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Check if /etc/pam.d/system-auth file is present
ansible.builtin.stat:
path: /etc/pam.d/system-auth
register: result_pam_auth_file_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020110
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- accounts_password_pam_ucredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Check the proper remediation for the system
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Define the PAM file to be edited as a local fact
ansible.builtin.set_fact:
pam_file_path: /etc/pam.d/system-auth
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Check if system relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Ensure authselect custom profile is used if authselect is present
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Check integrity of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Informative message based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- 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 Enforces Password Requirements - Minimum Uppercase Characters
- 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 Enforces Password Requirements - Minimum Uppercase Characters
- 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 Enforces Password Requirements - Minimum Uppercase Characters
- Get authselect current features to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- 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:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Create an authselect custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- 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 Enforces Password Requirements - Minimum Uppercase Characters
- 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 Enforces Password Requirements - Minimum Uppercase Characters
- 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 Enforces Password Requirements - Minimum Uppercase Characters
- 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 Enforces Password Requirements - Minimum Uppercase Characters
- 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Define a fact for control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Check if {{ pam_file_path }} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Ensure the "ucredit" option from "pam_pwquality.so" is not present in {{
pam_file_path }}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: (.*password.*pam_pwquality.so.*)\bucredit\b=?[0-9a-zA-Z]*(.*)
replace: \1\2
register: result_pam_option_removal
when:
- result_pam_file_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- 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:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
- result_pam_auth_file_present.stat.exists
tags:
- DISA-STIG-OL08-00-020110
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- accounts_password_pam_ucredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Check if /etc/pam.d/password-auth file is present
ansible.builtin.stat:
path: /etc/pam.d/password-auth
register: result_pam_password_auth_file_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020110
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- accounts_password_pam_ucredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Check the proper remediation for the system
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Define the PAM file to be edited as a local fact
ansible.builtin.set_fact:
pam_file_path: /etc/pam.d/password-auth
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Check if system relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Ensure authselect custom profile is used if authselect is present
block:
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Check integrity of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Informative message based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- 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 Enforces Password Requirements - Minimum Uppercase Characters
- 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 Enforces Password Requirements - Minimum Uppercase Characters
- 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 Enforces Password Requirements - Minimum Uppercase Characters
- Get authselect current features to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- 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:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- 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_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Create an authselect custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- 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 Enforces Password Requirements - Minimum Uppercase Characters
- 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 Enforces Password Requirements - Minimum Uppercase Characters
- 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 Enforces Password Requirements - Minimum Uppercase Characters
- 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 Enforces Password Requirements - Minimum Uppercase Characters
- 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:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Define a fact for control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: ''
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Check if {{ pam_file_path }} file is present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: result_pam_file_present
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Ensure the "ucredit" option from "pam_pwquality.so" is not present in {{
pam_file_path }}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: (.*password.*pam_pwquality.so.*)\bucredit\b=?[0-9a-zA-Z]*(.*)
replace: \1\2
register: result_pam_option_removal
when:
- result_pam_file_present.stat.exists
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- 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:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
- result_pam_password_auth_file_present.stat.exists
tags:
- DISA-STIG-OL08-00-020110
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- accounts_password_pam_ucredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure PAM Enforces Password Requirements - Minimum Uppercase Characters
- Ensure PAM variable ucredit is set accordingly
ansible.builtin.lineinfile:
create: true
dest: /etc/security/pwquality.conf
regexp: ^#?\s*ucredit
line: ucredit = {{ var_password_pam_ucredit }}
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"libpwquality" in ansible_facts.packages'
tags:
- DISA-STIG-OL08-00-020110
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(4)
- NIST-800-53-IA-5(c)
- PCI-DSS-Req-8.2.3
- accounts_password_pam_ucredit
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Set PAM Password Hashing Algorithm - system-auth - Check if /etc/pam.d/system-auth
file is present
ansible.builtin.stat:
path: /etc/pam.d/system-auth
register: result_pam_auth_file_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"pam" in ansible_facts.packages'
tags:
- CJIS-5.6.2.2
- DISA-STIG-OL08-00-010159
- 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
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.2
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- set_password_hashing_algorithm_systemauth
- name: Set PAM Password Hashing Algorithm - system-auth - Check the proper remediation
for the system
block:
- name: Set PAM Password Hashing Algorithm - system-auth - 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 Password Hashing Algorithm - system-auth - Check if system relies
on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Set PAM Password Hashing Algorithm - system-auth - Ensure authselect custom
profile is used if authselect is present
block:
- name: Set PAM Password Hashing Algorithm - system-auth - Check integrity of
authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Set PAM Password Hashing Algorithm - system-auth - Informative message
based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Set PAM Password Hashing Algorithm - system-auth - Get authselect current
profile
ansible.builtin.shell:
cmd: authselect current -r | awk '{ print $1 }'
register: result_authselect_profile
changed_when: false
when:
- result_authselect_check_cmd is success
- name: Set PAM Password Hashing Algorithm - system-auth - Define the current
authselect profile as a local fact
ansible.builtin.set_fact:
authselect_current_profile: '{{ result_authselect_profile.stdout }}'
authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
when:
- result_authselect_profile is not skipped
- result_authselect_profile.stdout is match("custom/")
- name: Set PAM Password Hashing Algorithm - system-auth - Define the new authselect
custom profile as a local fact
ansible.builtin.set_fact:
authselect_current_profile: '{{ result_authselect_profile.stdout }}'
authselect_custom_profile: custom/hardening
when:
- result_authselect_profile is not skipped
- result_authselect_profile.stdout is not match("custom/")
- name: Set PAM Password Hashing Algorithm - system-auth - Get authselect current
features to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Set PAM Password Hashing Algorithm - system-auth - Check if any custom
profile with the same name was already created
ansible.builtin.stat:
path: /etc/authselect/{{ authselect_custom_profile }}
register: result_authselect_custom_profile_present
changed_when: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Set PAM Password Hashing Algorithm - system-auth - Create an authselect
custom profile based on the current profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b {{ authselect_current_profile
}}
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Set PAM Password Hashing Algorithm - system-auth - Create an authselect
custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Set PAM Password Hashing Algorithm - system-auth - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- authselect_custom_profile is not match(authselect_current_profile)
- name: Set PAM Password Hashing Algorithm - system-auth - Ensure the authselect
custom profile is selected
ansible.builtin.command:
cmd: authselect select {{ authselect_custom_profile }}
register: result_pam_authselect_select_profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- authselect_custom_profile is not match(authselect_current_profile)
- name: Set PAM Password Hashing Algorithm - system-auth - Restore the authselect
features in the custom profile
ansible.builtin.command:
cmd: authselect enable-feature {{ item }}
loop: '{{ result_authselect_features.stdout_lines }}'
register: result_pam_authselect_restore_features
when:
- result_authselect_profile is not skipped
- result_authselect_features is not skipped
- result_pam_authselect_select_profile is not skipped
- name: Set PAM Password Hashing Algorithm - system-auth - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- result_pam_authselect_restore_features is not skipped
- name: Set PAM Password Hashing Algorithm - system-auth - Change the PAM file
to be edited according to the custom authselect profile
ansible.builtin.set_fact:
pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
| basename }}
when:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Set PAM Password Hashing Algorithm - system-auth - Define a fact for control
already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: sufficient
- name: Set PAM Password Hashing Algorithm - system-auth - Check if expected PAM
module line is present in {{ pam_file_path }}
ansible.builtin.lineinfile:
path: '{{ pam_file_path }}'
regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s*.*
state: absent
check_mode: true
changed_when: false
register: result_pam_line_present
- name: Set PAM Password Hashing Algorithm - system-auth - Include or update the
PAM module line in {{ pam_file_path }}
block:
- name: Set PAM Password Hashing Algorithm - system-auth - Check if required
PAM module line is present in {{ pam_file_path }} with different control
ansible.builtin.lineinfile:
path: '{{ pam_file_path }}'
regexp: ^\s*password\s+.*\s+pam_unix.so\s*
state: absent
check_mode: true
changed_when: false
register: result_pam_line_other_control_present
- name: Set PAM Password Hashing Algorithm - system-auth - Ensure the correct
control for the required PAM module line in {{ pam_file_path }}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: ^(\s*password\s+).*(\bpam_unix.so.*)
replace: \1{{ pam_module_control }} \2
register: result_pam_module_edit
when:
- result_pam_line_other_control_present.found == 1
- name: Set PAM Password Hashing Algorithm - system-auth - Ensure the required
PAM module line is included in {{ pam_file_path }}
ansible.builtin.lineinfile:
dest: '{{ pam_file_path }}'
line: password {{ pam_module_control }} 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 Password Hashing Algorithm - system-auth - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b
when:
- result_authselect_present is defined
- 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 Password Hashing Algorithm - system-auth - Define a fact for control
already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: sufficient
- name: Set PAM Password Hashing Algorithm - system-auth - Check if the required
PAM module option is present in {{ pam_file_path }}
ansible.builtin.lineinfile:
path: '{{ pam_file_path }}'
regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s*.*\s{{
var_password_hashing_algorithm_pam.split("|")[0] }}\b
state: absent
check_mode: true
changed_when: false
register: result_pam_module_set_password_hashing_algorithm_systemauth_option_present
- name: Set PAM Password Hashing Algorithm - system-auth - Ensure the "{{ var_password_hashing_algorithm_pam.split("|")[0]
}}" 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+{{ pam_module_control | regex_escape() }}\s+pam_unix.so.*)
line: \1 {{ var_password_hashing_algorithm_pam.split("|")[0] }}
state: present
register: result_pam_set_password_hashing_algorithm_systemauth_add
when:
- result_pam_module_set_password_hashing_algorithm_systemauth_option_present.found
is defined
- result_pam_module_set_password_hashing_algorithm_systemauth_option_present.found
== 0
- name: Set PAM Password Hashing Algorithm - system-auth - Ensure authselect changes
are applied
ansible.builtin.command:
cmd: authselect apply-changes -b
when:
- result_authselect_present.stat.exists
- |-
(result_pam_set_password_hashing_algorithm_systemauth_add is defined and result_pam_set_password_hashing_algorithm_systemauth_add.changed)
or (result_pam_set_password_hashing_algorithm_systemauth_edit is defined and result_pam_set_password_hashing_algorithm_systemauth_edit.changed)
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"pam" in ansible_facts.packages'
- result_pam_auth_file_present.stat.exists
tags:
- CJIS-5.6.2.2
- DISA-STIG-OL08-00-010159
- 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
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.2
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- set_password_hashing_algorithm_systemauth
- name: Set PAM Password Hashing Algorithm - system-auth - Check if /etc/pam.d/system-auth
File is Present
ansible.builtin.stat:
path: /etc/pam.d/system-auth
register: result_pam_auth_file_present
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"pam" in ansible_facts.packages'
tags:
- CJIS-5.6.2.2
- DISA-STIG-OL08-00-010159
- 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
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.2
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- set_password_hashing_algorithm_systemauth
- name: Set PAM Password Hashing Algorithm - system-auth - Check The Proper Remediation
For The System
block:
- name: Set PAM Password Hashing Algorithm - system-auth - 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 Password Hashing Algorithm - system-auth - Check if system relies
on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Set PAM Password Hashing Algorithm - system-auth - Ensure authselect custom
profile is used if authselect is present
block:
- name: Set PAM Password Hashing Algorithm - system-auth - Check integrity of
authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Set PAM Password Hashing Algorithm - system-auth - Informative message
based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Set PAM Password Hashing Algorithm - system-auth - Get authselect current
profile
ansible.builtin.shell:
cmd: authselect current -r | awk '{ print $1 }'
register: result_authselect_profile
changed_when: false
when:
- result_authselect_check_cmd is success
- name: Set PAM Password Hashing Algorithm - system-auth - Define the current
authselect profile as a local fact
ansible.builtin.set_fact:
authselect_current_profile: '{{ result_authselect_profile.stdout }}'
authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
when:
- result_authselect_profile is not skipped
- result_authselect_profile.stdout is match("custom/")
- name: Set PAM Password Hashing Algorithm - system-auth - Define the new authselect
custom profile as a local fact
ansible.builtin.set_fact:
authselect_current_profile: '{{ result_authselect_profile.stdout }}'
authselect_custom_profile: custom/hardening
when:
- result_authselect_profile is not skipped
- result_authselect_profile.stdout is not match("custom/")
- name: Set PAM Password Hashing Algorithm - system-auth - Get authselect current
features to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Set PAM Password Hashing Algorithm - system-auth - Check if any custom
profile with the same name was already created
ansible.builtin.stat:
path: /etc/authselect/{{ authselect_custom_profile }}
register: result_authselect_custom_profile_present
changed_when: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Set PAM Password Hashing Algorithm - system-auth - Create an authselect
custom profile based on the current profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b {{ authselect_current_profile
}}
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Set PAM Password Hashing Algorithm - system-auth - Create an authselect
custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Set PAM Password Hashing Algorithm - system-auth - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- authselect_custom_profile is not match(authselect_current_profile)
- name: Set PAM Password Hashing Algorithm - system-auth - Ensure the authselect
custom profile is selected
ansible.builtin.command:
cmd: authselect select {{ authselect_custom_profile }}
register: result_pam_authselect_select_profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- authselect_custom_profile is not match(authselect_current_profile)
- name: Set PAM Password Hashing Algorithm - system-auth - Restore the authselect
features in the custom profile
ansible.builtin.command:
cmd: authselect enable-feature {{ item }}
loop: '{{ result_authselect_features.stdout_lines }}'
register: result_pam_authselect_restore_features
when:
- result_authselect_profile is not skipped
- result_authselect_features is not skipped
- result_pam_authselect_select_profile is not skipped
- name: Set PAM Password Hashing Algorithm - system-auth - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- result_pam_authselect_restore_features is not skipped
- name: Set PAM Password Hashing Algorithm - system-auth - Change the PAM file
to be edited according to the custom authselect profile
ansible.builtin.set_fact:
pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
| basename }}
when:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Set PAM Password Hashing Algorithm - system-auth - Check if "{{ pam_file_path
}}" File is Present
ansible.builtin.stat:
path: '{{ pam_file_path }}'
register: pam_file_path_present
- name: Set PAM Password Hashing Algorithm - system-auth - Ensure That Only the
Correct Hashing Algorithm Option For pam_unix.so Is Used in {{ pam_file_path
}}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: (^\s*password.*pam_unix\.so.*)\b{{ item }}\b\s*(.*)
replace: \1\2
when:
- item != var_password_hashing_algorithm_pam.split('|')[0]
- pam_file_path_present.stat.exists
loop:
- sha512
- yescrypt
- gost_yescrypt
- blowfish
- sha256
- md5
- bigcrypt
register: result_pam_hashing_options_removal
- name: Set PAM Password Hashing Algorithm - system-auth - Ensure authselect changes
are applied
ansible.builtin.command:
cmd: authselect apply-changes -b
when:
- result_authselect_present.stat.exists
- result_pam_hashing_options_removal is changed
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"pam" in ansible_facts.packages'
- result_pam_auth_file_present.stat.exists
tags:
- CJIS-5.6.2.2
- DISA-STIG-OL08-00-010159
- 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
- PCI-DSSv4-8.3
- PCI-DSSv4-8.3.2
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- set_password_hashing_algorithm_systemauth
- name: Set Password Minimum Length in login.defs
ansible.builtin.lineinfile:
dest: /etc/login.defs
regexp: ^PASS_MIN_LEN *[0-9]*
state: present
line: PASS_MIN_LEN {{ var_accounts_password_minlen_login_defs }}
create: true
when:
- ("kernel" in ansible_facts.packages or "kernel-uek" in ansible_facts.packages)
- '"shadow-utils" in ansible_facts.packages'
tags:
- CJIS-5.6.2.1
- DISA-STIG-OL08-00-020231
- NIST-800-171-3.5.7
- NIST-800-53-CM-6(a)
- NIST-800-53-IA-5(1)(a)
- NIST-800-53-IA-5(f)
- accounts_password_minlen_login_defs
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Set number of Password Hashing Rounds - password-auth - Check if /etc/pam.d/password-auth
file is present
ansible.builtin.stat:
path: /etc/pam.d/password-auth
register: result_pam_password_auth_file_present
when: ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages
or "kernel-uek" in ansible_facts.packages) )
tags:
- accounts_password_pam_unix_rounds_password_auth
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Set number of Password Hashing Rounds - password-auth - Check the proper
remediation for the system
block:
- name: Set number of Password Hashing Rounds - password-auth - Define the PAM
file to be edited as a local fact
ansible.builtin.set_fact:
pam_file_path: /etc/pam.d/password-auth
- name: Set number of Password Hashing Rounds - password-auth - Check if system
relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Set number of Password Hashing Rounds - password-auth - Ensure authselect
custom profile is used if authselect is present
block:
- name: Set number of Password Hashing Rounds - password-auth - Check integrity
of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Set number of Password Hashing Rounds - password-auth - Informative
message based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Set number of Password Hashing Rounds - password-auth - Get authselect
current profile
ansible.builtin.shell:
cmd: authselect current -r | awk '{ print $1 }'
register: result_authselect_profile
changed_when: false
when:
- result_authselect_check_cmd is success
- name: Set number of Password Hashing Rounds - password-auth - Define the current
authselect profile as a local fact
ansible.builtin.set_fact:
authselect_current_profile: '{{ result_authselect_profile.stdout }}'
authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
when:
- result_authselect_profile is not skipped
- result_authselect_profile.stdout is match("custom/")
- name: Set number of Password Hashing Rounds - password-auth - Define the new
authselect custom profile as a local fact
ansible.builtin.set_fact:
authselect_current_profile: '{{ result_authselect_profile.stdout }}'
authselect_custom_profile: custom/hardening
when:
- result_authselect_profile is not skipped
- result_authselect_profile.stdout is not match("custom/")
- name: Set number of Password Hashing Rounds - password-auth - Get authselect
current features to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Set number of Password Hashing Rounds - password-auth - Check if any
custom profile with the same name was already created
ansible.builtin.stat:
path: /etc/authselect/{{ authselect_custom_profile }}
register: result_authselect_custom_profile_present
changed_when: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Set number of Password Hashing Rounds - password-auth - Create an authselect
custom profile based on the current profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b {{ authselect_current_profile
}}
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Set number of Password Hashing Rounds - password-auth - Create an authselect
custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Set number of Password Hashing Rounds - password-auth - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- authselect_custom_profile is not match(authselect_current_profile)
- name: Set number of Password Hashing Rounds - password-auth - Ensure the authselect
custom profile is selected
ansible.builtin.command:
cmd: authselect select {{ authselect_custom_profile }}
register: result_pam_authselect_select_profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- authselect_custom_profile is not match(authselect_current_profile)
- name: Set number of Password Hashing Rounds - password-auth - Restore the
authselect features in the custom profile
ansible.builtin.command:
cmd: authselect enable-feature {{ item }}
loop: '{{ result_authselect_features.stdout_lines }}'
register: result_pam_authselect_restore_features
when:
- result_authselect_profile is not skipped
- result_authselect_features is not skipped
- result_pam_authselect_select_profile is not skipped
- name: Set number of Password Hashing Rounds - password-auth - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- result_pam_authselect_restore_features is not skipped
- name: Set number of Password Hashing Rounds - password-auth - Change the PAM
file to be edited according to the custom authselect profile
ansible.builtin.set_fact:
pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
| basename }}
when:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Set number of Password Hashing Rounds - password-auth - Define a fact
for control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: sufficient
- name: Set number of Password Hashing Rounds - password-auth - Check if expected
PAM module line is present in {{ pam_file_path }}
ansible.builtin.lineinfile:
path: '{{ pam_file_path }}'
regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s*.*
state: absent
check_mode: true
changed_when: false
register: result_pam_line_present
- name: Set number of Password Hashing Rounds - password-auth - Include or update
the PAM module line in {{ pam_file_path }}
block:
- name: Set number of Password Hashing Rounds - password-auth - Check if required
PAM module line is present in {{ pam_file_path }} with different control
ansible.builtin.lineinfile:
path: '{{ pam_file_path }}'
regexp: ^\s*password\s+.*\s+pam_unix.so\s*
state: absent
check_mode: true
changed_when: false
register: result_pam_line_other_control_present
- name: Set number of Password Hashing Rounds - password-auth - Ensure the correct
control for the required PAM module line in {{ pam_file_path }}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: ^(\s*password\s+).*(\bpam_unix.so.*)
replace: \1{{ pam_module_control }} \2
register: result_pam_module_edit
when:
- result_pam_line_other_control_present.found == 1
- name: Set number of Password Hashing Rounds - password-auth - Ensure the required
PAM module line is included in {{ pam_file_path }}
ansible.builtin.lineinfile:
dest: '{{ pam_file_path }}'
line: password {{ pam_module_control }} 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 number of Password Hashing Rounds - password-auth - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b
when:
- result_authselect_present is defined
- 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 number of Password Hashing Rounds - password-auth - Define a fact
for control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: sufficient
- name: Set number of Password Hashing Rounds - password-auth - Check if the required
PAM module option is present in {{ pam_file_path }}
ansible.builtin.lineinfile:
path: '{{ pam_file_path }}'
regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s*.*\srounds\b
state: absent
check_mode: true
changed_when: false
register: result_pam_module_accounts_password_pam_unix_rounds_password_auth_option_present
- name: Set number of Password Hashing Rounds - password-auth - Ensure the "rounds"
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+{{ pam_module_control | regex_escape() }}\s+pam_unix.so.*)
line: \1 rounds={{ var_password_pam_unix_rounds }}
state: present
register: result_pam_accounts_password_pam_unix_rounds_password_auth_add
when:
- result_pam_module_accounts_password_pam_unix_rounds_password_auth_option_present.found
is defined
- result_pam_module_accounts_password_pam_unix_rounds_password_auth_option_present.found
== 0
- name: Set number of Password Hashing Rounds - password-auth - Ensure the required
value for "rounds" PAM option from "pam_unix.so" in {{ pam_file_path }}
ansible.builtin.lineinfile:
path: '{{ pam_file_path }}'
backrefs: true
regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s+.*)(rounds)=[0-9a-zA-Z]*\s*(.*)
line: \1\2={{ var_password_pam_unix_rounds }} \3
register: result_pam_accounts_password_pam_unix_rounds_password_auth_edit
when:
- result_pam_module_accounts_password_pam_unix_rounds_password_auth_option_present.found
> 0
- name: Set number of Password Hashing Rounds - password-auth - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b
when:
- result_authselect_present.stat.exists
- |-
(result_pam_accounts_password_pam_unix_rounds_password_auth_add is defined and result_pam_accounts_password_pam_unix_rounds_password_auth_add.changed)
or (result_pam_accounts_password_pam_unix_rounds_password_auth_edit is defined and result_pam_accounts_password_pam_unix_rounds_password_auth_edit.changed)
when:
- ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages or
"kernel-uek" in ansible_facts.packages) )
- result_pam_password_auth_file_present.stat.exists
tags:
- accounts_password_pam_unix_rounds_password_auth
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Set number of Password Hashing Rounds - system-auth - Check if /etc/pam.d/system-auth
file is present
ansible.builtin.stat:
path: /etc/pam.d/system-auth
register: result_pam_auth_file_present
when: ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages
or "kernel-uek" in ansible_facts.packages) )
tags:
- accounts_password_pam_unix_rounds_system_auth
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Set number of Password Hashing Rounds - system-auth - Check the proper remediation
for the system
block:
- name: Set number of Password Hashing Rounds - system-auth - 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 number of Password Hashing Rounds - system-auth - Check if system
relies on authselect tool
ansible.builtin.stat:
path: /usr/bin/authselect
register: result_authselect_present
- name: Set number of Password Hashing Rounds - system-auth - Ensure authselect
custom profile is used if authselect is present
block:
- name: Set number of Password Hashing Rounds - system-auth - Check integrity
of authselect current profile
ansible.builtin.command:
cmd: authselect check
register: result_authselect_check_cmd
changed_when: false
check_mode: false
failed_when: false
- name: Set number of Password Hashing Rounds - system-auth - Informative message
based on the authselect integrity check result
ansible.builtin.assert:
that:
- ansible_check_mode or result_authselect_check_cmd.rc == 0
fail_msg:
- authselect integrity check failed. Remediation aborted!
- This remediation could not be applied because an authselect profile was
not selected or the selected profile is not intact.
- It is not recommended to manually edit the PAM files when authselect tool
is available.
- In cases where the default authselect profile does not cover a specific
demand, a custom authselect profile is recommended.
success_msg:
- authselect integrity check passed
- name: Set number of Password Hashing Rounds - system-auth - Get authselect
current profile
ansible.builtin.shell:
cmd: authselect current -r | awk '{ print $1 }'
register: result_authselect_profile
changed_when: false
when:
- result_authselect_check_cmd is success
- name: Set number of Password Hashing Rounds - system-auth - Define the current
authselect profile as a local fact
ansible.builtin.set_fact:
authselect_current_profile: '{{ result_authselect_profile.stdout }}'
authselect_custom_profile: '{{ result_authselect_profile.stdout }}'
when:
- result_authselect_profile is not skipped
- result_authselect_profile.stdout is match("custom/")
- name: Set number of Password Hashing Rounds - system-auth - Define the new
authselect custom profile as a local fact
ansible.builtin.set_fact:
authselect_current_profile: '{{ result_authselect_profile.stdout }}'
authselect_custom_profile: custom/hardening
when:
- result_authselect_profile is not skipped
- result_authselect_profile.stdout is not match("custom/")
- name: Set number of Password Hashing Rounds - system-auth - Get authselect
current features to also enable them in the custom profile
ansible.builtin.shell:
cmd: authselect current | tail -n+3 | awk '{ print $2 }'
register: result_authselect_features
changed_when: false
check_mode: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Set number of Password Hashing Rounds - system-auth - Check if any custom
profile with the same name was already created
ansible.builtin.stat:
path: /etc/authselect/{{ authselect_custom_profile }}
register: result_authselect_custom_profile_present
changed_when: false
when:
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- name: Set number of Password Hashing Rounds - system-auth - Create an authselect
custom profile based on the current profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b {{ authselect_current_profile
}}
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is not match("^(custom/|local)")
- not result_authselect_custom_profile_present.stat.exists
- name: Set number of Password Hashing Rounds - system-auth - Create an authselect
custom profile based on sssd profile
ansible.builtin.command:
cmd: authselect create-profile hardening -b sssd
when:
- result_authselect_profile is not skipped
- result_authselect_check_cmd is success
- authselect_current_profile is match("local")
- not result_authselect_custom_profile_present.stat.exists
- name: Set number of Password Hashing Rounds - system-auth - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b --backup=before-hardening-custom-profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- authselect_custom_profile is not match(authselect_current_profile)
- name: Set number of Password Hashing Rounds - system-auth - Ensure the authselect
custom profile is selected
ansible.builtin.command:
cmd: authselect select {{ authselect_custom_profile }}
register: result_pam_authselect_select_profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- authselect_current_profile is not match("custom/")
- authselect_custom_profile is not match(authselect_current_profile)
- name: Set number of Password Hashing Rounds - system-auth - Restore the authselect
features in the custom profile
ansible.builtin.command:
cmd: authselect enable-feature {{ item }}
loop: '{{ result_authselect_features.stdout_lines }}'
register: result_pam_authselect_restore_features
when:
- result_authselect_profile is not skipped
- result_authselect_features is not skipped
- result_pam_authselect_select_profile is not skipped
- name: Set number of Password Hashing Rounds - system-auth - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b --backup=after-hardening-custom-profile
when:
- result_authselect_check_cmd is success
- result_authselect_profile is not skipped
- result_pam_authselect_restore_features is not skipped
- name: Set number of Password Hashing Rounds - system-auth - Change the PAM
file to be edited according to the custom authselect profile
ansible.builtin.set_fact:
pam_file_path: /etc/authselect/{{ authselect_custom_profile }}/{{ pam_file_path
| basename }}
when:
- authselect_custom_profile is defined
when:
- result_authselect_present.stat.exists
- name: Set number of Password Hashing Rounds - system-auth - Define a fact for
control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: sufficient
- name: Set number of Password Hashing Rounds - system-auth - Check if expected
PAM module line is present in {{ pam_file_path }}
ansible.builtin.lineinfile:
path: '{{ pam_file_path }}'
regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s*.*
state: absent
check_mode: true
changed_when: false
register: result_pam_line_present
- name: Set number of Password Hashing Rounds - system-auth - Include or update
the PAM module line in {{ pam_file_path }}
block:
- name: Set number of Password Hashing Rounds - system-auth - Check if required
PAM module line is present in {{ pam_file_path }} with different control
ansible.builtin.lineinfile:
path: '{{ pam_file_path }}'
regexp: ^\s*password\s+.*\s+pam_unix.so\s*
state: absent
check_mode: true
changed_when: false
register: result_pam_line_other_control_present
- name: Set number of Password Hashing Rounds - system-auth - Ensure the correct
control for the required PAM module line in {{ pam_file_path }}
ansible.builtin.replace:
dest: '{{ pam_file_path }}'
regexp: ^(\s*password\s+).*(\bpam_unix.so.*)
replace: \1{{ pam_module_control }} \2
register: result_pam_module_edit
when:
- result_pam_line_other_control_present.found == 1
- name: Set number of Password Hashing Rounds - system-auth - Ensure the required
PAM module line is included in {{ pam_file_path }}
ansible.builtin.lineinfile:
dest: '{{ pam_file_path }}'
line: password {{ pam_module_control }} 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 number of Password Hashing Rounds - system-auth - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b
when:
- result_authselect_present is defined
- 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 number of Password Hashing Rounds - system-auth - Define a fact for
control already filtered in case filters are used
ansible.builtin.set_fact:
pam_module_control: sufficient
- name: Set number of Password Hashing Rounds - system-auth - Check if the required
PAM module option is present in {{ pam_file_path }}
ansible.builtin.lineinfile:
path: '{{ pam_file_path }}'
regexp: ^\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s*.*\srounds\b
state: absent
check_mode: true
changed_when: false
register: result_pam_module_accounts_password_pam_unix_rounds_system_auth_option_present
- name: Set number of Password Hashing Rounds - system-auth - Ensure the "rounds"
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+{{ pam_module_control | regex_escape() }}\s+pam_unix.so.*)
line: \1 rounds={{ var_password_pam_unix_rounds }}
state: present
register: result_pam_accounts_password_pam_unix_rounds_system_auth_add
when:
- result_pam_module_accounts_password_pam_unix_rounds_system_auth_option_present.found
is defined
- result_pam_module_accounts_password_pam_unix_rounds_system_auth_option_present.found
== 0
- name: Set number of Password Hashing Rounds - system-auth - Ensure the required
value for "rounds" PAM option from "pam_unix.so" in {{ pam_file_path }}
ansible.builtin.lineinfile:
path: '{{ pam_file_path }}'
backrefs: true
regexp: ^(\s*password\s+{{ pam_module_control | regex_escape() }}\s+pam_unix.so\s+.*)(rounds)=[0-9a-zA-Z]*\s*(.*)
line: \1\2={{ var_password_pam_unix_rounds }} \3
register: result_pam_accounts_password_pam_unix_rounds_system_auth_edit
when:
- result_pam_module_accounts_password_pam_unix_rounds_system_auth_option_present.found
> 0
- name: Set number of Password Hashing Rounds - system-auth - Ensure authselect
changes are applied
ansible.builtin.command:
cmd: authselect apply-changes -b
when:
- result_authselect_present.stat.exists
- |-
(result_pam_accounts_password_pam_unix_rounds_system_auth_add is defined and result_pam_accounts_password_pam_unix_rounds_system_auth_add.changed)
or (result_pam_accounts_password_pam_unix_rounds_system_auth_edit is defined and result_pam_accounts_password_pam_unix_rounds_system_auth_edit.changed)
when:
- ( "pam" in ansible_facts.packages and ("kernel" in ansible_facts.packages or
"kernel-uek" in ansible_facts.packages) )
- result_pam_auth_file_present.stat.exists
tags:
- accounts_password_pam_unix_rounds_system_auth
- configure_strategy
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- name: Ensure All World-Writable Directories Are Owned by root User - Define Excluded
(Non-Local) File Systems and Paths
ansible.builtin.set_fact:
excluded_fstypes:
- afs
- autofs
- ceph
- cifs
- smb3
- smbfs
- sshfs
- ncpfs
- ncp
- nfs
- nfs4
- gfs
- gfs2
- glusterfs
- gpfs
- pvfs2
- ocfs2
- lustre
- davfs
- fuse.sshfs
excluded_paths:
- dev
- proc
- run
- sys
search_paths: []
tags:
- dir_perms_world_writable_root_owned
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure All World-Writable Directories Are Owned by root User - Find Relevant
Root Directories Ignoring Pre-Defined Excluded Paths
ansible.builtin.find:
paths: /
file_type: directory
excludes: '{{ excluded_paths }}'
hidden: true
recurse: false
register: result_relevant_root_dirs
tags:
- dir_perms_world_writable_root_owned
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure All World-Writable Directories Are Owned by root User - Include Relevant
Root Directories in a List of Paths to be Searched
ansible.builtin.set_fact:
search_paths: '{{ search_paths | union([item.path]) }}'
loop: '{{ result_relevant_root_dirs.files }}'
tags:
- dir_perms_world_writable_root_owned
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure All World-Writable Directories Are Owned by root User - Increment
Search Paths List with Local Partitions Mount Points
ansible.builtin.set_fact:
search_paths: '{{ search_paths | union([item.mount]) }}'
loop: '{{ ansible_mounts }}'
when:
- item.fstype not in excluded_fstypes
- item.mount != '/'
tags:
- dir_perms_world_writable_root_owned
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure All World-Writable Directories Are Owned by root User - Increment
Search Paths List with Local NFS File System Targets
ansible.builtin.set_fact:
search_paths: '{{ search_paths | union([item.device.split('':'')[1]]) }}'
loop: '{{ ansible_mounts }}'
when: item.device is search("localhost:")
tags:
- dir_perms_world_writable_root_owned
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure All World-Writable Directories Are Owned by root User - Define Rule
Specific Facts
ansible.builtin.set_fact:
world_writable_dirs: []
tags:
- dir_perms_world_writable_root_owned
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure All World-Writable Directories Are Owned by root User - Find All
Uncompliant Directories in Local File Systems
ansible.builtin.command:
cmd: find {{ item }} -xdev -type d -perm -0002 -uid +0
loop: '{{ search_paths }}'
changed_when: false
register: result_found_dirs
tags:
- dir_perms_world_writable_root_owned
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure All World-Writable Directories Are Owned by root User - Create List
of World Writable Directories Not Owned by root
ansible.builtin.set_fact:
world_writable_dirs: '{{ world_writable_dirs | union(item.stdout_lines) | list
}}'
loop: '{{ result_found_dirs.results }}'
when: item is not skipped
tags:
- dir_perms_world_writable_root_owned
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Ensure All World-Writable Directories Are Owned by root User - Ensure root
Ownership on Local World Writable Directories
ansible.builtin.file:
path: '{{ item }}'
owner: root
loop: '{{ world_writable_dirs }}'
tags:
- dir_perms_world_writable_root_owned
- low_complexity
- medium_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Verify that All World-Writable Directories Have Sticky Bits Set - Define
Excluded (Non-Local) File Systems and Paths
ansible.builtin.set_fact:
excluded_fstypes:
- afs
- autofs
- ceph
- cifs
- smb3
- smbfs
- sshfs
- ncpfs
- ncp
- nfs
- nfs4
- gfs
- gfs2
- glusterfs
- gpfs
- pvfs2
- ocfs2
- lustre
- davfs
- fuse.sshfs
excluded_paths:
- dev
- proc
- run
- sys
search_paths: []
tags:
- DISA-STIG-OL08-00-010190
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- dir_perms_world_writable_sticky_bits
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Verify that All World-Writable Directories Have Sticky Bits Set - Find Relevant
Root Directories Ignoring Pre-Defined Excluded Paths
ansible.builtin.find:
paths: /
file_type: directory
excludes: '{{ excluded_paths }}'
hidden: true
recurse: false
register: result_relevant_root_dirs
tags:
- DISA-STIG-OL08-00-010190
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- dir_perms_world_writable_sticky_bits
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Verify that All World-Writable Directories Have Sticky Bits Set - Include
Relevant Root Directories in a List of Paths to be Searched
ansible.builtin.set_fact:
search_paths: '{{ search_paths | union([item.path]) }}'
loop: '{{ result_relevant_root_dirs.files }}'
tags:
- DISA-STIG-OL08-00-010190
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- dir_perms_world_writable_sticky_bits
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Verify that All World-Writable Directories Have Sticky Bits Set - Increment
Search Paths List with Local Partitions Mount Points
ansible.builtin.set_fact:
search_paths: '{{ search_paths | union([item.mount]) }}'
loop: '{{ ansible_mounts }}'
when:
- item.fstype not in excluded_fstypes
- item.mount != '/'
tags:
- DISA-STIG-OL08-00-010190
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- dir_perms_world_writable_sticky_bits
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Verify that All World-Writable Directories Have Sticky Bits Set - Increment
Search Paths List with Local NFS File System Targets
ansible.builtin.set_fact:
search_paths: '{{ search_paths | union([item.device.split('':'')[1]]) }}'
loop: '{{ ansible_mounts }}'
when: item.device is search("localhost:")
tags:
- DISA-STIG-OL08-00-010190
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- dir_perms_world_writable_sticky_bits
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Verify that All World-Writable Directories Have Sticky Bits Set - Define
Rule Specific Facts
ansible.builtin.set_fact:
world_writable_dirs: []
tags:
- DISA-STIG-OL08-00-010190
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- dir_perms_world_writable_sticky_bits
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Verify that All World-Writable Directories Have Sticky Bits Set - Find All
Uncompliant Directories in Local File Systems
ansible.builtin.command:
cmd: find {{ item }} -xdev -type d ( -perm -0002 -a ! -perm -1000 )
loop: '{{ search_paths }}'
changed_when: false
register: result_found_dirs
tags:
- DISA-STIG-OL08-00-010190
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- dir_perms_world_writable_sticky_bits
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Verify that All World-Writable Directories Have Sticky Bits Set - Create
List of World Writable Directories Without Sticky Bit
ansible.builtin.set_fact:
world_writable_dirs: '{{ world_writable_dirs | union(item.stdout_lines) | list
}}'
loop: '{{ result_found_dirs.results }}'
when: result_found_dirs is not skipped and item is not skipped
tags:
- DISA-STIG-OL08-00-010190
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- dir_perms_world_writable_sticky_bits
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy
- name: Verify that All World-Writable Directories Have Sticky Bits Set - Ensure
Sticky Bit is Set on Local World Writable Directories
ansible.builtin.file:
path: '{{ item }}'
mode: a+t
loop: '{{ world_writable_dirs }}'
tags:
- DISA-STIG-OL08-00-010190
- NIST-800-53-AC-6(1)
- NIST-800-53-CM-6(a)
- PCI-DSSv4-2.2
- PCI-DSSv4-2.2.6
- dir_perms_world_writable_sticky_bits
- low_complexity
- low_disruption
- medium_severity
- no_reboot_needed
- restrict_strategy