diff --git a/tasks/main.yml b/tasks/main.yml index 760ee1b..63bcfad 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,262 +1,265 @@ --- # tasks file for RHEL9-CIS -- name: "Check OS version and family" - when: os_check - tags: always - ansible.builtin.assert: - that: (ansible_facts.distribution != 'CentOS' and ansible_facts.os_family == 'RedHat' or ansible_facts.os_family == "Rocky") and ansible_facts.distribution_major_version is version_compare('9', '==') - fail_msg: "This role can only be run against Supported OSs. {{ ansible_facts.distribution }} {{ ansible_facts.distribution_major_version }} is not supported." - success_msg: "This role is running against a supported OS {{ ansible_facts.distribution }} {{ ansible_facts.distribution_major_version }}" - -- name: "Check ansible version" - tags: always - ansible.builtin.assert: - that: ansible_version.full is version_compare(min_ansible_version, '>=') - fail_msg: "You must use Ansible {{ min_ansible_version }} or greater" - success_msg: "This role is running a supported version of ansible {{ ansible_version.full }} >= {{ min_ansible_version }}" - -- name: "Setup rules if container" - when: - - ansible_connection == 'docker' or - ansible_facts.virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] - tags: - - container_discovery - - always +- name: "RHEL9-CIS" + become: true block: - - name: "Discover and set container variable if required" - ansible.builtin.set_fact: - system_is_container: true + - name: "Check OS version and family" + when: os_check + tags: always + ansible.builtin.assert: + that: (ansible_facts.distribution != 'CentOS' and ansible_facts.os_family == 'RedHat' or ansible_facts.os_family == "Rocky") and ansible_facts.distribution_major_version is version_compare('9', '==') + fail_msg: "This role can only be run against Supported OSs. {{ ansible_facts.distribution }} {{ ansible_facts.distribution_major_version }} is not supported." + success_msg: "This role is running against a supported OS {{ ansible_facts.distribution }} {{ ansible_facts.distribution_major_version }}" - - name: "Load variable for container" - ansible.builtin.include_vars: - file: "{{ container_vars_file }}" + - name: "Check ansible version" + tags: always + ansible.builtin.assert: + that: ansible_version.full is version_compare(min_ansible_version, '>=') + fail_msg: "You must use Ansible {{ min_ansible_version }} or greater" + success_msg: "This role is running a supported version of ansible {{ ansible_version.full }} >= {{ min_ansible_version }}" - - name: "Output if discovered is a container" - when: system_is_container - ansible.builtin.debug: - msg: system has been discovered as a container - -- name: "Check crypto-policy input" - ansible.builtin.assert: - that: rhel9cis_crypto_policy in rhel9cis_allowed_crypto_policies - fail_msg: "Crypto policy is not a permitted version" - success_msg: "Crypto policy is a permitted version" - -- name: "Check rhel9cis_bootloader_password_hash variable has been changed" - when: - - rhel9cis_set_boot_pass - - rhel9cis_rule_1_4_1 - tags: always - ansible.builtin.assert: - that: rhel9cis_bootloader_password_hash.find('grub.pbkdf2.sha512') != -1 and rhel9cis_bootloader_password_hash != 'grub.pbkdf2.sha512.changethispassword' # pragma: allowlist secret - msg: "This role will not be able to run single user password commands as rhel9cis_bootloader_password_hash variable has not been set correctly" - -- name: "Check crypto-policy module input" - when: - - rhel9cis_rule_1_6_1 - - rhel9cis_crypto_policy_module | length > 0 - tags: - - rule_1.6.1 - - crypto - - NIST800-53R5_SC-6 - ansible.builtin.assert: - that: rhel9cis_additional_crypto_policy_module in rhel9cis_allowed_crypto_policies_modules - fail_msg: "Crypto policy module is not a permitted version" - success_msg: "Crypto policy module is a permitted version" - -- name: "Check password set for {{ ansible_env.SUDO_USER }}" - when: - - rhel9cis_rule_5_2_4 - - ansible_env.SUDO_USER is defined - - not system_is_ec2 - tags: - - user_passwd - - rule_5.2.4 - vars: - sudo_password_rule: rhel9cis_rule_5_2_4 # pragma: allowlist secret - block: - - name: "Check password set for {{ ansible_env.SUDO_USER }} | password state" # noqa name[template] - ansible.builtin.shell: "(grep {{ ansible_env.SUDO_USER }} /etc/shadow || echo 'not found:not found') | awk -F: '{print $2}'" - changed_when: false - failed_when: false - check_mode: false - register: prelim_ansible_user_password_set - - - name: "Check for local account {{ ansible_env.SUDO_USER }} | Check for local account" # noqa name[template] - when: prelim_ansible_user_password_set.stdout == "not found" - ansible.builtin.debug: - msg: "No local account found for {{ ansible_env.SUDO_USER }} user. Skipping local account checks." - - - name: "Check local account" - when: prelim_ansible_user_password_set.stdout != "not found" + - name: "Setup rules if container" + when: + - ansible_connection == 'docker' or + ansible_facts.virtualization_type in ["docker", "lxc", "openvz", "podman", "container"] + tags: + - container_discovery + - always block: - - name: "Check password set for {{ ansible_env.SUDO_USER }} | Assert local password set" # noqa name[template] - ansible.builtin.assert: - that: | - ( - ((prelim_ansible_user_password_set.stdout | length != 0) and (prelim_ansible_user_password_set.stdout != "!!" )) - or - (ansible_env.SUDO_USER in rhel9cis_sudoers_exclude_nopasswd_list) - ) - fail_msg: "You have {{ sudo_password_rule }} enabled but the user = {{ ansible_env.SUDO_USER }} has no password set or or the user is not included in the exception list for rule 5.2.4 - It can break access" - success_msg: "You have a password set for the {{ ansible_env.SUDO_USER }} user or the user is included in the exception list for rule 5.2.4" + - name: "Discover and set container variable if required" + ansible.builtin.set_fact: + system_is_container: true - - name: "Check account is not locked for {{ ansible_env.SUDO_USER }} | Assert local account not locked" # noqa name[template] - ansible.builtin.assert: - that: (not prelim_ansible_user_password_set.stdout.startswith("!")) or (ansible_env.SUDO_USER in rhel9cis_sudoers_exclude_nopasswd_list) - fail_msg: "You have {{ sudo_password_rule }} enabled but the user = {{ ansible_env.SUDO_USER }} is locked - It can break access" - success_msg: "The local account {{ ansible_env.SUDO_USER }} is not locked or included in the exception list for rule 5.2.4" + - name: "Load variable for container" + ansible.builtin.include_vars: + file: "{{ container_vars_file }}" -- name: "Check authselect profile is selected" - when: rhel9cis_allow_authselect_updates - tags: always - block: - - name: "Check authselect profile name has been updated | Ensure name from default is changed" + - name: "Output if discovered is a container" + when: system_is_container + ansible.builtin.debug: + msg: system has been discovered as a container + + - name: "Check crypto-policy input" ansible.builtin.assert: - that: rhel9cis_authselect_custom_profile_name != 'cis_example_profile' - fail_msg: "You still have the default name for your authselect profile" + that: rhel9cis_crypto_policy in rhel9cis_allowed_crypto_policies + fail_msg: "Crypto policy is not a permitted version" + success_msg: "Crypto policy is a permitted version" - - name: "Check authselect profile is selected | Check current profile" - ansible.builtin.command: authselect list - changed_when: false - failed_when: prelim_authselect_current_profile.rc not in [ 0, 1 ] - register: prelim_authselect_current_profile + - name: "Check rhel9cis_bootloader_password_hash variable has been changed" + when: + - rhel9cis_set_boot_pass + - rhel9cis_rule_1_4_1 + tags: always + ansible.builtin.assert: + that: rhel9cis_bootloader_password_hash.find('grub.pbkdf2.sha512') != -1 and rhel9cis_bootloader_password_hash != 'grub.pbkdf2.sha512.changethispassword' # pragma: allowlist secret + msg: "This role will not be able to run single user password commands as rhel9cis_bootloader_password_hash variable has not been set correctly" -- name: "Ensure root password is set" - when: rhel9cis_rule_5_4_2_4 - tags: - - level1-server - - level1-workstation - - patch - - accounts - - root - - rule_5.4.2.4 - block: - - name: "Ensure root password is set" - ansible.builtin.shell: LC_ALL=C passwd -S root | grep -E "(Password set|Password locked)" - changed_when: false - failed_when: prelim_root_passwd_set.rc not in [ 0, 1 ] - register: prelim_root_passwd_set + - name: "Check crypto-policy module input" + when: + - rhel9cis_rule_1_6_1 + - rhel9cis_crypto_policy_module | length > 0 + tags: + - rule_1.6.1 + - crypto + - NIST800-53R5_SC-6 + ansible.builtin.assert: + that: rhel9cis_additional_crypto_policy_module in rhel9cis_allowed_crypto_policies_modules + fail_msg: "Crypto policy module is not a permitted version" + success_msg: "Crypto policy module is a permitted version" + + - name: "Check password set for {{ ansible_env.SUDO_USER }}" + when: + - rhel9cis_rule_5_2_4 + - ansible_env.SUDO_USER is defined + - not system_is_ec2 + tags: + - user_passwd + - rule_5.2.4 + vars: + sudo_password_rule: rhel9cis_rule_5_2_4 # pragma: allowlist secret + block: + - name: "Check password set for {{ ansible_env.SUDO_USER }} | password state" # noqa name[template] + ansible.builtin.shell: "(grep {{ ansible_env.SUDO_USER }} /etc/shadow || echo 'not found:not found') | awk -F: '{print $2}'" + changed_when: false + failed_when: false + check_mode: false + register: prelim_ansible_user_password_set + + - name: "Check for local account {{ ansible_env.SUDO_USER }} | Check for local account" # noqa name[template] + when: prelim_ansible_user_password_set.stdout == "not found" + ansible.builtin.debug: + msg: "No local account found for {{ ansible_env.SUDO_USER }} user. Skipping local account checks." + + - name: "Check local account" + when: prelim_ansible_user_password_set.stdout != "not found" + block: + - name: "Check password set for {{ ansible_env.SUDO_USER }} | Assert local password set" # noqa name[template] + ansible.builtin.assert: + that: | + ( + ((prelim_ansible_user_password_set.stdout | length != 0) and (prelim_ansible_user_password_set.stdout != "!!" )) + or + (ansible_env.SUDO_USER in rhel9cis_sudoers_exclude_nopasswd_list) + ) + fail_msg: "You have {{ sudo_password_rule }} enabled but the user = {{ ansible_env.SUDO_USER }} has no password set or or the user is not included in the exception list for rule 5.2.4 - It can break access" + success_msg: "You have a password set for the {{ ansible_env.SUDO_USER }} user or the user is included in the exception list for rule 5.2.4" + + - name: "Check account is not locked for {{ ansible_env.SUDO_USER }} | Assert local account not locked" # noqa name[template] + ansible.builtin.assert: + that: (not prelim_ansible_user_password_set.stdout.startswith("!")) or (ansible_env.SUDO_USER in rhel9cis_sudoers_exclude_nopasswd_list) + fail_msg: "You have {{ sudo_password_rule }} enabled but the user = {{ ansible_env.SUDO_USER }} is locked - It can break access" + success_msg: "The local account {{ ansible_env.SUDO_USER }} is not locked or included in the exception list for rule 5.2.4" + + - name: "Check authselect profile is selected" + when: rhel9cis_allow_authselect_updates + tags: always + block: + - name: "Check authselect profile name has been updated | Ensure name from default is changed" + ansible.builtin.assert: + that: rhel9cis_authselect_custom_profile_name != 'cis_example_profile' + fail_msg: "You still have the default name for your authselect profile" + + - name: "Check authselect profile is selected | Check current profile" + ansible.builtin.command: authselect list + changed_when: false + failed_when: prelim_authselect_current_profile.rc not in [ 0, 1 ] + register: prelim_authselect_current_profile - name: "Ensure root password is set" - ansible.builtin.assert: - that: prelim_root_passwd_set.rc == 0 - fail_msg: "You have rule 5.4.2.4 enabled this requires that you have a root password set" - success_msg: "You have a root password set" + when: rhel9cis_rule_5_4_2_4 + tags: + - level1-server + - level1-workstation + - patch + - accounts + - root + - rule_5.4.2.4 + block: + - name: "Ensure root password is set" + ansible.builtin.shell: LC_ALL=C passwd -S root | grep -E "(Password set|Password locked)" + changed_when: false + failed_when: prelim_root_passwd_set.rc not in [ 0, 1 ] + register: prelim_root_passwd_set -- name: "Gather the package facts" - tags: always - ansible.builtin.package_facts: - manager: auto + - name: "Ensure root password is set" + ansible.builtin.assert: + that: prelim_root_passwd_set.rc == 0 + fail_msg: "You have rule 5.4.2.4 enabled this requires that you have a root password set" + success_msg: "You have a root password set" -- name: "Include OS specific variables" - tags: always - ansible.builtin.include_vars: - file: "{{ ansible_facts.distribution }}.yml" + - name: "Gather the package facts" + tags: always + ansible.builtin.package_facts: + manager: auto -- name: "Include preliminary steps" - tags: - - prelim_tasks - - always - ansible.builtin.import_tasks: - file: prelim.yml + - name: "Include OS specific variables" + tags: always + ansible.builtin.include_vars: + file: "{{ ansible_facts.distribution }}.yml" -- name: "Run Section 1 tasks" - when: rhel9cis_section1 - ansible.builtin.import_tasks: - file: section_1/main.yml + - name: "Include preliminary steps" + tags: + - prelim_tasks + - always + ansible.builtin.import_tasks: + file: prelim.yml -- name: "Run Section 2 tasks" - when: rhel9cis_section2 - ansible.builtin.import_tasks: - file: section_2/main.yml + - name: "Run Section 1 tasks" + when: rhel9cis_section1 + ansible.builtin.import_tasks: + file: section_1/main.yml -- name: "Run Section 3 tasks" - when: rhel9cis_section3 - ansible.builtin.import_tasks: - file: section_3/main.yml + - name: "Run Section 2 tasks" + when: rhel9cis_section2 + ansible.builtin.import_tasks: + file: section_2/main.yml -- name: "Run Section 4 tasks" - when: rhel9cis_section4 - ansible.builtin.import_tasks: - file: section_4/main.yml + - name: "Run Section 3 tasks" + when: rhel9cis_section3 + ansible.builtin.import_tasks: + file: section_3/main.yml -- name: "Run Section 5 tasks" - when: rhel9cis_section5 - ansible.builtin.import_tasks: - file: section_5/main.yml + - name: "Run Section 4 tasks" + when: rhel9cis_section4 + ansible.builtin.import_tasks: + file: section_4/main.yml -- name: "Run Section 6 tasks" - when: rhel9cis_section6 - ansible.builtin.import_tasks: - file: section_6/main.yml + - name: "Run Section 5 tasks" + when: rhel9cis_section5 + ansible.builtin.import_tasks: + file: section_5/main.yml -- name: "Run Section 7 tasks" - when: rhel9cis_section7 - ansible.builtin.import_tasks: - file: section_7/main.yml + - name: "Run Section 6 tasks" + when: rhel9cis_section6 + ansible.builtin.import_tasks: + file: section_6/main.yml -- name: "Run auditd logic" - when: update_audit_template - tags: always - ansible.builtin.import_tasks: - file: auditd.yml + - name: "Run Section 7 tasks" + when: rhel9cis_section7 + ansible.builtin.import_tasks: + file: section_7/main.yml -- name: "Run post remediation tasks" - tags: - - post_tasks - - always - ansible.builtin.import_tasks: - file: post.yml + - name: "Run auditd logic" + when: update_audit_template + tags: always + ansible.builtin.import_tasks: + file: auditd.yml -- name: "Run post_remediation audit" - when: run_audit - tags: always - ansible.builtin.import_tasks: - file: post_remediation_audit.yml + - name: "Run post remediation tasks" + tags: + - post_tasks + - always + ansible.builtin.import_tasks: + file: post.yml -- name: Add ansible file showing Benchmark and levels applied if audit details not present - when: - - create_benchmark_facts - - (post_audit_summary is defined) or - (ansible_local['compliance_facts']['lockdown_audit_details']['audit_summary'] is undefined and post_audit_summary is undefined) - tags: - - always - - benchmark - block: - - name: Create ansible facts directory if audit facts not present - ansible.builtin.file: - path: "{{ ansible_facts_path }}" - state: directory - owner: root - group: root - mode: 'u=rwx,go=rx' + - name: "Run post_remediation audit" + when: run_audit + tags: always + ansible.builtin.import_tasks: + file: post_remediation_audit.yml - - name: Create ansible facts file and levels applied if audit facts not present - ansible.builtin.template: - src: etc/ansible/compliance_facts.j2 - dest: "{{ ansible_facts_path }}/compliance_facts.fact" - owner: root - group: root - mode: 'u-x,go=r' + - name: Add ansible file showing Benchmark and levels applied if audit details not present + when: + - create_benchmark_facts + - (post_audit_summary is defined) or + (ansible_local['compliance_facts']['lockdown_audit_details']['audit_summary'] is undefined and post_audit_summary is undefined) + tags: + - always + - benchmark + block: + - name: Create ansible facts directory if audit facts not present + ansible.builtin.file: + path: "{{ ansible_facts_path }}" + state: directory + owner: root + group: root + mode: 'u=rwx,go=rx' -- name: Fetch audit files - when: - - fetch_audit_output - - run_audit - tags: always - ansible.builtin.import_tasks: - file: fetch_audit_output.yml + - name: Create ansible facts file and levels applied if audit facts not present + ansible.builtin.template: + src: etc/ansible/compliance_facts.j2 + dest: "{{ ansible_facts_path }}/compliance_facts.fact" + owner: root + group: root + mode: 'u-x,go=r' -- name: "Show Audit Summary" - when: run_audit - tags: always - ansible.builtin.debug: - msg: "{{ audit_results.split('\n') }}" + - name: Fetch audit files + when: + - fetch_audit_output + - run_audit + tags: always + ansible.builtin.import_tasks: + file: fetch_audit_output.yml -- name: "If Warnings found Output count and control IDs affected" - when: warn_count != 0 - tags: always - ansible.builtin.debug: - msg: "You have {{ warn_count }} Warning(s) that require investigating that are related to the following benchmark ID(s) {{ warn_control_list }}" + - name: "Show Audit Summary" + when: run_audit + tags: always + ansible.builtin.debug: + msg: "{{ audit_results.split('\n') }}" + + - name: "If Warnings found Output count and control IDs affected" + when: warn_count != 0 + tags: always + ansible.builtin.debug: + msg: "You have {{ warn_count }} Warning(s) that require investigating that are related to the following benchmark ID(s) {{ warn_control_list }}"