--- # Password Policy Configuration (CIS 5.4.x, 5.5.x) - name: Set default password expiration (CIS 5.4.1) ansible.builtin.lineinfile: path: /etc/login.defs regexp: '^PASS_MAX_DAYS' line: "PASS_MAX_DAYS {{ password_max_days }}" state: present - name: Set minimum password change days (CIS 5.4.2) ansible.builtin.lineinfile: path: /etc/login.defs regexp: '^PASS_MIN_DAYS' line: "PASS_MIN_DAYS {{ password_min_days }}" state: present - name: Set password expiration warning (CIS 5.4.3) ansible.builtin.lineinfile: path: /etc/login.defs regexp: '^PASS_WARN_AGE' line: "PASS_WARN_AGE {{ password_warn_age }}" state: present - name: Set default umask (CIS 5.4.4) ansible.builtin.lineinfile: path: /etc/login.defs regexp: '^UMASK' line: "UMASK {{ default_umask }}" state: present - name: Configure PAM password quality requirements (CIS 5.5.1) ansible.builtin.apt: name: libpam-pwquality state: present - name: Set password quality requirements ansible.builtin.lineinfile: path: /etc/security/pwquality.conf regexp: "^{{ item.key }}" line: "{{ item.key }} = {{ item.value }}" state: present loop: - { key: 'minlen', value: '14' } - { key: 'dcredit', value: '-1' } # At least 1 digit - { key: 'ucredit', value: '-1' } # At least 1 uppercase - { key: 'lcredit', value: '-1' } # At least 1 lowercase - { key: 'ocredit', value: '-1' } # At least 1 special char - { key: 'minclass', value: '4' } # All 4 character classes - name: Configure account lockout (CIS 5.5.2) ansible.builtin.lineinfile: path: /etc/pam.d/common-auth line: "auth required pam_faillock.so preauth audit silent deny=5 unlock_time=900" insertbefore: '^auth\s+\[success=1 default=ignore\]\s+pam_unix.so' state: present - name: Configure account lockout (part 2) ansible.builtin.lineinfile: path: /etc/pam.d/common-auth line: "auth [default=die] pam_faillock.so authfail audit deny=5 unlock_time=900" insertafter: '^auth\s+\[success=1 default=ignore\]\s+pam_unix.so' state: present - name: Configure account lockout (part 3) ansible.builtin.lineinfile: path: /etc/pam.d/common-auth line: "auth sufficient pam_faillock.so authsucc audit deny=5 unlock_time=900" insertafter: '^auth\s+\[default=die\]\s+pam_faillock.so' state: present - name: Configure password reuse prevention (CIS 5.5.3) ansible.builtin.lineinfile: path: /etc/pam.d/common-password regexp: '^password\s+\[success=1 default=ignore\]\s+pam_unix.so' line: "password [success=1 default=ignore] pam_unix.so obscure use_authtok try_first_pass yescrypt remember=5" state: present - name: Ensure password hashing algorithm is yescrypt (CIS 5.5.4) ansible.builtin.lineinfile: path: /etc/pam.d/common-password regexp: '^password\s+\[success=1 default=ignore\]\s+pam_unix.so' line: "password [success=1 default=ignore] pam_unix.so obscure use_authtok try_first_pass yescrypt" state: present - name: Set inactive password lock (CIS 5.4.4) ansible.builtin.lineinfile: path: /etc/default/useradd regexp: '^INACTIVE=' line: "INACTIVE={{ password_inactive_days }}" state: present