Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions components/pam.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ rules:
- accounts_password_all_shadowed_sha512
- accounts_password_last_change_is_in_past
- accounts_password_minlen_login_defs
- accounts_password_pam_modules_in_authselect_profile
- accounts_password_pam_pwhistory_enabled
- accounts_password_pam_pwhistory_enforce_root
- accounts_password_pam_pwhistory_enforce_for_root
Expand Down
23 changes: 16 additions & 7 deletions controls/cis_fedora.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1978,15 +1978,24 @@ controls:
levels:
- l1_server
- l1_workstation
status: partial
status: automated
notes: |-
This requirement is hard to be automated without any specific requirement. The policy even
states that provided commands are examples, other custom settings might be in place and the
settings might be different depending on site policies. The other rules will already make
sure there is a correct autheselect profile regardless of the existing settings. It is
necessary to better discuss with CIS Community.
This rule verifies that the active authselect profile includes the required PAM modules:
pam_pwquality.so, pam_pwhistory.so, pam_faillock.so, and pam_unix.so in both system-auth
and password-auth files. The rule checks the authselect profile source files directly,
not the symlinked files in /etc/pam.d/. Other rules ensure these modules are properly
configured with correct options.
rules:
- accounts_password_pam_modules_in_authselect_profile
related_rules:
- no_empty_passwords
- enable_authselect
- account_password_pam_faillock_password_auth
- account_password_pam_faillock_system_auth
- accounts_password_pam_pwquality_password_auth
- accounts_password_pam_pwquality_system_auth
- accounts_password_pam_pwhistory_remember_password_auth
- accounts_password_pam_pwhistory_remember_system_auth
- accounts_password_pam_unix_enabled

- id: 5.3.2.2
title: Ensure pam_faillock module is enabled (Automated)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,235 @@
# platform = multi_platform_rhel
# reboot = false
# strategy = restrict
# complexity = low
# disruption = low

{{{ ansible_check_authselect_integrity(rule_title) }}}

{{{ ansible_ensure_authselect_custom_profile(rule_title) }}}

- name: '{{{ rule_title }}} - Get authselect current profile'
ansible.builtin.command: head -1 /etc/authselect/authselect.conf
register: result_authselect_profile_name
changed_when: false
when:
- result_authselect_check_cmd is success

- name: '{{{ rule_title }}} - Determine PAM profile path'
ansible.builtin.set_fact:
pam_profile_path: >-
Copy link
Contributor

Choose a reason for hiding this comment

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

We should probably avoid manually editing of PAM profiles. Please check if you can replace some of the tasks that edit /pam_profile_path/ with authselect commands

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I don't think that's possible. The authselect enable-feature and authselect disable-feature commands modify the currently selected profile, they don't modify the files in /etc/authselect/custom/.

{%- if result_authselect_profile_name.stdout is match('^custom/') -%}
/etc/authselect/{{ result_authselect_profile_name.stdout }}
{%- else -%}
/usr/share/authselect/default/{{ result_authselect_profile_name.stdout }}
{%- endif %}
when:
- result_authselect_check_cmd is success
- result_authselect_profile_name is not skipped

- name: '{{{ rule_title }}} - Ensure PAM modules are present in system-auth and password-auth'
block:
- name: '{{{ rule_title }}} - Check if {{ item }} file exists'
ansible.builtin.stat:
path: "{{ pam_profile_path }}/{{ item }}"
register: pam_file_stat
loop:
- system-auth
- password-auth
when:
- pam_profile_path is defined

- name: '{{{ rule_title }}} - Set list of PAM files to process'
ansible.builtin.set_fact:
pam_files_to_process: "{{ pam_file_stat.results | default([]) | selectattr('stat.exists', 'equalto', true) | map(attribute='item') | list }}"

- name: '{{{ rule_title }}} - Check if pam_faillock.so exists in auth section of {{ item }}'
ansible.builtin.lineinfile:
path: "{{ pam_profile_path }}/{{ item }}"
regexp: ^\s*auth\s+\S+\s+pam_faillock\.so\s+preauth
state: absent
check_mode: true
changed_when: false
register: pam_faillock_auth_check_result
loop: "{{ pam_files_to_process | default([]) }}"
when:
- item is defined
- pam_profile_path is defined

- name: '{{{ rule_title }}} - Add pam_faillock.so preauth entry in auth section of {{ item }}'
ansible.builtin.lineinfile:
path: "{{ pam_profile_path }}/{{ item }}"
regexp: ^\s*auth\s+\S+\s+pam_faillock\.so\s+preauth
insertbefore: "^auth"
line: "auth required pam_faillock.so preauth"
state: present
register: pam_faillock_auth_add_result
loop: "{{ pam_files_to_process | default([]) }}"
when:
- item is defined
- pam_profile_path is defined
- "pam_faillock_auth_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(1) == 0"

- name: '{{{ rule_title }}} - Check if pam_faillock.so exists in account section of {{ item }}'
ansible.builtin.lineinfile:
path: "{{ pam_profile_path }}/{{ item }}"
regexp: ^\s*account\s+\S+\s+pam_faillock\.so
state: absent
check_mode: true
changed_when: false
register: pam_faillock_account_check_result
loop: "{{ pam_files_to_process | default([]) }}"
when:
- item is defined
- pam_profile_path is defined

- name: '{{{ rule_title }}} - Add pam_faillock.so entry in account section of {{ item }}'
ansible.builtin.lineinfile:
path: "{{ pam_profile_path }}/{{ item }}"
regexp: ^\s*account\s+\S+\s+pam_faillock\.so
insertafter: "^account"
line: "account required pam_faillock.so"
state: present
register: pam_faillock_account_add_result
loop: "{{ pam_files_to_process | default([]) }}"
when:
- item is defined
- pam_profile_path is defined
- "pam_faillock_account_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(1) == 0"

- name: '{{{ rule_title }}} - Check if pam_pwquality.so exists in {{ item }}'
ansible.builtin.lineinfile:
path: "{{ pam_profile_path }}/{{ item }}"
regexp: ^\s*password\s+\S+\s+pam_pwquality\.so
state: absent
check_mode: true
changed_when: false
register: pam_pwquality_check_result
loop: "{{ pam_files_to_process | default([]) }}"
when:
- item is defined
- pam_profile_path is defined

- name: '{{{ rule_title }}} - Add pam_pwquality.so entry in password section of {{ item }}'
ansible.builtin.lineinfile:
path: "{{ pam_profile_path }}/{{ item }}"
regexp: ^\s*password\s+\S+\s+pam_pwquality\.so
insertbefore: "^password"
line: "password requisite pam_pwquality.so"
state: present
register: pam_pwquality_add_result
loop: "{{ pam_files_to_process | default([]) }}"
when:
- item is defined
- pam_profile_path is defined
- "pam_pwquality_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(1) == 0"

- name: '{{{ rule_title }}} - Check if pam_pwhistory.so exists in {{ item }}'
ansible.builtin.lineinfile:
path: "{{ pam_profile_path }}/{{ item }}"
regexp: ^\s*password\s+\S+\s+pam_pwhistory\.so
state: absent
check_mode: true
changed_when: false
register: pam_pwhistory_check_result
loop: "{{ pam_files_to_process | default([]) }}"
when:
- item is defined
- pam_profile_path is defined

- name: '{{{ rule_title }}} - Add pam_pwhistory.so entry after pam_pwquality in {{ item }}'
ansible.builtin.lineinfile:
path: "{{ pam_profile_path }}/{{ item }}"
regexp: ^\s*password\s+\S+\s+pam_pwhistory\.so
insertafter: "^.*pam_pwquality\\.so.*"
line: "password requisite pam_pwhistory.so"
state: present
register: pam_pwhistory_add_result
loop: "{{ pam_files_to_process | default([]) }}"
when:
- item is defined
- pam_profile_path is defined
- "pam_pwhistory_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(1) == 0"
- "pam_pwquality_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(0) > 0"

- name: '{{{ rule_title }}} - Add pam_pwhistory.so entry at beginning of password section in {{ item }}'
ansible.builtin.lineinfile:
path: "{{ pam_profile_path }}/{{ item }}"
regexp: ^\s*password\s+\S+\s+pam_pwhistory\.so
insertbefore: "^password"
line: "password requisite pam_pwhistory.so"
state: present
register: pam_pwhistory_add_result
loop: "{{ pam_files_to_process | default([]) }}"
when:
- item is defined
- pam_profile_path is defined
- "pam_pwhistory_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(1) == 0"
- "pam_pwquality_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(1) == 0"

- name: '{{{ rule_title }}} - Check if pam_unix.so exists in password section of {{ item }}'
ansible.builtin.lineinfile:
path: "{{ pam_profile_path }}/{{ item }}"
regexp: ^\s*password\s+\S+\s+pam_unix\.so
state: absent
check_mode: true
changed_when: false
register: pam_unix_check_result
loop: "{{ pam_files_to_process | default([]) }}"
when:
- item is defined
- pam_profile_path is defined

- name: '{{{ rule_title }}} - Add pam_unix.so entry after pam_pwhistory in {{ item }}'
ansible.builtin.lineinfile:
path: "{{ pam_profile_path }}/{{ item }}"
regexp: ^\s*password\s+\S+\s+pam_unix\.so
insertafter: "^.*pam_pwhistory\\.so.*"
line: "password sufficient pam_unix.so"
state: present
register: pam_unix_add_result
loop: "{{ pam_files_to_process | default([]) }}"
when:
- item is defined
- pam_profile_path is defined
- "pam_unix_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(1) == 0"
- "pam_pwhistory_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(0) > 0"

- name: '{{{ rule_title }}} - Add pam_unix.so entry at end of password section in {{ item }}'
ansible.builtin.lineinfile:
path: "{{ pam_profile_path }}/{{ item }}"
regexp: ^\s*password\s+\S+\s+pam_unix\.so
insertafter: "^password.*"
line: "password sufficient pam_unix.so"
state: present
register: pam_unix_add_result
loop: "{{ pam_files_to_process | default([]) }}"
when:
- item is defined
- pam_profile_path is defined
- "pam_unix_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(1) == 0"
- "pam_pwhistory_check_result.results | selectattr('item', 'equalto', item) | map(attribute='found') | first | default(1) == 0"

- name: '{{{ rule_title }}} - Store results for {{ item }}'
ansible.builtin.set_fact:
"pam_changes_{{ item | replace('-', '_') }}": >-
{{ ((pam_faillock_auth_add_result.results | selectattr('item', 'equalto', item) | map(attribute='changed') | first | default(false)) or
(pam_faillock_account_add_result.results | selectattr('item', 'equalto', item) | map(attribute='changed') | first | default(false)) or
(pam_pwquality_add_result.results | selectattr('item', 'equalto', item) | map(attribute='changed') | first | default(false)) or
(pam_pwhistory_add_result.results | selectattr('item', 'equalto', item) | map(attribute='changed') | first | default(false)) or
(pam_unix_add_result.results | selectattr('item', 'equalto', item) | map(attribute='changed') | first | default(false))) }}
loop: "{{ pam_files_to_process | default([]) }}"
when:
- item is defined
- pam_profile_path is defined

when:
- result_authselect_check_cmd is success
- pam_profile_path is defined

{{{ ansible_apply_authselect_changes(rule_title=rule_title) }}}
when:
- result_authselect_check_cmd is success
- >-
(pam_changes_system_auth is defined and pam_changes_system_auth)
or (pam_changes_password_auth is defined and pam_changes_password_auth)
Loading
Loading