diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 717f0e6..71a7e81 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -7,7 +7,7 @@ ci: repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: # Safety - id: detect-aws-credentials @@ -40,7 +40,7 @@ repos: - id: gitleaks - repo: https://github.com/ansible-community/ansible-lint - rev: v24.2.0 + rev: v24.2.2 hooks: - id: ansible-lint name: Ansible-lint diff --git a/defaults/main.yml b/defaults/main.yml index 25c23ca..42123e2 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -866,14 +866,20 @@ rhel8stig_fapolicy_white_list: # rhel8stig_custom_firewall_zone is the desired name for the new customer firewall zone rhel8stig_custom_firewall_zone: "new_fw_zone" +# rhel8stig_copy_existing_zone - if you wish to copy an existing zones rules to the new zone +rhel8stig_copy_existing_zone: true +# rhel8stig_existing_zone_to_copy - name of the zone that you wish to copy from +rhel8stig_existing_zone_to_copy: public + # RHEL-08-040090 -# rhel8stig_white_list_services is the services that you want to allow through initially for teh new firewall zone +# This designed not work with rhel8stig_existing_zone_to_copy and when deploy new rules +# rhel8stig_white_list_services is the services that you want to allow through initially for the new firewall zone # http and ssh need to be enabled for the role to run. # This can also be a port number if no service exists rhel8stig_white_list_services: + - ssh - http - https - - ssh # RHEL-08-010290 # RHEL-08-010290 diff --git a/tasks/fix-cat1.yml b/tasks/fix-cat1.yml index 28ecec5..04597be 100644 --- a/tasks/fix-cat1.yml +++ b/tasks/fix-cat1.yml @@ -276,18 +276,18 @@ - name: "HIGH | RHEL-08-010470 | PATCH | There must be no .shosts files on the RHEL 8 operating system." block: - name: "HIGH | RHEL-08-010470 | PATCH | There must be no .shosts files on the RHEL 8 operating system. | Find .shosts files" - ansible.builtin.find: - path: '/' - recurse: true - patterns: '*.shosts' + ansible.builtin.shell: find / -name "*.shosts" + changed_when: false + failed_when: rhel_08_010470_shost_files.rc not in [ 0, 1 ] register: rhel_08_010470_shost_files - name: "HIGH | RHEL-08-010470 | PATCH | There must be no .shosts files on the RHEL 8 operating system. | Remove .shosts files" ansible.builtin.file: - path: "{{ item.path }}" + path: "{{ item }}" state: absent with_items: - - "{{ rhel_08_010470_shost_files.files }}" + - "{{ rhel_08_010470_shost_files.stdout_lines }}" + when: rhel_08_010470_shost_files.stdout | length > 0 when: - rhel_08_010470 tags: diff --git a/tasks/fix-cat2.yml b/tasks/fix-cat2.yml index 0f4c63b..9120242 100644 --- a/tasks/fix-cat2.yml +++ b/tasks/fix-cat2.yml @@ -461,19 +461,18 @@ - name: "MEDIUM | RHEL-08-010161 | PATCH | RHEL 8 must prevent system daemons from using Kerberos for authentication." block: - name: "MEDIUM | RHEL-08-010161 | AUDIT | RHEL 8 must prevent system daemons from using Kerberos for authentication. | Find .keytab files" - ansible.builtin.find: - path: / - patterns: '*.keytab' - recurse: true + ansible.builtin.shell: find / -name *.keytab + changed_when: false + failed_when: rhel8stig_010161_keytab_files.rc not in [ 0, 1 ] register: rhel8stig_010161_keytab_files - name: "MEDIUM | RHEL-08-010161 | PATCH | RHEL 8 must prevent system daemons from using Kerberos for authentication. | Remove .keytab files" ansible.builtin.file: - path: "{{ item.path }}" + path: "{{ item }}" state: absent with_items: - - "{{ rhel8stig_010161_keytab_files.files }}" - when: rhel8stig_010161_keytab_files.matched > 0 + - "{{ rhel8stig_010161_keytab_files.stdout_lines }}" + when: rhel8stig_010161_keytab_files.stdout | length > 0 when: - rhel_08_010161 tags: @@ -1629,25 +1628,19 @@ - name: "MEDIUM | RHEL-08-010480 | PATCH | The RHEL 8 SSH public host key files must have mode 0644 or less permissive." block: - name: "MEDIUM | RHEL-08-010480 | AUDIT | The RHEL 8 SSH public host key files must have mode 0644 or less permissive. | Find files" - ansible.builtin.find: - paths: /etc/ssh - recurse: true - file_type: file - patterns: 'ssh_host*_key.pub' - hidden: true + ansible.builtin.shell: find /etc/ssh -name ssh_host*_key.pub changed_when: false - failed_when: false + failed_when: rhel_08_010480_public_files.rc not in [ 0, 1 ] register: rhel_08_010480_public_files - name: "MEDIUM | RHEL-08-010480 | PATCH | The RHEL 8 SSH public host key files must have mode 0644 or less permissive. | Set permissions" ansible.builtin.file: - path: "{{ item.path }}" + path: "{{ item }}" mode: "{{ rhel8stig_ssh_pub_key_perm }}" with_items: - - "{{ rhel_08_010480_public_files.files }}" - loop_control: - label: "{{ item.path }}" + - "{{ rhel_08_010480_public_files.stdout_lines }}" notify: restart sshd + when: rhel_08_010480_public_files.stdout | length > 0 when: - rhel_08_010480 - rhel8stig_ssh_required @@ -1663,25 +1656,19 @@ - name: "MEDIUM | RHEL-08-010490 | PATCH | The RHEL 8 SSH private host key files must have mode 0640 or less permissive." block: - name: "MEDIUM | RHEL-08-010490 | AUDIT | The RHEL 8 SSH private host key files must have mode 0640 or less permissive. | Find files" - ansible.builtin.find: - paths: /etc/ssh - recurse: true - file_type: file - patterns: 'ssh_host*key' - hidden: true + ansible.builtin.shell: find /etc/ssh -name ssh_host*_key changed_when: false - failed_when: false + failed_when: rhel_08_010490_private_host_key_files.rc not in [ 0, 1 ] register: rhel_08_010490_private_host_key_files - name: "MEDIUM | RHEL-08-010490 | PATCH | The RHEL 8 SSH private host key files must have mode 0640 or less permissive. | Set permissions" ansible.builtin.file: - path: "{{ item.path }}" + path: "{{ item }}" mode: "{{ rhel8stig_ssh_priv_key_perm }}" with_items: - - "{{ rhel_08_010490_private_host_key_files.files }}" - loop_control: - label: "{{ item.path }}" + - "{{ rhel_08_010490_private_host_key_files.stdout_lines }}" notify: restart sshd + when: rhel_08_010490_private_host_key_files.stdout | length > 0 when: - rhel_08_010490 - rhel8stig_ssh_required @@ -2229,7 +2216,6 @@ when: - rhel_08_010660 - rhel8stig_disruption_high - # - rhel_08_stig_interactive_homedir_inifiles is defined tags: - RHEL-08-010660 - CAT2 @@ -2440,7 +2426,7 @@ block: - name: "MEDIUM | RHEL-08-010690 | AUDIT | Executable search paths within the initialization files of all local interactive RHEL 8 users must only contain paths that resolve to the system default or the users home directory. | Find path files" ansible.builtin.shell: find "{{ item }}" -maxdepth 1 -type f | xargs grep "PATH=" | cut -d':' -f1 | xargs realpath - with_items: "{{ rhel_08_stig_interactive_homedir_results }}" + with_items: "{{ discovered_interactive_users_home.stdout_list }}" register: rhel_08_010690_ini_path_grep_list changed_when: false failed_when: false @@ -2557,15 +2543,31 @@ - SV-230320r627750_rule - V-230320 +# Required for RHEL-08-010730 +- name: "MEDIUM | RHEL-08-010750 | PATCH | All RHEL 8 local interactive user home directories defined in the /etc/passwd file must exist." + ansible.builtin.file: + path: "{{ item }}" + state: directory + with_items: "{{ discovered_interactive_users_home.stdout_lines }}" + when: + - rhel_08_010750 + tags: + - RHEL-08-010750 + - CAT2 + - CCI-000366 + - SRG-OS-000480-GPOS-00227 + - SV-230323r627750_rule + - V-230323 + - permissions + - name: "MEDIUM | RHEL-08-010730 | PATCH | All RHEL 8 local interactive user home directories must have mode 0750 or less permissive." ansible.builtin.file: path: "{{ item }}" mode: "{{ rhel8stig_local_int_home_perms }}" with_items: - - "{{ local_home_directories.stdout_lines }}" + - "{{ discovered_interactive_users_home.stdout_lines }}" when: - rhel_08_010730 - - local_home_directories.stdout | length > 0 tags: - RHEL-08-010730 - CAT2 @@ -2577,20 +2579,12 @@ - name: "MEDIUM | RHEL-08-010731 | PATCH | All RHEL 8 local interactive user home directory files must have mode 0750 or less permissive." block: - - name: "MEDIUM | RHEL-08-010731 | AUDIT | All RHEL 8 local interactive user home directory files must have mode 0750 or less permissive. | Find out of compliance files" - ansible.builtin.shell: "find {{ item }} -perm -750 ! -perm 750" - changed_when: false - failed_when: false - register: rhel_08_010731_files - with_items: - - "{{ rhel8stig_passwd | selectattr('uid', '>=', rhel8stig_interactive_uid_start | int) | selectattr('uid', '!=', 65534) | map(attribute='dir') | list }}" - - name: "MEDIUM | RHEL-08-010731 | PATCH | All RHEL 8 local interactive user home directory files must have mode 0750 or less permissive. | Bring files into compliance" ansible.builtin.file: path: "{{ item }}" mode: "{{ rhel8stig_local_int_home_file_perms }}" with_items: - - "{{ rhel_08_010731_files.results | map(attribute='stdout_lines') | flatten }}" + - "{{ discovered_interactive_users_home.stdout_lines }}" when: rhel8stig_disruption_high - name: "MEDIUM | RHEL-08-010731 | AUDIT | All RHEL 8 local interactive user home directory files must have mode 0750 or less permissive. | Alert on out of compliance files" @@ -2598,7 +2592,7 @@ msg: - "Alert! Below are the files that are in interactive user folders but permissiosn less restrictiv than 0750." - "Please review the files to bring into STIG compliance" - - "{{ rhel_08_010731_files.results | map(attribute='stdout_lines') | flatten }}" + - "{{ discovered_interactive_users_home.stdout_lines }}" when: not rhel8stig_disruption_high when: - rhel_08_010731 @@ -2621,10 +2615,8 @@ label: "{{ rhel8stig_passwd_label }}" when: - rhel_08_010740 - - (item.uid >= rhel8stig_interactive_uid_start | int) - - (item.uid >= rhel8stig_interactive_uid_stop | int) + - item.uid is search(discovered_interactive_uids.stdout) tags: - - skip_ansible_lint - RHEL-08-010740 - CAT2 - CCI-000366 @@ -2644,8 +2636,7 @@ label: "{{ rhel8stig_passwd_label }}" when: - rhel_08_010741 - - (item.uid >= rhel8stig_interactive_uid_start | int) - - item.uid != 65534 + - item.uid is search(discovered_interactive_uids.stdout) tags: - RHEL-08-010741 - CAT2 @@ -2655,26 +2646,6 @@ - V-244532 - permissions -- name: "MEDIUM | RHEL-08-010750 | PATCH | All RHEL 8 local interactive user home directories defined in the /etc/passwd file must exist." - ansible.builtin.file: - path: "{{ item.dir }}" - state: directory - with_items: "{{ rhel8stig_passwd }}" - loop_control: - label: "{{ rhel8stig_passwd_label }}" - when: - - rhel_08_010750 - - (item.uid >= rhel8stig_interactive_uid_start | int) - tags: - - skip_ansible_lint - - RHEL-08-010750 - - CAT2 - - CCI-000366 - - SRG-OS-000480-GPOS-00227 - - SV-230323r627750_rule - - V-230323 - - permissions - - name: "MEDIUM | RHEL-08-010760 | PATCH | All RHEL 8 local interactive user accounts must be assigned a home directory upon creation." ansible.builtin.lineinfile: path: /etc/login.defs @@ -3234,7 +3205,7 @@ - password-auth when: - rhel_08_020022 - - ansible_distribution_version is version('8.2', '>=') + - ansible_distribution_version is version('8.1', '<=') tags: - RHEL-08-020022 - CAT2 @@ -4399,7 +4370,7 @@ hidden: true use_regex: true register: rhel8stig_020352_file - loop: "{{ local_home_directories.stdout_lines }}" + loop: "{{ discovered_interactive_users_home.stdout_lines }}" - name: "MEDIUM | RHEL-08-020352 | PATCH | RHEL 8 must set the umask value to 077 for all local interactive user accounts. | Remove umask param" ansible.builtin.lineinfile: @@ -6084,15 +6055,38 @@ permanent: true state: present + - name: "MEDIUM | RHEL-08-040090 | PATCH | A RHEL 8 firewall must employ a deny-all, allow-by-exception policy for allowing connections to other systems. | Copy existing rules to new zone" + ansible.builtin.copy: + src: "/etc/firewalld/zones/{{ rhel8stig_existing_zone_to_copy }}.xml" + dest: "/etc/firewalld/zones/{{ rhel8stig_custom_firewall_zone }}.xml" + remote_src: true + when: + - rhel8stig_copy_existing_zone + - rhel8stig_existing_zone_to_copy | length > 0 + + - name: "MEDIUM | RHEL-08-040090 | PATCH | A RHEL 8 firewall must employ a deny-all, allow-by-exception policy for allowing connections to other systems. | Amend copied file" + ansible.builtin.replace: + path: "/etc/firewalld/zones/{{ rhel8stig_custom_firewall_zone }}.xml" + regexp: "{{ item.regexp }}" + replace: \1{{ item.replace }}\2 + loop: + - { regexp: (\s*(\s*$), replace: ' target="DROP">' } + - { regexp: (\s*).*(<\/short>), replace: "{{ rhel8stig_custom_firewall_zone }}" } + when: + - rhel8stig_copy_existing_zone + - rhel8stig_existing_zone_to_copy | length > 0 + - name: "MEDIUM | RHEL-08-040090 | PATCH | A RHEL 8 firewall must employ a deny-all, allow-by-exception policy for allowing connections to other systems. | Allow internet and ssh" ansible.posix.firewalld: zone: "{{ rhel8stig_custom_firewall_zone }}" permanent: true state: enabled - service: "{{ (item == (item | regex_search('^[a-z]+$'))) | bool | ternary(item, omit) }}" - port: "{{ (item == (item | regex_search('^[0-9]+/[a-z]+$'))) | bool | ternary(item, omit) }}" + service: "{{ (item == (item | regex_search('^[a-z]+$'))) | ternary(item, omit) }}" + port: "{{ (item == (item | regex_search('^[0-9]+/[a-z]+$'))) | ternary(item, omit) }}" with_items: - "{{ rhel8stig_white_list_services }}" + when: + - not rhel8stig_copy_existing_zone - name: "MEDIUM | RHEL-08-040090 | PATCH | A RHEL 8 firewall must employ a deny-all, allow-by-exception policy for allowing connections to other systems. | Target Drop | 2.10+" ansible.posix.firewalld: @@ -6100,7 +6094,9 @@ permanent: true state: enabled target: DROP - when: ansible_version.full is version_compare('2.10.0 | int', '>=') + when: + - ansible_version.full is version_compare('2.10.0 | int', '>=') + - not rhel8stig_copy_existing_zone - name: "MEDIUM | RHEL-08-040090 | PATCH | A RHEL 8 firewall must employ a deny-all, allow-by-exception policy for allowing connections to other systems. | Target Drop | 2.9" block: @@ -6114,7 +6110,9 @@ ansible.builtin.shell: firewall-cmd --permanent --zone={{ rhel8stig_custom_firewall_zone }} --set-target=DROP when: - rhel8stig_target_drop_set.rc != 0 - when: ansible_version.full is version_compare('2.10 | int', '<') + when: + - ansible_version.full is version_compare('2.10 | int', '<') + - not rhel8stig_copy_existing_zone - name: "MEDIUM | RHEL-08-040090 | PATCH | A RHEL 8 firewall must employ a deny-all, allow-by-exception policy for allowing connections to other systems. | Reload zones" ansible.builtin.shell: firewall-cmd --reload @@ -7144,7 +7142,7 @@ - name: "MEDIUM | RHEL-08-040279 | PATCH | RHEL 8 must ignore IPv4 Internet Control Message Protocol (ICMP) redirect messages. | Use template to create file" ansible.posix.sysctl: - name: net.ipv4.conf.all.send_redirects + name: net.ipv4.conf.all.accept_redirects value: 0 state: present reload: "{{ rhel8stig_sysctl_reload }}" diff --git a/tasks/main.yml b/tasks/main.yml index 4ce2c93..96d3f1d 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -36,7 +36,7 @@ ansible.builtin.include_vars: file: "{{ container_vars_file }}" - - name: output if discovered is a container + - name: Output if discovered is a container ansible.builtin.debug: msg: system has been discovered as a container when: @@ -150,17 +150,17 @@ - name: Include CAT III patches ansible.builtin.import_tasks: fix-cat3.yml - when: rhel8stig_cat3_patch | bool + when: rhel8stig_cat3_patch tags: - CAT3 - low -- name: flush handlers +- name: Flush handlers ansible.builtin.meta: flush_handlers -- name: reboot system +- name: Reboot system block: - - name: reboot system if not skipped + - name: Reboot system if not skipped ansible.builtin.reboot: when: - change_requires_reboot @@ -174,7 +174,7 @@ - change_requires_reboot - rhel8stig_skip_reboot -- name: run post remediation audit +- name: Run post remediation audit ansible.builtin.import_tasks: post_remediation_audit.yml when: - run_audit diff --git a/tasks/prelim.yml b/tasks/prelim.yml index 4aad42c..17891e5 100644 --- a/tasks/prelim.yml +++ b/tasks/prelim.yml @@ -234,15 +234,39 @@ - RHEL-08-010750 - RHEL-08-020320 -- name: "PRELIM | RHEL-08-010690 Ensure user enumeration command is modified when autofs remote home directories are in use" +- name: "PRELIM | AUDIT | Discover Interactive Users" + tags: + - always + ansible.builtin.shell: > + grep -E -v '^(root|halt|sync|shutdown)' /etc/passwd | awk -F: '(!index($7, "sbin/nologin") && $7 != "/bin/nologin" && $7 != "/bin/false") { print $1 }' + changed_when: false + register: discovered_interactive_usernames + +- name: "PRELIM | AUDIT | Discover Interactive User accounts home directories" + tags: + - always + ansible.builtin.shell: > + grep -E -v '^(root|halt|sync|shutdown)' /etc/passwd | awk -F: '(!index($7, "sbin/nologin") && $7 != "/bin/nologin" && $7 != "/bin/false") { print $6 }' + changed_when: false + register: discovered_interactive_users_home + +- name: "PRELIM | AUDIT | Discover Interactive user UIDs" + tags: + - always + ansible.builtin.shell: > + grep -E -v '^(root|halt|sync|shutdown)' /etc/passwd | awk -F: '(!index($7, "sbin/nologin") && $7 != "/bin/nologin" && $7 != "/bin/false") { print $3 }' + changed_when: false + register: discovered_interactive_uids + +- name: "PRELIM | RHEL-08-010690 | Ensure user enumeration command is modified when autofs remote home directories are in use" block: - - name: Ensure that rhel8stig_auto_mount_home_dirs_local_mount_point is defined and not length zero + - name: PRELIM | RHEL-08-010690 | AUDIT | Ensure that rhel8stig_auto_mount_home_dirs_local_mount_point is defined and not length zero ansible.builtin.assert: that: - rhel8stig_auto_mount_home_dirs_local_mount_point is defined - rhel8stig_auto_mount_home_dirs_local_mount_point | length > 0 - - name: Modify local_interactive_user_dir_command to exclude remote automounted home directories + - name: PRELIM | RHEL-08-010690 | PATCH | Modify local_interactive_user_dir_command to exclude remote automounted home directories ansible.builtin.set_fact: local_interactive_user_dir_command: "{{ local_interactive_user_dir_command }} | grep -v '{{ rhel8stig_auto_mount_home_dirs_local_mount_point }}" @@ -283,17 +307,6 @@ - RHEL-08-010070 - RHEL-08-030010 -- name: "PRELIM | RHEL-08-010730 | RHEL-08-20352 | Get local interactive user home directories" - ansible.builtin.shell: ls -d $(awk -F':' '($3>=1000)&&($1!="nobody"){print $6}' /etc/passwd) - changed_when: false - failed_when: false - register: local_home_directories - when: - - rhel_08_010730 or - rhel_08_020352 - tags: - - always - - name: "PRELIM | RHEL-08-030620 | RHEL-08-030630 | RHEL-08-030640 | RHEL-08-030650 | Install audit remote plugin." ansible.builtin.package: name: audispd-plugins @@ -410,13 +423,13 @@ - RHEL-08-010770 - complexity-high -- name: Gather the package facts +- name: "PRELIM | Gather the package facts" ansible.builtin.package_facts: manager: auto tags: - always -- name: "PRELIM | RHEL-08-020017 | RHEL-08-020027 | REHL-08-020028 | If using selinux set up system prereqs" +- name: "PRELIM | RHEL-08-020017 | RHEL-08-020027 | RHEL-08-020028 | If using selinux set up system prereqs" block: - name: "PRELIM | RHEL-08-020017 | Install policycoreutils-python-utils" ansible.builtin.package: