--- # Copyright 2016, Rackspace US, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. - name: Get a list of users on the system to use throughout the auth tasks action: get_users register: user_list check_mode: no tags: - always - name: Check if /etc/security/pwquality.conf exists stat: path: /etc/security/pwquality.conf check_mode: no register: pwquality_config_check tags: - always - name: Set password quality requirements blockinfile: dest: /etc/security/pwquality.conf backup: yes insertbefore: EOF marker: "# {mark} Added by openstack-ansible-security role" state: present block: "{{ lookup('template', 'pwquality.conf.j2') }}" when: - pwquality_config_check.stat.exists tags: - auth - medium - RHEL-07-010090 - RHEL-07-010100 - RHEL-07-010110 - RHEL-07-010120 - RHEL-07-010130 - RHEL-07-010140 - RHEL-07-010150 - RHEL-07-010160 - RHEL-07-010250 - name: Check for SHA512 password storage in PAM command: "grep pam_unix.so {{ pam_password_file }}" register: password_sha512_check changed_when: False check_mode: no tags: - always - name: RHEL-07-010170 - The PAM system service must be configured to store only encrypted representations of passwords. debug: msg: > PAM is not using SHA512 for password storage. This is a security issue. when: - password_sha512_check is defined - "'sha512' not in password_sha512_check.stdout" tags: - auth - medium - RHEL-07-010170 - name: Configure shadow-utils configuration lineinfile: dest: /etc/login.defs regexp: "^{{ item.parameter }}" line: "{{ item.parameter }} {{ item.value }}" state: present when: - item.value != '' with_items: "{{ shadow_utils_rhel7 }}" tags: - auth - medium - RHEL-07-010180 - RHEL-07-010200 - RHEL-07-010220 - RHEL-07-010420 - RHEL-07-020230 - RHEL-07-020630 - name: RHEL-07-010190 - User and group account administration utilities must be configured to store only encrypted representations of passwords. ini_file: dest: /etc/libuser.conf section: defaults option: crypt_style value: sha512 backup: yes when: - security_libuser_crypt_style_sha512 | bool - ansible_os_family | lower == 'redhat' tags: - auth - medium - RHEL-07-010190 - name: Get all user accounts with a password lifetime limit under 24 hours shell: "awk -F: '$4 < 1 {print $1}' /etc/shadow" check_mode: no changed_when: False register: password_lifetime_check tags: - auth - medium - RHEL-07-010210 - skip_ansible_lint - name: RHEL-07-010210 - Passwords must be restricted to a 24 hours/1 day minimum lifetime. debug: msg: | Accounts were found with a minimum password lifetime limit under 24 hours: {{ password_lifetime_check.stdout_lines | join(', ') }} when: - password_lifetime_check.stdout_lines is defined tags: - auth - medium - RHEL-07-010210 - name: RHEL-07-010240 - Passwords must be prohibited from reuse for a minimum of five generations. lineinfile: dest: "{{ pam_password_file }}" regexp: '^(password\s+[a-z0-9\=\[\] ]+\s+pam_unix\.so.+?)\s+(?:remember=\d+)?$' line: '\1 remember={{ security_password_remember_password }}' backrefs: yes state: present when: - security_password_remember_password is defined tags: - auth - medium - RHEL-07-010240 - name: RHEL-07-010230 - Existing passwords must be restricted to a 60-day maximum lifetime. debug: msg: | The following user accounts have an existing password with a lifetime of greater than 60 days: {%- for user in user_list.users %} {% if user['shadow']['max_days'] > 60 %} {{ user['name'] }} has an expiration of {{ user['shadow']['max_days'] }} days {% endif %} {% endfor %} tags: - auth - medium - RHEL-07-010230 - name: RHEL-07-010260 - The system must not have accounts configured with blank or null passwords lineinfile: dest: "{{ pam_auth_file }}" state: present regexp: "^(.*)nullok_secure(.*)$" line: '\1\2' backup: yes backrefs: yes when: - ansible_os_family == 'Debian' - security_disallow_blank_password_login | bool tags: - auth - high - RHEL-07-010260 - name: RHEL-07-010260 - The system must not have accounts configured with blank or null passwords lineinfile: dest: "{{ pam_auth_file }}" state: present regexp: "^({{ item }}.*sufficient.*)nullok(.*)$" line: '\1\2' backup: yes backrefs: yes with_items: - auth - password when: - ansible_os_family == 'RedHat' - security_disallow_blank_password_login | bool tags: - auth - high - RHEL-07-010260 - name: RHEL-07-010280 - The operating system must disable account identifiers if the password expires. lineinfile: dest: /etc/default/useradd regexp: '^[#\s]*INACTIVE' line: 'INACTIVE=0' when: - security_disable_account_if_password_expires | bool tags: - auth - medium - RHEL-07-010280 - name: RHEL-07-010371 - If three unsuccessful logon attempts within 15 minutes occur the associated account must be locked. blockinfile: dest: pam_password_file state: present marker: "# {mark} MANAGED BY OPENSTACK-ANSIBLE-SECURITY" insertbefore: EOF block: "{{ lookup('template', 'pam_faillock.j2') }}" when: - ansible_os_family | lower == 'redhat' - security_pam_faillock_enable | bool tags: - auth - medium - RHEL-07-010371 - RHEL-07-010372 - RHEL-07-010373 - name: Check for 'nopasswd' in sudoers files shell: grep -ir nopasswd /etc/sudoers /etc/sudoers.d/ || echo 'not found' register: sudoers_nopasswd_check changed_when: False tags: - auth - medium - RHEL-07-010380 - name: RHEL-07-010380 - Users must provide a password for privilege escalation. debug: msg: > The 'NOPASSWD' directive was found in the sudoers configuration files. Remove the directive to ensure that all users must provide a password to run commands as the root user. when: - not sudoers_nopasswd_check | skipped - sudoers_nopasswd_check.stdout != 'not found' tags: - auth - medium - RHEL-07-010380 - skip_ansible_lint - name: Check for '!authenticate' in sudoers files shell: grep -ir '\!authenticate' /etc/sudoers /etc/sudoers.d/ || echo 'not found' register: sudoers_authenticate_check changed_when: False tags: - auth - medium - RHEL-07-010381 - name: RHEL-07-010381 - Users must re-authenticate for privilege escalation. debug: msg: > The '!authenticate' directive was found in the sudoers configuration files. Remove the directive to ensure that all users must provide a password to run commands as the root user each time they use sudo. when: - not sudoers_authenticate_check | skipped - sudoers_authenticate_check.stdout != 'not found' tags: - auth - medium - RHEL-07-010381 - skip_ansible_lint - name: Check if sssd.conf exists stat: path: /etc/sssd/sssd.conf register: sssd_conf_check check_mode: no tags: - always - name: RHEL-07-010400 - The operating system must prohibit the use of cached nss authenticators after one day. ini_file: dest: /etc/sssd/sssd.conf section: nss option: memcache_timeout value: "{{ security_nss_cached_authenticator_timeout }}" backup: yes when: - sssd_conf_check.stat.exists - security_nss_cached_authenticator_timeout is defined tags: - auth - medium - RHEL-07-010400 - name: RHEL-07-010401 - The operating system must prohibit the use of cached PAM authenticators after one day. ini_file: dest: /etc/sssd/sssd.conf section: pam option: offline_credentials_expiration value: "{{ security_pam_offline_credentials_expiration_days }}" backup: yes when: - sssd_conf_check.stat.exists - security_pam_offline_credentials_expiration_days is defined tags: - auth - medium - RHEL-07-010401 - RHEL-07-010402 - name: Set a GRUB 2 password for single-user/maintenance modes lineinfile: dest: "{{ grub_defaults_file }}" regexp: '^(#)?GRUB_PASSWORD' line: 'GRUB_PASSWORD="{{ security_grub_password_hash }}"' state: present when: - security_require_grub_authentication | bool notify: - update grub config tags: - auth - high - RHEL-07-010460 - RHEL-07-010470 - name: Get all accounts with UID 0 shell: "awk -F: '$3 == 0 {print $1}' /etc/passwd" changed_when: False check_mode: no register: root_user_check tags: - auth - high - RHEL-07-020310 - skip_ansible_lint - name: Check for groups in /etc/passwd that are not in /etc/group debug: msg: > The following users have GIDs in /etc/passwd that do not exist in /etc/group: {{ user_list.users | selectattr('group', 'equalto', False) | map(attribute='name') | join(', ') }} when: - user_list is defined - user_list.users | selectattr('group', 'equalto', False) | list | length > 0 tags: - auth - low - RHEL-07-020300 - name: RHEL-07-020310 - The root account must be the only account having unrestricted access to the system fail: msg: | Only the 'root' user should have UID 0. Other users were found: {{ root_user_check.stdout_lines | join(', ') }}" when: - root_user_check.stdout != 'root' tags: - auth - high - RHEL-07-020310 - name: RHEL-07-020620 - All local interactive users must have a home directory assigned in the /etc/passwd file. debug: msg: | The following users do not have a home directory assigned: {{ user_list.users | selectattr('dir', 'equalto', '') | map(attribute='name') | join(', ') }} when: - user_list is defined - user_list.users | selectattr('dir', 'equalto', '') | map(attribute='name') | list | length > 0 tags: - auth - medium - RHEL-07-020620 - name: Check each user to see if its home directory exists on the filesystem stat: path: "{{ item['dir'] }}" when: - item['dir'] != '' with_items: "{{ user_list.users }}" register: home_directory_checks tags: - auth - medium - RHEL-07-020640 - name: RHEL-07-020640 - All local interactive user home directories defined in the /etc/passwd file must exist. debug: msg: | These users have a home directory assigned, but the directory does not exist: {% for check in home_directory_checks.results %} {% if not check.stat.exists %} {{ check.item.name }} ({{ check.item.dir }} does not exist) {% endif %} {% endfor %} when: - home_directory_checks.results | selectattr('stat.exists', 'sameas', false) | list | length > 0 tags: - auth - medium - RHEL-07-020640 - name: RHEL-07-040010 - The operating system must limit the number of concurrent sessions to 10 for all accounts and/or account types. blockinfile: dest: /etc/security/limits.d/openstack-ansible-security-maxlogins.conf create: yes block: | # Deployed by the openstack-ansible-security role # RHEL-07-040010 - Limit concurrent sessions for all accounts/types * hard maxlogins {{ security_rhel7_concurrent_session_limit }} when: - security_rhel7_concurrent_session_limit is defined tags: - auth - low - RHEL-07-040010 - name: Check for PAM PKCS 11 authentication configuration stat: path: /etc/pam_pkcs11/pam_pkcs11.conf register: pkcs11_conf_check check_mode: no tags: - always - name: Check for ocsp_on in PAM PKCS 11 auth configuration shell: 'grep cert_policy /etc/pam_pkcs11/pam_pkcs11.conf | grep -c ocsp_on' register: oscp_on_check changed_when: False failed_when: False check_mode: no when: - pkcs11_conf_check.stat.exists tags: - always - name: RHEL-07-040030 - Must Validate PKI-based auth attempts with OCSP debug: msg: > PKI-based authentication attempts must use OCSP for certificate validation. Review the documentation for RHEL-07-040030. when: - pkcs11_conf_check.stat.exists - oscp_on_check.stdout != 3 tags: - medium - auth - RHEL-07-040030 - name: Check for cackey or coolkey in the PAM PKCS11 auth configuration shell: 'egrep "use_pkcs11_module = (cackey|coolkey)" /etc/pam_pkcs11/pam_pkcs11.conf' register: pkcs11_key_check changed_when: False failed_when: False check_mode: no when: - pkcs11_conf_check.stat.exists tags: - always - name: RHEL-07-040040 - Must use cackey/cookey for PKCS 11 auth debug: msg: > PKI-based authentication attempts must use cackey or coolkey. Review the documentation for RHEL-07-040040. when: - pkcs11_conf_check.stat.exists - pkcs11_key_check.stdout.rc != 0 tags: - medium - auth - RHEL-07-040040 - name: Check for pam_lastlog in PAM configuration command: "grep pam_lastlog {{ pam_postlogin_file }}" register: pam_lastlog_check changed_when: False failed_when: False check_mode: no tags: - always - name: RHEL-07-040300 - Display date/time of last logon after logon debug: msg: > The 'pam_lastlog' directive is missing in {{ pam_postlogin_file }}. This is required by RHEL-07-040300. when: - pam_lastlog_check.rc != 0 tags: - low - auth - RHEL-07-040300 - name: Check for .shosts or shosts.equiv files find: paths: / recurse: yes hidden: yes patterns: '.shosts,shosts.equiv' register: shosts_find when: - security_rhel7_remove_shosts_files | bool tags: - always - name: Remove .shosts or shosts.equiv files file: path: "{{ item.path }}" state: absent with_items: "{{ shosts_find.files }}" when: - security_rhel7_remove_shosts_files | bool - shosts_find is defined - shosts_find.files is defined tags: - high - auth - RHEL-07-040330 - RHEL-07-040331