From c6caa90059ee6637872d07d6c23ab1b70fb093e4 Mon Sep 17 00:00:00 2001 From: Mark Bolwell Date: Wed, 30 Mar 2022 16:18:11 +0100 Subject: [PATCH] updated Signed-off-by: Mark Bolwell --- README.md | 1 + defaults/main.yml | 137 ++-- tasks/section_3/cis_3.3.x.yml | 6 +- tasks/section_3/cis_3.4.1.1.yml | 14 - tasks/section_3/cis_3.4.1.x.yml | 138 ++++ tasks/section_3/cis_3.4.2.x.yml | 340 ++++++-- tasks/section_3/cis_3.4.3.1.x.yml | 50 ++ .../{cis_3.4.4.1.x.yml => cis_3.4.3.2.x.yml} | 133 ++-- .../{cis_3.4.4.2.x.yml => cis_3.4.3.3.x.yml} | 133 ++-- tasks/section_3/cis_3.4.3.x.yml | 320 -------- tasks/section_3/cis_3.5.yml | 27 - tasks/section_3/cis_3.6.yml | 17 - tasks/section_4/cis_4.1.1.x.yml | 48 +- tasks/section_4/cis_4.1.2.x.yml | 15 +- tasks/section_4/cis_4.1.3.x.yml | 322 ++++++++ tasks/section_4/cis_4.1.x.yml | 207 ----- tasks/section_4/cis_4.2.1.x.yml | 112 ++- tasks/section_4/cis_4.2.2.x.yml | 189 ++++- tasks/section_4/cis_4.2.3.yml | 8 +- tasks/section_4/cis_4.3.yml | 11 +- tasks/section_4/main.yml | 10 +- tasks/section_5/cis_5.1.x.yml | 88 ++- tasks/section_5/cis_5.2.x.yml | 380 +++++---- tasks/section_5/cis_5.3.x.yml | 182 +++-- tasks/section_5/cis_5.4.x.yml | 168 ++-- tasks/section_5/cis_5.5.1.x.yml | 131 ---- tasks/section_5/cis_5.5.x.yml | 28 +- tasks/section_5/cis_5.6.1.x.yml | 125 +++ tasks/section_5/cis_5.6.x.yml | 108 +++ tasks/section_5/cis_5.6.yml | 37 - tasks/section_5/cis_5.7.yml | 22 - tasks/section_5/main.yml | 21 +- tasks/section_6/cis_6.1.x.yml | 275 ++++--- tasks/section_6/cis_6.2.x.yml | 740 ++++++++---------- tasks/section_6/main.yml | 2 +- templates/audit/99_auditd.rules.j2 | 117 +-- 36 files changed, 2584 insertions(+), 2078 deletions(-) delete mode 100644 tasks/section_3/cis_3.4.1.1.yml create mode 100644 tasks/section_3/cis_3.4.1.x.yml create mode 100644 tasks/section_3/cis_3.4.3.1.x.yml rename tasks/section_3/{cis_3.4.4.1.x.yml => cis_3.4.3.2.x.yml} (51%) rename tasks/section_3/{cis_3.4.4.2.x.yml => cis_3.4.3.3.x.yml} (54%) delete mode 100644 tasks/section_3/cis_3.4.3.x.yml delete mode 100644 tasks/section_3/cis_3.5.yml delete mode 100644 tasks/section_3/cis_3.6.yml create mode 100644 tasks/section_4/cis_4.1.3.x.yml delete mode 100644 tasks/section_4/cis_4.1.x.yml delete mode 100644 tasks/section_5/cis_5.5.1.x.yml create mode 100644 tasks/section_5/cis_5.6.1.x.yml create mode 100644 tasks/section_5/cis_5.6.x.yml delete mode 100644 tasks/section_5/cis_5.6.yml delete mode 100644 tasks/section_5/cis_5.7.yml diff --git a/README.md b/README.md index d629e1f..ea3ead5 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ ![Release](https://img.shields.io/github/v/release/ansible-lockdown/RHEL9-CIS?style=plastic) Configure RHEL 9 machine to be [CIS](https://www.cisecurity.org/cis-benchmarks/) compliant with RHEL8 settings (RHEL9 not yet released) +Based on v2.0.0 RHEL8 Based on [CIS RedHat Enterprise Linux 8 Benchmark v1.0.1 - 05-19-2021 ](https://www.cisecurity.org/cis-benchmarks/) diff --git a/defaults/main.yml b/defaults/main.yml index 2a6bd1b..d2a2372 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -169,49 +169,55 @@ rhel9cis_rule_2_3_5: true rhel9cis_rule_2_3_6: true rhel9cis_rule_2_4: true -# Section 3 rules + Section 3 rules rhel9cis_rule_3_1_1: true rhel9cis_rule_3_1_2: true +rhel9cis_rule_3_1_3: true +rhel9cis_rule_3_1_4: true rhel9cis_rule_3_2_1: true rhel9cis_rule_3_2_2: true -rhel9cis_rule_3_2_3: true -rhel9cis_rule_3_2_4: true -rhel9cis_rule_3_2_5: true -rhel9cis_rule_3_2_6: true -rhel9cis_rule_3_2_7: true -rhel9cis_rule_3_2_8: true -rhel9cis_rule_3_2_9: true rhel9cis_rule_3_3_1: true rhel9cis_rule_3_3_2: true rhel9cis_rule_3_3_3: true rhel9cis_rule_3_3_4: true +rhel9cis_rule_3_3_5: true +rhel9cis_rule_3_3_6: true +rhel9cis_rule_3_3_7: true +rhel9cis_rule_3_3_8: true +rhel9cis_rule_3_3_9: true rhel9cis_rule_3_4_1_1: true +rhel9cis_rule_3_4_1_2: true +rhel9cis_rule_3_4_1_3: true +rhel9cis_rule_3_4_1_4: true +rhel9cis_rule_3_4_1_5: true +rhel9cis_rule_3_4_1_6: true +rhel9cis_rule_3_4_1_7: true rhel9cis_rule_3_4_2_1: true rhel9cis_rule_3_4_2_2: true rhel9cis_rule_3_4_2_3: true rhel9cis_rule_3_4_2_4: true rhel9cis_rule_3_4_2_5: true rhel9cis_rule_3_4_2_6: true -rhel9cis_rule_3_4_3_1: true -rhel9cis_rule_3_4_3_2: true -rhel9cis_rule_3_4_3_3: true -rhel9cis_rule_3_4_3_4: true -rhel9cis_rule_3_4_3_5: true -rhel9cis_rule_3_4_3_6: true -rhel9cis_rule_3_4_3_7: true -rhel9cis_rule_3_4_3_8: true -rhel9cis_rule_3_4_4_1_1: true -rhel9cis_rule_3_4_4_1_2: true -rhel9cis_rule_3_4_4_1_3: true -rhel9cis_rule_3_4_4_1_4: true -rhel9cis_rule_3_4_4_1_5: true -rhel9cis_rule_3_4_4_2_1: true -rhel9cis_rule_3_4_4_2_2: true -rhel9cis_rule_3_4_4_2_3: true -rhel9cis_rule_3_4_4_2_4: true -rhel9cis_rule_3_4_4_2_5: true -rhel9cis_rule_3_5: true -rhel9cis_rule_3_6: true +rhel9cis_rule_3_4_2_7: true +rhel9cis_rule_3_4_2_8: true +rhel9cis_rule_3_4_2_9: true +rhel9cis_rule_3_4_2_10: true +rhel9cis_rule_3_4_2_11: true +rhel9cis_rule_3_4_3_1_1: true +rhel9cis_rule_3_4_3_1_2: true +rhel9cis_rule_3_4_3_1_3: true +rhel9cis_rule_3_4_3_2_1: true +rhel9cis_rule_3_4_3_2_2: true +rhel9cis_rule_3_4_3_2_3: true +rhel9cis_rule_3_4_3_2_4: true +rhel9cis_rule_3_4_3_2_5: true +rhel9cis_rule_3_4_3_2_6: true +rhel9cis_rule_3_4_3_3_1: true +rhel9cis_rule_3_4_3_3_2: true +rhel9cis_rule_3_4_3_3_3: true +rhel9cis_rule_3_4_3_3_4: true +rhel9cis_rule_3_4_3_3_5: true +rhel9cis_rule_3_4_3_3_6: true # Section 4 rules rhel9cis_rule_4_1_1_1: true @@ -221,30 +227,44 @@ rhel9cis_rule_4_1_1_4: true rhel9cis_rule_4_1_2_1: true rhel9cis_rule_4_1_2_2: true rhel9cis_rule_4_1_2_3: true -rhel9cis_rule_4_1_3: true -rhel9cis_rule_4_1_4: true -rhel9cis_rule_4_1_5: true -rhel9cis_rule_4_1_6: true -rhel9cis_rule_4_1_7: true -rhel9cis_rule_4_1_8: true -rhel9cis_rule_4_1_9: true -rhel9cis_rule_4_1_10: true -rhel9cis_rule_4_1_11: true -rhel9cis_rule_4_1_12: true -rhel9cis_rule_4_1_13: true -rhel9cis_rule_4_1_14: true -rhel9cis_rule_4_1_15: true -rhel9cis_rule_4_1_16: true -rhel9cis_rule_4_1_17: true +rhel9cis_rule_4_1_3_1: true +rhel9cis_rule_4_1_3_2: true +rhel9cis_rule_4_1_3_3: true +rhel9cis_rule_4_1_3_4: true +rhel9cis_rule_4_1_3_5: true +rhel9cis_rule_4_1_3_6: true +rhel9cis_rule_4_1_3_7: true +rhel9cis_rule_4_1_3_8: true +rhel9cis_rule_4_1_3_9: true +rhel9cis_rule_4_1_3_10: true +rhel9cis_rule_4_1_3_11: true +rhel9cis_rule_4_1_3_12: true +rhel9cis_rule_4_1_3_13: true +rhel9cis_rule_4_1_3_14: true +rhel9cis_rule_4_1_3_15: true +rhel9cis_rule_4_1_3_16: true +rhel9cis_rule_4_1_3_17: true +rhel9cis_rule_4_1_3_18: true +rhel9cis_rule_4_1_3_19: true +rhel9cis_rule_4_1_3_20: true +rhel9cis_rule_4_1_3_21: true rhel9cis_rule_4_2_1_1: true rhel9cis_rule_4_2_1_2: true rhel9cis_rule_4_2_1_3: true rhel9cis_rule_4_2_1_4: true rhel9cis_rule_4_2_1_5: true rhel9cis_rule_4_2_1_6: true -rhel9cis_rule_4_2_2_1: true +rhel9cis_rule_4_2_1_7: true +rhel9cis_rule_4_2_2_1_1: true +rhel9cis_rule_4_2_2_1_2: true +rhel9cis_rule_4_2_2_1_3: true +rhel9cis_rule_4_2_2_1_4: true rhel9cis_rule_4_2_2_2: true rhel9cis_rule_4_2_2_3: true +rhel9cis_rule_4_2_2_4: true +rhel9cis_rule_4_2_2_5: true +rhel9cis_rule_4_2_2_6: true +rhel9cis_rule_4_2_2_7: true rhel9cis_rule_4_2_3: true rhel9cis_rule_4_3: true @@ -257,6 +277,7 @@ rhel9cis_rule_5_1_5: true rhel9cis_rule_5_1_6: true rhel9cis_rule_5_1_7: true rhel9cis_rule_5_1_8: true +rhel9cis_rule_5_1_9: true rhel9cis_rule_5_2_1: true rhel9cis_rule_5_2_2: true rhel9cis_rule_5_2_3: true @@ -280,21 +301,26 @@ rhel9cis_rule_5_2_20: true rhel9cis_rule_5_3_1: true rhel9cis_rule_5_3_2: true rhel9cis_rule_5_3_3: true +rhel9cis_rule_5_3_4: true +rhel9cis_rule_5_3_5: true +rhel9cis_rule_5_3_6: true +rhel9cis_rule_5_3_7: true rhel9cis_rule_5_4_1: true rhel9cis_rule_5_4_2: true -rhel9cis_rule_5_4_3: true -rhel9cis_rule_5_4_4: true -rhel9cis_rule_5_5_1_1: true -rhel9cis_rule_5_5_1_2: true -rhel9cis_rule_5_5_1_3: true -rhel9cis_rule_5_5_1_4: true -rhel9cis_rule_5_5_1_5: true +rhel9cis_rule_5_5_1: true rhel9cis_rule_5_5_2: true rhel9cis_rule_5_5_3: true rhel9cis_rule_5_5_4: true rhel9cis_rule_5_5_5: true -rhel9cis_rule_5_6: true -rhel9cis_rule_5_7: true +rhel9cis_rule_5_6_1_1: true +rhel9cis_rule_5_6_1_2: true +rhel9cis_rule_5_6_1_3: true +rhel9cis_rule_5_6_1_4: true +rhel9cis_rule_5_6_1_5: true +rhel9cis_rule_5_6_2: true +rhel9cis_rule_5_6_3: true +rhel9cis_rule_5_6_4: true +rhel9cis_rule_5_6_5: true # Section 6 rules rhel9cis_rule_6_1_1: true @@ -311,6 +337,7 @@ rhel9cis_rule_6_1_11: true rhel9cis_rule_6_1_12: true rhel9cis_rule_6_1_13: true rhel9cis_rule_6_1_14: true +rhel9cis_rule_6_1_15: true rhel9cis_rule_6_2_1: true rhel9cis_rule_6_2_2: true rhel9cis_rule_6_2_3: true @@ -327,10 +354,6 @@ rhel9cis_rule_6_2_13: true rhel9cis_rule_6_2_14: true rhel9cis_rule_6_2_15: true rhel9cis_rule_6_2_16: true -rhel9cis_rule_6_2_17: true -rhel9cis_rule_6_2_18: true -rhel9cis_rule_6_2_19: true -rhel9cis_rule_6_2_20: true # Service configuration booleans set true to keep service rhel9cis_avahi_server: false diff --git a/tasks/section_3/cis_3.3.x.yml b/tasks/section_3/cis_3.3.x.yml index 28697f1..7187816 100644 --- a/tasks/section_3/cis_3.3.x.yml +++ b/tasks/section_3/cis_3.3.x.yml @@ -128,16 +128,16 @@ - patch - rule_3.3.8 -- name: "3.3.9 | L2 | PATCH | Ensure IPv6 router advertisements are not accepted" +- name: "3.3.9 | PATCH | Ensure IPv6 router advertisements are not accepted" block: - - name: "3.3.9 | L2 | PATCH | Ensure IPv6 router advertisements are not accepted" + - name: "3.3.9 | PATCH | Ensure IPv6 router advertisements are not accepted" debug: msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/99-sysctl.conf" notify: - update sysctl - sysctl flush ipv4 route table - - name: "3.3.9 | L2 | PATCH | Ensure IPv6 router advertisements are not accepted" + - name: "3.3.9 | PATCH | Ensure IPv6 router advertisements are not accepted" debug: msg: "Control being set via Handler 'update sysctl' which writes to /etc/sysctl.d/99-sysctl.conf" notify: diff --git a/tasks/section_3/cis_3.4.1.1.yml b/tasks/section_3/cis_3.4.1.1.yml deleted file mode 100644 index fc78b06..0000000 --- a/tasks/section_3/cis_3.4.1.1.yml +++ /dev/null @@ -1,14 +0,0 @@ ---- - -- name: "3.4.1.1 | L1 | PATCH | Ensure a Firewall package is installed" - package: - name: "{{ rhel9cis_firewall }}" - state: present - when: - - rhel9cis_rule_3_4_1_1 - - not system_is_container - tags: - - level1-server - - level1-workstation - - patch - - rule_3.4.1.1 diff --git a/tasks/section_3/cis_3.4.1.x.yml b/tasks/section_3/cis_3.4.1.x.yml new file mode 100644 index 0000000..753a4e5 --- /dev/null +++ b/tasks/section_3/cis_3.4.1.x.yml @@ -0,0 +1,138 @@ +--- + +- name: "3.4.1.1 | PATCH | Ensure firewalld is installed" + package: + name: + - firewalld + - iptables + state: present + when: + - rhel9cis_rule_3_4_1_1 + - rhel9cis_firewall == "firewalld" + tags: + - level1-server + - level1-workstation + - automated + - patch + - firewalld + - rule_3.4.1.1 + +- name: "3.4.1.2 | PATCH | Ensure iptables-services not installed with firewalld" + block: + - name: "3.4.1.2 | PATCH | Ensure iptables-services not installed with firewalld | Stop running services" + systemd: + name: "{{ item }}" + enabled: false + masked: true + with_items: + - iptables + - ip6tables + when: item in ansible_facts.packages + + - name: "3.4.1.2 | PATCH | Ensure iptables-services not installed with firewalld | Remove IPTables" + package: + name: iptables-services + state: absent + when: + - rhel9cis_rule_3_4_1_2 + - rhel9cis_firewall == "firewalld" + tags: + - level1-server + - level1-workstation + - automated + - patch + - firewalld + - rule_3.4.1.2 + +- name: "3.4.1.3 | PATCH | Ensure nftables either not installed or masked with firewalld" + systemd: + name: nftables + state: stopped + masked: yes + when: + - rhel9cis_firewall == "firewalld" + - rhel9cis_rule_3_4_1_3 + tags: + - level1-server + - level1-workstation + - automated + - patch + - firewalld + - rule_3_4_1_3 + +- name: "3.4.1.4 | PATCH | Ensure firewalld service is enabled and running" + systemd: + name: firewalld + state: started + enabled: yes + when: + - rhel9cis_firewall == "firewalld" + - rhel9cis_rule_3_4_1_4 + tags: + - level1-server + - level1-workstation + - automated + - patch + - firewalld + - rule_3_4_1_4 + +- name: "3.4.1.5 | PATCH | Ensure firewalld default zone is set" + command: firewall-cmd --set-default-zone="{{ rhel9cis_default_zone }}" + when: + - rhel9cis_firewall == "firewalld" + - rhel9cis_rule_3_4_1_5 + tags: + - level1-server + - level1-workstation + - automated + - patch + - firewalld + - rule_3.4.1.5 + +- name: "3.4.1.6 | AUDIT | Ensure network interfaces are assigned to appropriate zone" + block: + - name: "3.4.1.6 | AUDIT | Ensure network interfaces are assigned to appropriate zone | Get list of interfaces and polocies" + shell: "nmcli -t connection show | awk -F: '{ if($4){print $4} }' | while read INT; do firewall-cmd --get-active-zones | grep -B1 $INT; done" + changed_when: false + failed_when: false + check_mode: no + register: rhel9cis_3_4_1_6_interfacepolicy + + - name: "3.4.1.6 | AUDIT | Ensure network interfaces are assigned to appropriate zone | Get list of interfaces and polocies | Show the interface to policy" + debug: + msg: + - "The items below are the policies tied to the interfaces, please correct as needed" + - "{{ rhel9cis_3_4_1_6_interfacepolicy.stdout_lines }}" + when: + - rhel9cis_firewall == "firewalld" + - rhel9cis_rule_3_4_1_6 + tags: + - level1-server + - level1-workstation + - manual + - audit + - rule_3.4.1.6 + +- name: "3.4.1.7 | AUDIT | Ensure firewalld drops unnecessary services and ports" + block: + - name: "3.4.1.7 | AUDIT | Ensure firewalld drops unnecessary services and ports | Get list of services and ports" + shell: "firewall-cmd --get-active-zones | awk '!/:/ {print $1}' | while read ZN; do firewall-cmd --list-all --zone=$ZN; done" + changed_when: false + failed_when: false + check_mode: no + register: rhel9cis_3_4_1_7_servicesport + + - name: "3.4.1.7 | AUDIT | Ensure firewalld drops unnecessary services and ports | Show services and ports" + debug: + msg: + - "The items below are the services and ports that are accepted, please correct as needed" + - "{{ rhel9cis_3_4_1_7_servicesport.stdout_lines }}" + when: + - rhel9cis_firewall == "firewalld" + - rhel9cis_rule_3_4_1_7 + tags: + - level1-server + - level1-workstation + - manual + - audit + - rule_3.4.1.7 diff --git a/tasks/section_3/cis_3.4.2.x.yml b/tasks/section_3/cis_3.4.2.x.yml index 68b08dc..e5b0c9a 100644 --- a/tasks/section_3/cis_3.4.2.x.yml +++ b/tasks/section_3/cis_3.4.2.x.yml @@ -1,108 +1,344 @@ --- -- name: "3.4.2.1 | L1 | PATCH | Ensure firewalld service is enabled and running" - service: - name: firewalld - state: started - enabled: true +- name: "3.4.2.1 | PATCH | Ensure nftables is installed" + package: + name: nftables + state: present when: - - rhel9cis_firewall == "firewalld" + - rhel9cis_firewall == "nftables" - rhel9cis_rule_3_4_2_1 tags: - level1-server - level1-workstation + - automated - patch - - rule_3_4_2_1 + - nftables + - rule_3.4.2.1 -- name: "3.4.2.2 | L1 | PATCH | Ensure iptables is not enabled with firewalld" - systemd: - name: iptables - masked: true +# The control allows the service it be masked or not installed +# We have chosen not installed +- name: "3.4.2.2 | PATCH | Ensure firewalld is either not installed or masked with nftables" + package: + name: firewalld + state: absent when: - - rhel9cis_firewall == "firewalld" - - "'iptables' in ansible_facts.packages" + - rhel9cis_firewall == "nftables" - rhel9cis_rule_3_4_2_2 tags: - - skip_ansible_lint - level1-server - level1-workstation + - automated - patch - - rule_3_4_2_2 + - nftables + - rule_3.4.2.2 -- name: "3.4.2.3 | L1 | PATCH | Ensure nftables is not enabled with firewalld" - systemd: - name: nftables - enabled: false - masked: true +- name: "3.4.2.3 | PATCH | Ensure iptables-services not installed with nftables" + block: + - name: "3.4.2.3 | PATCH | Ensure iptables-services not installed with nftables | Stop services" + systemd: + name: "{{ item }}" + enabled: false + masked: true + ignore_errors: true + with_items: + - iptables + - ip6tables + + - name: "3.4.2.3 | PATCH | Ensure iptables-services not installed with nftables | Remove IPTables" + package: + name: iptables-service + state: absent when: - - rhel9cis_firewall == "firewalld" - - "'nftables' in ansible_facts.packages" + - rhel9cis_firewall == "nftables" - rhel9cis_rule_3_4_2_3 tags: - level1-server - level1-workstation + - automated - patch - - rule_3_4_2_3 + - nftables + - rule_3.4.2.3 -- name: "3.4.2.4 | L1 | PATCH | Ensure default zone is set" - shell: firewall-cmd --set-default-zone="{{ rhel9cis_default_zone }}" - args: - warn: false +- name: "3.4.2.4 | PATCH | Ensure iptables are flushed with nftables" + block: + - name: "3.4.2.4 | PATCH | Ensure iptables are flushed with nftables | IPv4" + command: iptables -F + + - name: "3.4.2.4 | PATCH | Ensure iptables are flushed with nftables | IPv6" + command: ip6tables -F + when: rhel9cis_ipv6_required when: - - rhel9cis_firewall == "firewalld" - rhel9cis_rule_3_4_2_4 + - rhel9cis_firewall != "firewalld" tags: - level1-server - level1-workstation + - manual - patch + - nftables - rule_3.4.2.4 -- name: "3.4.2.5 | L1 | AUDIT | Ensure network interfaces are assigned to appropriate zone" +- name: "3.4.2.5 | AUDIT | Ensure an nftables table exists" block: - - name: "3.4.2.5 | L1 | AUDIT | Ensure network interfaces are assigned to appropriate zone | Get list of interfaces and polocies" - shell: "nmcli -t connection show | awk -F: '{ if($4){print $4} }' | while read INT; do firewall-cmd --get-active-zones | grep -B1 $INT; done" - args: - warn: false + - name: "3.4.2.5 | AUDIT | Ensure a table exists | Check for tables" + command: nft list tables changed_when: false failed_when: false - check_mode: false - register: rhel9cis_3_4_2_5_interfacepolicy + register: rhel9cis_3_4_2_5_nft_tables - - name: "3.4.2.5 | L1 | AUDIT | Ensure network interfaces are assigned to appropriate zone | Get list of interfaces and polocies | Show the interface to policy" + - name: "3.4.2.5 | AUDIT | Ensure an nftables table exists | Show existing tables" debug: msg: - - "The items below are the policies tied to the interfaces, please correct as needed" - - "{{ rhel9cis_3_4_2_5_interfacepolicy.stdout_lines }}" + - "Below are the current nft tables, please review" + - "{{ rhel9cis_3_4_2_5_nft_tables.stdout_lines }}" + when: rhel9cis_3_4_2_5_nft_tables.stdout | length > 0 + + - name: "3.4.2.5 | AUDIT | Ensure an nftables table exists | Alert on no tables" + debug: + msg: + - "Warning! You currently have no nft tables, please review your setup" + - 'Use the command "nft create table inet " to create a new table' + when: + - rhel9cis_3_4_2_5_nft_tables.stdout | length == 0 + - not rhel9cis_nft_tables_autonewtable + + - name: "3.4.2.5 | PATCH | Ensure a table exists | Create table if needed" + command: nft create table inet "{{ rhel9cis_nft_tables_tablename }}" + failed_when: no + when: rhel9cis_nft_tables_autonewtable when: - - rhel9cis_firewall == "firewalld" + - rhel9cis_firewall == "nftables" - rhel9cis_rule_3_4_2_5 tags: - level1-server - level1-workstation - - audit + - automated + - patch + - nftables - rule_3.4.2.5 -- name: "3.4.2.6 | L1 | AUDIT | Ensure firewalld drops unnecessary services and ports" +- name: "3.4.2.6 | PATCH | Ensure nftables base chains exist" block: - - name: "3.4.2.6 | L1 | AUDIT | Ensure firewalld drops unnecessary services and ports | Get list of services and ports" - shell: "firewall-cmd --get-active-zones | awk '!/:/ {print $1}' | while read ZN; do firewall-cmd --list-all --zone=$ZN; done" - args: - warn: false + - name: "3.4.2.6 | AUDIT | Ensure nftables base chains exist | Get current chains for INPUT" + shell: nft list ruleset | grep 'hook input' changed_when: false failed_when: false - check_mode: false - register: rhel9cis_3_4_2_6_servicesport + register: rhel9cis_3_4_2_6_input_chains - - name: "3.4.2.6 | L1 | AUDIT | Ensure firewalld drops unnecessary services and ports | Show services and ports" + - name: "3.4.2.6 | AUDIT | Ensure nftables base chains exist | Get current chains for FORWARD" + shell: nft list ruleset | grep 'hook forward' + changed_when: false + failed_when: false + register: rhel9cis_3_4_2_6_forward_chains + + - name: "3.4.2.6 | AUDIT | Ensure nftables base chains exist | Get current chains for OUTPUT" + shell: nft list ruleset | grep 'hook output' + changed_when: false + failed_when: false + register: rhel9cis_3_4_2_6_output_chains + + - name: "3.4.2.6 | AUDIT | Ensure nftables base chains exist | Display chains for review" debug: msg: - - "The items below are the services and ports that are accepted, please correct as needed" - - "{{ rhel9cis_3_4_2_6_servicesport.stdout_lines }}" + - "Below are the current INPUT chains" + - "{{ rhel9cis_3_4_2_6_input_chains.stdout_lines }}" + - "Below are the current FORWARD chains" + - "{{ rhel9cis_3_4_2_6_forward_chains.stdout_lines }}" + - "Below are teh current OUTPUT chains" + - "{{ rhel9cis_3_4_2_6_output_chains.stdout_lines }}" + when: not rhel9cis_nft_tables_autochaincreate + + - name: "3.4.2.6 | PATCH | Ensure nftables base chains exist | Create chains if needed" + shell: "{{ item }}" + args: + warn: no + failed_when: no + with_items: + - nft create chain inet "{{ rhel9cis_nft_tables_tablename }}" input { type filter hook input priority 0 \; } + - nft create chain inet "{{ rhel9cis_nft_tables_tablename }}" forward { type filter hook forward priority 0 \; } + - nft create chain inet "{{ rhel9cis_nft_tables_tablename }}" output { type filter hook output priority 0 \; } + when: rhel9cis_nft_tables_autochaincreate when: - - rhel9cis_firewall == "firewalld" + - rhel9cis_firewall == "nftables" - rhel9cis_rule_3_4_2_6 tags: - level1-server - level1-workstation - - audit + - automate + - patch + - nftables - rule_3.4.2.6 + +- name: "3.4.2.7 | PATCH | Ensure nftables loopback traffic is configured" + block: + - name: "3.4.2.7 | AUDIT | Ensure nftables loopback traffic is configured | Gather iif lo accept existence" + shell: nft list ruleset | awk '/hook input/,/}/' | grep 'iif "lo" accept' + changed_when: false + failed_when: false + register: rhel9cis_3_4_2_7_iiflo + + - name: "3.4.2.7 | AUDIT | Ensure nftables loopback traffic is configured | Gather ip saddr existence" + shell: nft list ruleset | awk '/hook input/,/}/' | grep 'ip saddr' + changed_when: false + failed_when: false + register: rhel9cis_3_4_2_7_ipsaddr + + - name: "3.4.2.7 | AUDIT | Ensure nftables loopback traffic is configured | Gather ip6 saddr existence" + shell: nft list ruleset | awk '/hook input/,/}/' | grep 'ip6 saddr' + changed_when: false + failed_when: false + register: rhel9cis_3_4_2_7_ip6saddr + + - name: "3.4.2.7 | PATCH | Ensure nftables loopback traffic is configured | Set iif lo accept rule" + command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input iif lo accept + when: '"iif \"lo\" accept" not in rhel9cis_3_4_2_7_iiflo.stdout' + + - name: "3.4.2.7 | PATCH | Ensure nftables loopback traffic is configured | Set ip sddr rule" + command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip saddr 127.0.0.0/8 counter drop + when: '"ip saddr 127.0.0.0/8 counter packets 0 bytes 0 drop" not in rhel9cis_3_4_2_7_ipsaddr.stdout' + + - name: "3.4.2.7 | PATCH | Ensure nftables loopback traffic is configured | Set ip6 saddr rule" + command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip6 saddr ::1 counter drop + when: '"ip6 saddr ::1 counter packets 0 bytes 0 drop" not in rhel9cis_3_4_2_7_ip6saddr.stdout' + when: + - rhel9cis_firewall == "nftables" + - rhel9cis_rule_3_4_2_7 + tags: + - level1-server + - level1-workstation + - automated + - patch + - nftables + - rule_3.4.2.7 + +- name: "3.4.2.8 | PATCH | Ensure nftables outbound and established connections are configured" + block: + - name: "3.4.2.8 | AUDIT | Ensure nftables outbound and established connections are configured | Gather incoming connection rules" + shell: nft list ruleset | awk '/hook input/,/}/' | grep -E 'ip protocol (tcp|udp|icmp) ct state' + changed_when: false + failed_when: false + register: rhel9cis_3_4_2_8_inconnectionrule + + - name: "3.4.2.8| AUDIT | Ensure nftables outbound and established connections are configured | Gather outbound connection rules" + shell: nft list ruleset | awk '/hook output/,/}/' | grep -E 'ip protocol (tcp|udp|icmp) ct state' + changed_when: false + failed_when: false + register: rhel9cis_3_4_2_8_outconnectionrule + + - name: "3.4.2.8| PATCH | Ensure nftables outbound and established connections are configured | Add input tcp established accept policy" + command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip protocol tcp ct state established accept + when: '"ip protocol tcp ct state established accept" not in rhel9cis_3_4_2_8_inconnectionrule.stdout' + + - name: "3.4.2.8 | PATCH | Ensure nftables outbound and established connections are configured | Add input udp established accept policy" + command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip protocol udp ct state established accept + when: '"ip protocol udp ct state established accept" not in rhel9cis_3_4_2_8_inconnectionrule.stdout' + + - name: "3.4.2.8 | PATCH | Ensure nftables outbound and established connections are configured | Add input icmp established accept policy" + command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip protocol icmp ct state established accept + when: '"ip protocol icmp ct state established accept" not in rhel9cis_3_4_2_8_inconnectionrule.stdout' + + - name: "3.4.2.8 | PATCH | Ensure nftables outbound and established connections are configured | Add output tcp new, related, established accept policy" + command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" output ip protocol tcp ct state new,related,established accept + when: '"ip protocol tcp ct state established,related,new accept" not in rhel9cis_3_4_2_8_outconnectionrule.stdout' + + - name: "3.4.2.8 | PATCH | Ensure nftables outbound and established connections are configured | Add output udp new, related, established accept policy" + command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" output ip protocol udp ct state new,related,established accept + when: '"ip protocol udp ct state established,related,new accept" not in rhel9cis_3_4_2_8_outconnectionrule.stdout' + + - name: "3.4.2.8 | PATCH | Ensure nftables outbound and established connections are configured | Add output icmp new, related, established accept policy" + command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" output ip protocol icmp ct state new,related,established accept + when: '"ip protocol icmp ct state established,related,new accept" not in rhel9cis_3_4_2_8_outconnectionrule.stdout' + when: + - rhel9cis_firewall == "nftables" + - rhel9cis_rule_3_4_2_8 + tags: + - level1-server + - level1-workstation + - automated + - patch + - nftables + - rule_3.4.3.5 + +- name: "3.4.2.9 | PATCH | Ensure nftables default deny firewall policy" + block: + - name: "3.4.2.9 | AUDIT | Ensure nftables default deny firewall policy | Check for hook input deny policy" + shell: nft list table inet "{{ rhel9cis_nft_tables_tablename }}" | grep 'hook input' + failed_when: false + changed_when: false + register: rhel9cis_3_4_2_9_inputpolicy + + - name: "3.4.2.9 | AUDIT | Ensure nftables default deny firewall policy | Check for hook forward deny policy" + shell: nft list table inet "{{ rhel9cis_nft_tables_tablename }}" | grep 'hook forward' + failed_when: false + changed_when: false + register: rhel9cis_3_4_2_9_forwardpolicy + + - name: "3.4.2.9 | AUDIT | Ensure nftables default deny firewall policy | Check for hook output deny policy" + shell: nft list table inet "{{ rhel9cis_nft_tables_tablename }}" | grep 'hook output' + failed_when: false + changed_when: false + register: rhel9cis_3_4_2_9_outputpolicy + + - name: "3.4.2.9 | AUDIT | Ensure nftables default deny firewall policy | Check for SSH allow" + shell: nft list table inet "{{ rhel9cis_nft_tables_tablename }}" | grep 'ssh' + failed_when: false + changed_when: false + register: rhel9cis_3_4_2_9_sshallowcheck + + - name: "3.4.2.9 | PATCH | Ensure nftables default deny firewall policy | Enable SSH traffic" + command: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input tcp dport ssh accept + when: '"tcp dport ssh accept" not in rhel9cis_3_4_2_9_sshallowcheck.stdout' + + - name: "3.4.2.9 | PATCH | Ensure nftables default deny firewall policy | Set hook input deny policy" + command: nft chain inet "{{ rhel9cis_nft_tables_tablename }}" input { policy drop \; } + when: '"type filter hook input priority 0; policy drop;" not in rhel9cis_3_4_2_9_inputpolicy.stdout' + + - name: "3.4.2.9 | PATCH | Ensure nftables default deny firewall policy | Create hook forward deny policy" + command: nft chain inet "{{ rhel9cis_nft_tables_tablename }}" forward { policy drop \; } + when: '"type filter hook forward priority 0; policy drop;" not in rhel9cis_3_4_2_9_forwardpolicy.stdout' + + - name: "3.4.2.9 | PATCH | Ensure nftables default deny firewall policy | Create hook output deny policy" + command: nft chain inet "{{ rhel9cis_nft_tables_tablename }}" output { policy drop \; } + when: '"type filter hook output priority 0; policy drop;" not in rhel9cis_3_4_2_9_outputpolicy.stdout' + when: + - rhel9cis_firewall == "nftables" + - rhel9cis_rule_3_4_2_9 + tags: + - level1-server + - level1-workstation + - automated + - patch + - nftables + - rule_3.4.2.9 + +- name: "3.4.2.10 | PATCH | Ensure nftables service is enabled" + service: + name: nftables + enabled: yes + when: + - rhel9cis_firewall == "nftables" + - rhel9cis_rule_3_4_2_10 + tags: + - level1-server + - level1-workstation + - automated + - patch + - nftables + - rule_3.4.3.7 + +- name: "3.4.2.11 | PATCH | Ensure nftables rules are permanent" + lineinfile: + path: /etc/sysconfig/nftables.conf + state: present + insertafter: EOF + line: include "/etc/nftables/inet-{{ rhel9cis_nft_tables_tablename }}" + when: + - rhel9cis_firewall == "nftables" + - rhel9cis_rule_3_4_2_11 + tags: + - level1-server + - level1-workstation + - automated + - patch + - nftables + - rule_3.4.2.11 diff --git a/tasks/section_3/cis_3.4.3.1.x.yml b/tasks/section_3/cis_3.4.3.1.x.yml new file mode 100644 index 0000000..926c685 --- /dev/null +++ b/tasks/section_3/cis_3.4.3.1.x.yml @@ -0,0 +1,50 @@ +--- + +- name: "3.4.3.1.1 | PATCH | Ensure iptables packages are installed" + package: + name: + - iptables + - iptables-services + state: present + when: + - rhel9cis_firewall == "iptables" + - rhel9cis_rule_3_4_3_1_1 + tags: + - level1-server + - level1-workstation + - automated + - patch + - iptables + - rule_3.4.3.1.1 + +- name: "3.4.3.1.2 | PATCH | Ensure nftables is not installed with iptables" + package: + name: nftables + state: absent + when: + - rhel9cis_firewall == "iptables" + - rhel9cis_rule_3_4_3_1_2 + tags: + - level1-server + - level1-workstation + - automated + - patch + - iptables + - rule_3.4.3.1.2 + +# The control allows the service it be masked or not installed +# We have chosen not installed +- name: "3.4.3.1.3 | PATCH | Ensure firewalld is either not installed or masked with iptables" + package: + name: firewalld + state: absent + when: + - rhel9cis_firewall == "iptables" + - rhel9cis_rule_3_4_3_1_3 + tags: + - level1-server + - level1-workstation + - automated + - patch + - iptables + - rule_3.4.3.1.3 diff --git a/tasks/section_3/cis_3.4.4.1.x.yml b/tasks/section_3/cis_3.4.3.2.x.yml similarity index 51% rename from tasks/section_3/cis_3.4.4.1.x.yml rename to tasks/section_3/cis_3.4.3.2.x.yml index a18e7ef..3348fb5 100644 --- a/tasks/section_3/cis_3.4.4.1.x.yml +++ b/tasks/section_3/cis_3.4.3.2.x.yml @@ -1,48 +1,22 @@ --- -- name: "3.4.4.1.1 | L1 | PATCH | Ensure iptables default deny firewall policy" +- name: "3.4.3.2.1 | PATCH | Ensure iptables loopback traffic is configured" block: - - name: "3.4.4.1.1 | L1 | PATCH | Ensure iptables default deny firewall policy | Configure ssh to be allowed" - iptables: - chain: INPUT - protocol: tcp - destination_port: "22" - jump: ACCEPT - - - name: "3.4.4.1.1 | L1 | PATCH | Ensure iptables default deny firewall policy | Set drop items" - iptables: - policy: DROP - chain: "{{ item }}" - with_items: - - INPUT - - FORWARD - - OUTPUT - when: - - rhel9cis_rule_3_4_4_1_1 - - rhel9cis_firewall == "iptables" - tags: - - level1-server - - level1-workstation - - patch - - rule_3.4.4.1.1 - -- name: "3.4.4.1.2 | L1 | PATCH | Ensure iptables loopback traffic is configured" - block: - - name: "3.4.4.1.2 | L1 | Ensure iptables loopback traffic is configured | INPUT Loopback ACCEPT" + - name: "3.4.3.2.1 | PATCH | Ensure iptables loopback traffic is configured | INPUT Loopback ACCEPT" iptables: action: append chain: INPUT in_interface: lo jump: ACCEPT - - name: "3.4.4.1.2 | L1 | PATCH | Ensure iptables loopback traffic is configured | OUTPUT Loopback ACCEPT" + - name: "3.4.3.2.1 | PATCH | Ensure iptables loopback traffic is configured | OUTPUT Loopback ACCEPT" iptables: action: append chain: OUTPUT out_interface: lo jump: ACCEPT - - name: "3.4.4.1.2 | L1 | PATCH | Ensure iptables loopback traffic is configured | INPUT Loopback 127.0.0.0/8" + - name: "3.4.3.2.1 | PATCH | Ensure iptables loopback traffic is configured | INPUT Loopback 127.0.0.0/8" iptables: action: append chain: INPUT @@ -50,14 +24,16 @@ jump: DROP when: - rhel9cis_firewall == "iptables" - - rhel9cis_rule_3_4_4_1_2 + - rhel9cis_rule_3_4_3_2_1 tags: - level1-server - level1-workstation + - automated - patch - - rule_3.4.4.1.2 + - iptables + - rule_3.4.3.2.1 -- name: "3.4.4.1.3 | L1 | PATCH | Ensure iptables outbound and established connections are configured" +- name: "3.4.3.2.2 | PATCH | Ensure iptables outbound and established connections are configured" iptables: action: append chain: '{{ item.chain }}' @@ -74,32 +50,30 @@ - { chain: INPUT, protocol: icmp, ctstate: ESTABLISHED } when: - rhel9cis_firewall == "iptables" - - rhel9cis_rule_3_4_4_1_3 + - rhel9cis_rule_3_4_3_2_2 tags: - level1-server - level1-workstation + - manual - patch - - rule_3.4.4.1.3 + - iptables + - rule_3.4.3.2.2 -- name: "3.4.4.1.4 | L1 | PATCH | Ensure iptables firewall rules exist for all open ports" +- name: "3.4.3.2.3 | PATCH | Ensure iptables rules exist for all open ports" block: - - name: "3.4.4.1.4 | L1 | AUDIT | Ensure iptables firewall rules exist for all open ports | Get list of TCP open ports" + - name: "3.4.3.2.3 | AUDIT | Ensure iptables rules exist for all open ports | Get list of TCP open ports" shell: netstat -ant |grep "tcp.*LISTEN" | awk '{ print $4 }'| sed 's/.*://' - args: - warn: false changed_when: false failed_when: false - register: rhel9cis_3_4_4_1_4_otcp + register: rhel9cis_3_4_3_2_3_otcp - - name: "3.4.4.1.4 | L1 | AUDIT | Ensure iptables firewall rules exist for all open ports | Get the list of udp open ports" + - name: "3.4.3.2.3 | AUDIT | Ensure iptables rules exist for all open ports | Get the list of udp open ports" shell: netstat -ant |grep "udp.*LISTEN" | awk '{ print $4 }'| sed 's/.*://' - args: - warn: false changed_when: false failed_when: false - register: rhel9cis_3_4_4_1_4_oudp + register: rhel9cis_3_4_3_2_3_oudp - - name: "3.4.4.1.4 | L1 | PATCH | Ensure iptables firewall rules exist for all open ports | Adjust open tcp ports" + - name: "3.4.3.2.3 | PATCH | Ensure iptables rules exist for all open ports | Adjust open tcp ports" iptables: action: append chain: INPUT @@ -109,10 +83,10 @@ ctstate: NEW jump: ACCEPT with_items: - - "{{ rhel9cis_3_4_4_1_4_otcp.stdout_lines }}" - when: rhel9cis_3_4_4_1_4_otcp.stdout is defined + - "{{ rhel9cis_3_4_3_2_3_otcp.stdout_lines }}" + when: rhel9cis_3_4_3_2_3_otcp.stdout is defined - - name: "3.4.4.1.4 | L1 | PATCH | Ensure iptables firewall rules exist for all open ports | Adjust open udp ports" + - name: "3.4.3.2.3 | PATCH | Ensure iptables rules exist for all open ports | Adjust open udp ports" iptables: action: append chain: INPUT @@ -122,27 +96,74 @@ ctstate: NEW jump: ACCEPT with_items: - - "{{ rhel9cis_3_4_4_1_4_oudp.stdout_lines }}" - when: rhel9cis_3_4_4_1_4_otcp.stdout is defined + - "{{ rhel9cis_3_4_3_2_3_oudp.stdout_lines }}" + when: rhel9cis_3_4_3_2_3_otcp.stdout is defined when: - rhel9cis_firewall == "iptables" - - rhel9cis_rule_3_4_4_1_4 + - rhel9cis_rule_3_4_3_2_3 tags: - level1-server - level1-workstation + - automated - patch - - rule_3.4.4.1.4 + - iptables + - rule_3.4.3.2.3 -- name: "3.4.4.1.5 | L1 | PATCH | Ensure iptables service is enabled and active | Check if iptables is enabled" +- name: "3.4.3.2.4 | PATCH | Ensure iptables default deny firewall policy" + block: + - name: "3.4.3.2.4 | PATCH | Ensure iptables default deny firewall policy | Configure ssh to be allowed" + iptables: + chain: INPUT + protocol: tcp + destination_port: "22" + jump: ACCEPT + + - name: "3.4.3.2.4 | PATCH | Ensure iptables default deny firewall policy | Set drop items" + iptables: + policy: DROP + chain: "{{ item }}" + with_items: + - INPUT + - FORWARD + - OUTPUT + when: + - rhel9cis_rule_3_4_3_2_4 + - rhel9cis_firewall == "iptables" + tags: + - level1-server + - level1-workstation + - automated + - patch + - iptables + - rule_3.4.3.2.4 + +- name: "3.4.3.2.5 | PATCH | Ensure iptables rules are saved" + iptables_state: + state: saved + path: /etc/sysconfig/iptables + when: + - rhel9cis_rule_3_4_3_2_5 + - rhel9cis_firewall == "iptables" + tags: + - level1-server + - level1-workstation + - automated + - patch + - iptables + - rule_3.4.3.2.5 + +- name: "3.4.3.2.6 | PATCH | Ensure iptables service is enabled and active" service: name: iptables - enabled: true + enabled: yes state: started when: - rhel9cis_firewall == "iptables" - - rhel9cis_rule_3_4_4_1_5 + - rhel9cis_rule_3_4_3_2_6 tags: - level1-server - level1-workstation + - automated - patch - - rule_3.4.4.1.5 + - iptables + - rule_3.4.3.2.6 diff --git a/tasks/section_3/cis_3.4.4.2.x.yml b/tasks/section_3/cis_3.4.3.3.x.yml similarity index 54% rename from tasks/section_3/cis_3.4.4.2.x.yml rename to tasks/section_3/cis_3.4.3.3.x.yml index be4bf54..f3bcfa1 100644 --- a/tasks/section_3/cis_3.4.4.2.x.yml +++ b/tasks/section_3/cis_3.4.3.3.x.yml @@ -1,37 +1,8 @@ --- -- name: "3.4.4.2.1 | L1 | PATCH | Ensure ip6tables default deny firewall policy" +- name: "3.4.3.3.1 | PATCH | Ensure ip6tables loopback traffic is configured" block: - - name: "3.4.4.2.1 | L1 | Ensure ip6tables default deny firewall policy | Configure ssh to be allowed" - iptables: - chain: INPUT - protocol: tcp - destination_port: "22" - jump: ACCEPT - ip_version: ipv6 - - - name: "3.4.4.2.1 | L1 | PATCH | Ensure ip6tables default deny firewall policy | Set drop items" - iptables: - policy: DROP - chain: "{{ item }}" - ip_version: ipv6 - with_items: - - INPUT - - FORWARD - - OUTPUT - when: - - rhel9cis_firewall == "iptables" - - rhel9cis_rule_3_4_4_2_1 - - rhel9cis_ipv6_required - tags: - - level1-server - - level1-workstation - - patch - - rule_3.4.4.2.1 - -- name: "3.4.4.2.2 | L1 | PATCH | Ensure ip6tables loopback traffic is configured" - block: - - name: "3.4.4.2.2 | L1 | PATCH | Ensure ip6tables loopback traffic is configured | INPUT Loopback ACCEPT" + - name: "3.4.3.3.1 | PATCH | Ensure ip6tables loopback traffic is configured | INPUT Loopback ACCEPT" iptables: action: append chain: INPUT @@ -39,7 +10,7 @@ jump: ACCEPT ip_version: ipv6 - - name: "3.4.4.2.2 | L1 | PATCH | Ensure ip6tables loopback traffic is configured | OUTPUT Loopback ACCEPT" + - name: "3.4.3.3.1 | PATCH | Ensure ip6tables loopback traffic is configured | OUTPUT Loopback ACCEPT" iptables: action: append chain: OUTPUT @@ -47,7 +18,7 @@ jump: ACCEPT ip_version: ipv6 - - name: "3.4.4.2.2 | L1 | PATCH | Ensure ip6tables loopback traffic is configured | INPUT Loopback 127.0.0.0/8" + - name: "3.4.3.3.1 | PATCH | Ensure ip6tables loopback traffic is configured | INPUT Loopback 127.0.0.0/8" iptables: action: append chain: INPUT @@ -56,15 +27,17 @@ ip_version: ipv6 when: - rhel9cis_firewall == "iptables" - - rhel9cis_rule_3_4_4_2_2 + - rhel9cis_rule_3_4_3_3_1 - rhel9cis_ipv6_required tags: - level1-server - level1-workstation + - automated - patch - - rule_3.4.4.2.2 + - ip6tables + - rule_3.4.3.3.1 -- name: "3.4.4.2.3 | L1 | PATCH | Ensure ip6tables outbound and established connections are configured" +- name: "3.4.3.3.2 | PATCH | Ensure ip6tables outbound and established connections are configured" iptables: action: append chain: '{{ item.chain }}' @@ -82,23 +55,25 @@ - { chain: INPUT, protocol: icmp, ctstate: ESTABLISHED } when: - rhel9cis_firewall == "iptables" - - rhel9cis_rule_3_4_4_2_3 + - rhel9cis_rule_3_4_3_3_2 - rhel9cis_ipv6_required tags: - level1-server - level1-workstation + - manual - patch - - rule_3.4.4.2.3 + - ip6tables + - rule_3.4.3.3.2 -- name: "3.4.4.2.4 | L1 | PATCH | Ensure ip6tables firewall rules exist for all open ports" +- name: "3.4.3.3.3 | PATCH | Ensure ip6tables firewall rules exist for all open ports" block: - - name: "3.4.4.2.4 | L1 | AUDIT | Ensure ip6tables firewall rules exist for all open ports | Get list of TCP6 open ports" + - name: "3.4.3.3.3 | AUDIT | Ensure ip6tables firewall rules exist for all open ports | Get list of TCP6 open ports" shell: netstat -ant |grep "tcp6.*LISTEN" | awk '{ print $4 }'| sed 's/.*://' changed_when: false failed_when: false - register: rhel9cis_3_4_4_2_4_otcp + register: rhel9cis_3_4_3_3_3_otcp - - name: "3.4.4.2.4 | L1 | PATCH |Ensure ip6tables firewall rules exist for all open ports| Adjust open tcp6 ports" + - name: "3.4.3.3.3 | PATCH |Ensure ip6tables firewall rules exist for all open ports| Adjust open tcp6 ports" iptables: action: append chain: INPUT @@ -109,28 +84,80 @@ jump: ACCEPT ip_version: ipv6 with_items: - - "{{ rhel9cis_3_4_4_2_4_otcp.stdout_lines }}" - when: rhel9cis_3_4_4_2_4_otcp.stdout is defined + - "{{ rhel9cis_3_4_3_3_3_otcp.stdout_lines }}" + when: rhel9cis_3_4_3_3_3_otcp.stdout is defined when: - rhel9cis_firewall == "iptables" - - rhel9cis_rule_3_4_4_2_4 + - rhel9cis_rule_3_4_3_3_3 - rhel9cis_ipv6_required tags: - level1-server - level1-workstation + - automated - patch - - rule_3.4.4.2.4 + - ip6tables + - rule_3.4.3.3.3 -- name: "3.4.4.2.5 | L1 | PATCH | Ensure ip6tables service is enabled and active | Check if ip6tables is enabled" - service: - name: ip6tables - enabled: true - state: started +- name: "3.4.3.3.4 | PATCH | Ensure ip6tables default deny firewall policy" + block: + - name: "3.4.3.3.4 | PATCH | Ensure ip6tables default deny firewall policy | Configure ssh to be allowed" + iptables: + chain: INPUT + protocol: tcp + destination_port: "22" + jump: ACCEPT + ip_version: ipv6 + + - name: "3.4.3.3.4 | PATCH | Ensure ip6tables default deny firewall policy | Set drop items" + iptables: + policy: DROP + chain: "{{ item }}" + ip_version: ipv6 + with_items: + - INPUT + - FORWARD + - OUTPUT when: - rhel9cis_firewall == "iptables" - - rhel9cis_rule_3_4_4_2_5 + - rhel9cis_rule_3_4_3_3_4 + - rhel9cis_ipv6_required tags: - level1-server - level1-workstation + - automated - patch - - rule_3.4.4.2.5 + - ip6tables + - rule_3.4.3.3.4 + +- name: "3.4.3.3.5 | PATCH | Ensure ip6tables rules are saved" + iptables_state: + state: saved + path: /etc/sysconfig/ip6tables + ip_version: ipv6 + when: + - rhel9cis_firewall == "iptables" + - rhel9cis_ipv6_required + - rhel9cis_rule_3_4_3_3_5 + tags: + - level1-server + - level1-workstation + - automated + - patch + - ip6tables + - rule_3.4.3.3.5 + +- name: "3.4.3.3.6 | PATCH | Ensure ip6tables service is enabled and active" + service: + name: ip6tables + enabled: yes + state: started + when: + - rhel9cis_firewall == "iptables" + - rhel9cis_rule_3_4_3_3_6 + tags: + - level1-server + - level1-workstation + - automated + - patch + - ip6tables + - rule_3.4.3.3.6 diff --git a/tasks/section_3/cis_3.4.3.x.yml b/tasks/section_3/cis_3.4.3.x.yml deleted file mode 100644 index 4212139..0000000 --- a/tasks/section_3/cis_3.4.3.x.yml +++ /dev/null @@ -1,320 +0,0 @@ ---- - -- name: "3.4.3.1 | L1 | PATCH | Ensure iptables are flushed with nftables" - shell: ip6tables -F - args: - warn: false - when: - - rhel9cis_rule_3_4_3_1 - - rhel9cis_firewall != "iptables" - - rhel9cis_ipv6_required - tags: - - level1-server - - level1-workstation - - patch - - rule_3.4.3.1 - -- name: "3.4.3.2 | L1 | AUDIT | Ensure an nftables table exists" - block: - - name: "3.4.3.2 | L1 | AUDIT | Ensure a table exists | Check for tables" - shell: nft list tables - args: - warn: false - changed_when: false - failed_when: false - register: rhel9cis_3_4_3_2_nft_tables - - - name: "3.4.3.2 | L1 | AUDIT | Ensure an nftables table exists | Show existing tables" - debug: - msg: - - "Below are the current nft tables, please review" - - "{{ rhel9cis_3_4_3_2_nft_tables.stdout_lines }}" - when: rhel9cis_3_4_3_2_nft_tables.stdout | length > 0 - - - name: "3.4.3.2 | L1 | AUDIT | Ensure an nftables table exists | Alert on no tables" - debug: - msg: - - "Warning! You currently have no nft tables, please review your setup" - - 'Use the shell "nft create table inet
" to create a new table' - when: - - rhel9cis_3_4_3_2_nft_tables.stdout | length == 0 - - not rhel9cis_nft_tables_autonewtable - - - name: "3.4.3.2 | L1 | PATCH | Ensure a table exists | Create table if needed" - shell: nft create table inet "{{ rhel9cis_nft_tables_tablename }}" - args: - warn: false - failed_when: false - when: rhel9cis_nft_tables_autonewtable - when: - - rhel9cis_firewall == "nftables" - - rhel9cis_rule_3_4_3_2 - tags: - - level1-server - - level1-workstation - - patch - - rule_3.4.3.2 - -- name: "3.4.3.3 | L1 | PATCH | Ensure nftables base chains exist" - block: - - name: "3.4.3.3 | L1 | Ensure nftables base chains exist | Get current chains for INPUT" - shell: nft list ruleset | grep 'hook input' - args: - warn: false - changed_when: false - failed_when: false - register: rhel9cis_3_4_3_3_input_chains - - - name: "3.4.3.3 | L1 | AUDIT | Ensure nftables base chains exist | Get current chains for FORWARD" - shell: nft list ruleset | grep 'hook forward' - args: - warn: false - changed_when: false - failed_when: false - register: rhel9cis_3_4_3_3_forward_chains - - - name: "3.4.3.3 | L1 | AUDIT | Ensure nftables base chains exist | Get current chains for OUTPUT" - shell: nft list ruleset | grep 'hook output' - args: - warn: false - changed_when: false - failed_when: false - register: rhel9cis_3_4_3_3_output_chains - - - name: "3.4.3.3 | L1 | AUDIT | Ensure nftables base chains exist | Display chains for review" - debug: - msg: - - "Below are the current INPUT chains" - - "{{ rhel9cis_3_4_3_3_input_chains.stdout_lines }}" - - "Below are the current FORWARD chains" - - "{{ rhel9cis_3_4_3_3_forward_chains.stdout_lines }}" - - "Below are teh current OUTPUT chains" - - "{{ rhel9cis_3_4_3_3_output_chains.stdout_lines }}" - when: not rhel9cis_nft_tables_autochaincreate - - - name: "3.4.3.3 | L1 | PATCH | Ensure nftables base chains exist | Create chains if needed" - shell: "{{ item }}" - args: - warn: false - failed_when: false - with_items: - - nft create chain inet "{{ rhel9cis_nft_tables_tablename }}" input { type filter hook input priority 0 \; } - - nft create chain inet "{{ rhel9cis_nft_tables_tablename }}" forward { type filter hook forward priority 0 \; } - - nft create chain inet "{{ rhel9cis_nft_tables_tablename }}" output { type filter hook output priority 0 \; } - when: rhel9cis_nft_tables_autochaincreate - when: - - rhel9cis_firewall == "nftables" - - rhel9cis_rule_3_4_3_3 - tags: - - level1-server - - level1-workstation - - patch - - rule_3.4.3.3 - -- name: "3.4.3.4 | L1 | PATCH | Ensure nftables loopback traffic is configured" - block: - - name: "3.4.3.4 | L1 | AUDIT | Ensure nftables loopback traffic is configured | Gather iif lo accept existence" - shell: nft list ruleset | awk '/hook input/,/}/' | grep 'iif "lo" accept' - args: - warn: false - changed_when: false - failed_when: false - register: rhel9cis_3_4_3_4_iiflo - - - name: "3.4.3.4 | L1 | AUDIT | Ensure nftables loopback traffic is configured | Gather ip saddr existence" - shell: nft list ruleset | awk '/hook input/,/}/' | grep 'ip saddr' - args: - warn: false - changed_when: false - failed_when: false - register: rhel9cis_3_4_3_4_ipsaddr - - - name: "3.4.3.4 | L1 | AUDIT | Ensure nftables loopback traffic is configured | Gather ip6 saddr existence" - shell: nft list ruleset | awk '/hook input/,/}/' | grep 'ip6 saddr' - args: - warn: false - changed_when: false - failed_when: false - register: rhel9cis_3_4_3_4_ip6saddr - - - name: "3.4.3.4 | L1 | PATCH | Ensure nftables loopback traffic is configured | Set iif lo accept rule" - shell: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input iif lo accept - args: - warn: false - when: '"iif \"lo\" accept" not in rhel9cis_3_4_3_4_iiflo.stdout' - - - name: "3.4.3.4 | L1 | PATCH | Ensure nftables loopback traffic is configured | Set ip sddr rule" - shell: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip saddr 127.0.0.0/8 counter drop - args: - warn: false - when: '"ip saddr 127.0.0.0/8 counter packets 0 bytes 0 drop" not in rhel9cis_3_4_3_4_ipsaddr.stdout' - - - name: "3.4.3.4 | L1 | PATCH | Ensure nftables loopback traffic is configured | Set ip6 saddr rule" - shell: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip6 saddr ::1 counter drop - args: - warn: false - when: '"ip6 saddr ::1 counter packets 0 bytes 0 drop" not in rhel9cis_3_4_3_4_ip6saddr.stdout' - when: - - rhel9cis_firewall == "nftables" - - rhel9cis_rule_3_4_3_4 - tags: - - level1-server - - level1-workstation - - patch - - rule_3.4.3.4 - -- name: "3.4.3.5 | L1 | PATCH | Ensure nftables outbound and established connections are configured" - block: - - name: "3.4.3.5 | L1 | AUDIT | Ensure nftables outbound and established connections are configured | Gather incoming connection rules" - shell: nft list ruleset | awk '/hook input/,/}/' | grep -E 'ip protocol (tcp|udp|icmp) ct state' - args: - warn: false - changed_when: false - failed_when: false - register: rhel9cis_3_4_3_5_inconnectionrule - - - name: "3.4.3.5 | L1 | AUDIT | Ensure nftables outbound and established connections are configured | Gather outbound connection rules" - shell: nft list ruleset | awk '/hook output/,/}/' | grep -E 'ip protocol (tcp|udp|icmp) ct state' - args: - warn: false - changed_when: false - failed_when: false - register: rhel9cis_3_4_3_5_outconnectionrule - - - name: "3.4.3.5 | L1 | PATCH | Ensure nftables outbound and established connections are configured | Add input tcp established accept policy" - shell: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip protocol tcp ct state established accept - args: - warn: false - when: '"ip protocol tcp ct state established accept" not in rhel9cis_3_4_3_5_inconnectionrule.stdout' - - - name: "3.4.3.5 | L1 | PATCH | Ensure nftables outbound and established connections are configured | Add input udp established accept policy" - shell: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip protocol udp ct state established accept - args: - warn: false - when: '"ip protocol udp ct state established accept" not in rhel9cis_3_4_3_5_inconnectionrule.stdout' - - - name: "3.4.3.5 | L1 | PATCH | Ensure nftables outbound and established connections are configured | Add input icmp established accept policy" - shell: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input ip protocol icmp ct state established accept - args: - warn: false - when: '"ip protocol icmp ct state established accept" not in rhel9cis_3_4_3_5_inconnectionrule.stdout' - - - name: "3.4.3.5 | L1 | PATCH | Ensure nftables outbound and established connections are configured | Add output tcp new, related, established accept policy" - shell: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" output ip protocol tcp ct state new,related,established accept - args: - warn: false - when: '"ip protocol tcp ct state established,related,new accept" not in rhel9cis_3_4_3_5_outconnectionrule.stdout' - - - name: "3.4.3.5 | L1 | PATCH | Ensure nftables outbound and established connections are configured | Add output udp new, related, established accept policy" - shell: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" output ip protocol udp ct state new,related,established accept - args: - warn: false - when: '"ip protocol udp ct state established,related,new accept" not in rhel9cis_3_4_3_5_outconnectionrule.stdout' - - - name: "3.4.3.5 | L1 | PATCH | Ensure nftables outbound and established connections are configured | Add output icmp new, related, established accept policy" - shell: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" output ip protocol icmp ct state new,related,established accept - args: - warn: false - when: '"ip protocol icmp ct state established,related,new accept" not in rhel9cis_3_4_3_5_outconnectionrule.stdout' - when: - - rhel9cis_firewall == "nftables" - - rhel9cis_rule_3_4_3_5 - tags: - - level1-server - - level1-workstation - - patch - - rule_3.4.3.5 - -- name: "3.4.3.6 | L1 | PATCH | Ensure nftables default deny firewall policy" - block: - - name: "3.4.3.6 | L1 | AUDIT | Ensure nftables default deny firewall policy | Check for hook input deny policy" - shell: nft list table inet "{{ rhel9cis_nft_tables_tablename }}" | grep 'hook input' - args: - warn: false - failed_when: false - changed_when: false - register: rhel9cis_3_4_3_6_inputpolicy - - - name: "3.4.3.6 | L1 | AUDIT | Ensure nftables default deny firewall policy | Check for hook forward deny policy" - shell: nft list table inet "{{ rhel9cis_nft_tables_tablename }}" | grep 'hook forward' - args: - warn: false - failed_when: false - changed_when: false - register: rhel9cis_3_4_3_6_forwardpolicy - - - name: "3.4.3.6 | L1 | AUDIT | Ensure nftables default deny firewall policy | Check for hook output deny policy" - shell: nft list table inet "{{ rhel9cis_nft_tables_tablename }}" | grep 'hook output' - args: - warn: false - failed_when: false - changed_when: false - register: rhel9cis_3_4_3_6_outputpolicy - - - name: "3.4.3.6 | L1 | AUDIT | Ensure nftables default deny firewall policy | Check for SSH allow" - shell: nft list table inet "{{ rhel9cis_nft_tables_tablename }}" | grep 'ssh' - args: - warn: false - failed_when: false - changed_when: false - register: rhel9cis_3_4_3_6_sshallowcheck - - - name: "3.4.3.6 | L1 | PATCH | Ensure nftables default deny firewall policy | Enable SSH traffic" - shell: nft add rule inet "{{ rhel9cis_nft_tables_tablename }}" input tcp dport ssh accept - args: - warn: false - when: '"tcp dport ssh accept" not in rhel9cis_3_4_3_6_sshallowcheck.stdout' - - - name: "3.4.3.6 | L1 | PATCH | Ensure nftables default deny firewall policy | Set hook input deny policy" - shell: nft chain inet "{{ rhel9cis_nft_tables_tablename }}" input { policy drop \; } - args: - warn: false - when: '"type filter hook input priority 0; policy drop;" not in rhel9cis_3_4_3_6_inputpolicy.stdout' - - - name: "3.4.3.6 | L1 | PATCH | Ensure nftables default deny firewall policy | Create hook forward deny policy" - shell: nft chain inet "{{ rhel9cis_nft_tables_tablename }}" forward { policy drop \; } - args: - warn: false - when: '"type filter hook forward priority 0; policy drop;" not in rhel9cis_3_4_3_6_forwardpolicy.stdout' - - - name: "3.4.3.6 | L1 | PATCH | Ensure nftables default deny firewall policy | Create hook output deny policy" - shell: nft chain inet "{{ rhel9cis_nft_tables_tablename }}" output { policy drop \; } - args: - warn: false - when: '"type filter hook output priority 0; policy drop;" not in rhel9cis_3_4_3_6_outputpolicy.stdout' - when: - - rhel9cis_firewall == "nftables" - - rhel9cis_rule_3_4_3_6 - tags: - - level1-server - - level1-workstation - - patch - - rule_3.4.3.6 - -- name: "3.4.3.7 | L1 | PATCH | Ensure nftables service is enabled | Check if nftables is enabled" - service: - name: nftables - enabled: true - when: - - rhel9cis_firewall == "nftables" - - rhel9cis_rule_3_4_3_7 - tags: - - level1-server - - level1-workstation - - patch - - rule_3.4.3.7 - -- name: "3.4.3.8 | L1 | PATCH | Ensure nftables rules are permanent" - lineinfile: - path: /etc/sysconfig/nftables.conf - state: present - insertafter: EOF - line: include "/etc/nftables/inet-{{ rhel9cis_nft_tables_tablename }}" - when: - - rhel9cis_firewall == "nftables" - - rhel9cis_rule_3_4_3_8 - tags: - - level1-server - - level1-workstation - - patch - - rule_3.4.3.8 diff --git a/tasks/section_3/cis_3.5.yml b/tasks/section_3/cis_3.5.yml deleted file mode 100644 index abe73d5..0000000 --- a/tasks/section_3/cis_3.5.yml +++ /dev/null @@ -1,27 +0,0 @@ ---- - -- name: "3.5 | L1 | PATCH | Ensure wireless interfaces are disabled" - block: - - name: "3.5 | L1 | AUDIT | Ensure wireless interfaces are disabled | Check if wifi is enabled" - shell: nmcli radio wifi - args: - warn: false - register: rhel_09_wifi_enabled - changed_when: rhel_09_wifi_enabled.stdout != "disabled" - failed_when: false - - - name: "3.5 | L1 | PATCH | Ensure wireless interfaces are disabled | Disable wifi if enabled" - shell: nmcli radio all off - args: - warn: false - changed_when: false - failed_when: false - when: rhel_09_wifi_enabled is changed - when: - - '"NetworkManager" in ansible_facts.packages' - - rhel9cis_rule_3_5 - tags: - - level1-server - - level2-workstation - - patch - - rule_3.5 diff --git a/tasks/section_3/cis_3.6.yml b/tasks/section_3/cis_3.6.yml deleted file mode 100644 index 4fa1ae5..0000000 --- a/tasks/section_3/cis_3.6.yml +++ /dev/null @@ -1,17 +0,0 @@ ---- - -- name: "3.6 | L2 | PATCH | Disable IPv6" - replace: - dest: /etc/default/grub - regexp: '(^GRUB_CMDLINE_LINUX\s*\=\s*)(?:")(.+)(?/dev/null; done + changed_when: false + failed_when: false + check_mode: no + register: priv_procs + + - name: "4.1.3.6 | PATCH | Ensure use of privileged commands is collected" + debug: + msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" + changed_when: true + notify: update auditd + when: + - rhel9cis_rule_4_1_3_6 + tags: + - level2-server + - level2-workstation + - automated + - patch + - auditd + - rule_4.1.3.6 + +- name: "4.1.3.7 | PATCH | Ensure unsuccessful unauthorized file access attempts are collected" + debug: + msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" + changed_when: true + notify: update auditd + when: + - rhel9cis_rule_4_1_3_7 + tags: + - level2-server + - level2-workstation + - automated + - patch + - auditd + - rule_4.1.3_7 + +- name: "4.1.3.8 | PATCH | Ensure events that modify user/group information are collected" + debug: + msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" + changed_when: true + notify: update auditd + when: + - rhel9cis_rule_4_1_3_8 + tags: + - level2-server + - level2-workstation + - autoamted + - patch + - auditd + - rule_4.1.3.8 + +- name: "4.1.3.9 | PATCH | Ensure discretionary access control permission modification events are collected" + debug: + msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" + changed_when: true + notify: update auditd + when: + - rhel9cis_rule_4_1_3_9 + tags: + - level2-server + - level2-workstation + - automated + - patch + - auditd + - rule_4.1.3.9 + +- name: "4.1.3.10 | PATCH | Ensure successful file system mounts are collected" + debug: + msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" + changed_when: true + notify: update auditd + when: + - rhel9cis_rule_4_1_3_10 + tags: + - level2-server + - level2-workstation + - automated + - patch + - auditd + - rule_4.1.3.10 + +- name: "4.1.3.11 | PATCH | Ensure session initiation information is collected" + debug: + msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" + changed_when: true + notify: update auditd + when: + - rhel9cis_rule_4_1_3_11 + tags: + - level2-server + - level2-workstation + - automated + - patch + - auditd + - rule_4.1.3.11 + +- name: "4.1.3.12 | PATCH | Ensure login and logout events are collected" + debug: + msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" + changed_when: true + notify: update auditd + when: + - rhel9cis_rule_4_1_3_12 + tags: + - level2-server + - level2-workstation + - automated + - patch + - auditd + - rule_4.1.3.12 + +- name: "4.1.3.13 | PATCH | Ensure file deletion events by users are collected" + debug: + msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" + changed_when: true + notify: update auditd + when: + - rhel9cis_rule_4_1_3_13 + tags: + - level2-server + - level2-workstation + - auditd + - patch + - rule_4.1.3.13 + +- name: "4.1.3.14 | PATCH | Ensure events that modify the system's Mandatory Access Controls are collected" + debug: + msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" + changed_when: true + notify: update auditd + when: + - rhel9cis_rule_4_1_3_14 + tags: + - level2-server + - level2-workstation + - automated + - patch + - auditd + - rule_4.1.3.14 + +- name: "4.1.3.15 | PATCH | Ensure successful and unsuccessful attempts to use the chcon command are recorded" + debug: + msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" + changed_when: true + notify: update auditd + when: + - rhel9cis_rule_4_1_3_15 + tags: + - level2-server + - level2- workstation + - automated + - patch + - auditd + - rule_4.1.3.15 + +- name: "4.1.3.16 | PATCH | Ensure successful and unsuccessful attempts to use the setfacl command are recorded" + debug: + msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" + changed_when: true + notify: update auditd + when: + - rhel9cis_rule_4_1_3_16 + tags: + - level2-server + - level2-workstation + - automated + - patch + - auditd + - rule_4.1.3.16 + +- name: "4.1.3.17 | PATCH | Ensure successful and unsuccessful attempts to use the chacl command are recorded" + debug: + msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" + changed_when: true + notify: update auditd + when: + - rhel9cis_rule_4_1_3_17 + tags: + - level2-server + - level2-workstation + - automated + - patch + - auditd + - rule_4.1.3.17 + +- name: "4.1.3.18 | PATCH | Ensure successful and unsuccessful attempts to use the usermod command are recorded" + debug: + msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" + changed_when: true + notify: update auditd + when: + - rhel9cis_rule_4_1_3_18 + tags: + - level2-server + - level2-workstation + - automated + - patch + - auditd + - rule_4.1.3.18 + +- name: "4.1.3.19 | PATCH | Ensure kernel module loading and unloading is collected" + debug: + msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" + changed_when: true + notify: update auditd + when: + - rhel9cis_rule_4_1_3_19 + tags: + - level2-server + - level2-workstation + - automated + - patch + - auditd + - rule_4.1.3.19 + +- name: "4.1.3.20 | PATCH | Ensure the audit configuration is immutable" + debug: + msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" + changed_when: true + notify: update auditd + when: + - rhel9cis_rule_4_1_3_20 + tags: + - level2-server + - level2-workstation + - automated + - patch + - auditd + - rule_4.1.20 + +- name: "4.1.3.21 | AUDIT | Ensure the running and on disk configuration is the same" + debug: + msg: + - "Please run augenrules --load if you suspect there is a configuration that is not active" + when: + - rhel9cis_rule_4_1_3_21 + tags: + - level2-server + - level2-workstation + - manual + - patch + - auditd + - rule_4.1.3.21 diff --git a/tasks/section_4/cis_4.1.x.yml b/tasks/section_4/cis_4.1.x.yml deleted file mode 100644 index ba14ec0..0000000 --- a/tasks/section_4/cis_4.1.x.yml +++ /dev/null @@ -1,207 +0,0 @@ ---- - -- name: "4.1.3 | L2 | PATCH | Ensure changes to system administration scope (sudoers) is collected" - debug: - msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" - notify: update auditd - when: - - rhel9cis_rule_4_1_3 - tags: - - level2-server - - level2-workstation - - auditd - - patch - - rule_4.1.3 - -- name: "4.1.4 | L2 | PATCH | Ensure login and logout events are collected" - debug: - msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" - notify: update auditd - when: - - rhel9cis_rule_4_1_4 - tags: - - level2-server - - level2-workstation - - auditd - - patch - - rule_4.1.4 - -- name: "4.1.5 | L2 | PATCH | Ensure session initiation information is collected" - debug: - msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" - notify: update auditd - when: - - rhel9cis_rule_4_1_5 - tags: - - level2-server - - level2-workstation - - auditd - - patch - - rule_4.1.5 - -- name: "4.1.6 | L2 | PATCH | Ensure events that modify date and time information are collected" - debug: - msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" - notify: update auditd - when: - - rhel9cis_rule_4_1_6 - tags: - - level2-server - - level2-workstation - - auditd - - patch - - rule_4.1.6 - -- name: "4.1.7 | L2 | PATCH | Ensure events that modify the system's Mandatory Access Controls are collected" - debug: - msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" - notify: update auditd - when: - - rhel9cis_rule_4_1_7 - tags: - - level2-server - - level2-workstation - - auditd - - patch - - rule_4.1.7 - -- name: "4.1.8 | L2 | PATCH | Ensure events that modify the system's network environment are collected" - debug: - msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" - notify: update auditd - when: - - rhel9cis_rule_4_1_8 - tags: - - level2-server - - level2-workstation - - auditd - - patch - - rule_4.1.8 - -- name: "4.1.9 | L2 | PATCH | Ensure discretionary access control permission modification events are collected" - debug: - msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" - notify: update auditd - when: - - rhel9cis_rule_4_1_9 - tags: - - level2-server - - level2-workstation - - auditd - - patch - - rule_4.1.9 - -- name: "4.1.10 | L2 | PATCH | Ensure unsuccessful unauthorized file access attempts are collected" - debug: - msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" - notify: update auditd - when: - - rhel9cis_rule_4_1_10 - tags: - - level2-server - - level2-workstation - - auditd - - patch - - rule_4.1.10 - -- name: "4.1.11 | L2 | PATCH | Ensure events that modify user/group information are collected" - debug: - msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" - notify: update auditd - when: - - rhel9cis_rule_4_1_11 - tags: - - level2-server - - level2-workstation - - auditd - - patch - - rule_4.1.11 - -- name: "4.1.12 | L2 | PATCH | Ensure successful file system mounts are collected" - block: - - name: "4.1.12 | L2 | AUDIT | Ensure successful file system mounts are collected" - shell: for i in $(df | grep '^/dev' | awk '{ print $NF }'); do find $i -xdev -type f -perm -4000 -o -type f -perm -2000 2>/dev/null; done - args: - warn: false - changed_when: false - failed_when: false - check_mode: false - register: priv_procs - - - name: "4.1.12 | L2 | PATCH | Ensure successful file system mounts are collected" - debug: - msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" - notify: update auditd - when: - - rhel9cis_rule_4_1_12 - tags: - - level2-server - - level2-workstation - - auditd - - patch - - rule_4.1.12 - -- name: "4.1.13 | L2 | PATCH | Ensure use of privileged commands is collected" - debug: - msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" - notify: update auditd - when: - - rhel9cis_rule_4_1_13 - tags: - - level2-server - - level2-workstation - - auditd - - patch - - rule_4.1.13 - -- name: "4.1.14 | L2 | PATCH | Ensure file deletion events by users are collected" - debug: - msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" - notify: update auditd - when: - - rhel9cis_rule_4_1_14 - tags: - - level2-server - - level2-workstation - - auditd - - patch - - rule_4.1.14 - -- name: "4.1.15 | L2 | PATCH | Ensure kernel module loading and unloading is collected" - debug: - msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" - notify: update auditd - when: - - rhel9cis_rule_4_1_15 - tags: - - level2-server - - level2-workstation - - auditd - - patch - - rule_4.1.15 - -- name: "4.1.16 | L2 | PATCH | Ensure system administrator actions (sudolog) are collected" - debug: - msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" - notify: update auditd - when: - - rhel9cis_rule_4_1_16 - tags: - - level2-server - - level2-workstation - - auditd - - patch - - rule_4.1.16 - -- name: "4.1.17 | L2 | PATCH | Ensure the audit configuration is immutable" - debug: - msg: "Control being set via Handler 'update auditd' which writes to /etc/audit.d/99_auditd.rules" - notify: update auditd - when: - - rhel9cis_rule_4_1_17 - tags: - - level2-server - - level2-workstation - - auditd - - patch - - rule_4.1.17 diff --git a/tasks/section_4/cis_4.2.1.x.yml b/tasks/section_4/cis_4.2.1.x.yml index dd9cdce..0d9d0ee 100644 --- a/tasks/section_4/cis_4.2.1.x.yml +++ b/tasks/section_4/cis_4.2.1.x.yml @@ -1,6 +1,6 @@ --- -- name: "4.2.1.1 | L1 | PATCH | Ensure rsyslog installed" +- name: "4.2.1.1 | PATCH | Ensure rsyslog installed" package: name: rsyslog state: present @@ -10,55 +10,74 @@ tags: - level1-server - level1-workstation + - automated - patch + - rsyslog - rule_4.2.1.1 -- name: "4.2.1.2 | L1 | PATCH | Ensure rsyslog Service is enabled" +- name: "4.2.1.2 | PATCH | Ensure rsyslog Service is enabled" service: name: rsyslog - enabled: true + enabled: yes when: - rhel9cis_rule_4_2_1_2 tags: - level1-server - level1-workstation + - autoamted - patch - rsyslog - rule_4.2.1.2 -- name: "4.2.1.3 | L1 | PATCH | Ensure rsyslog default file permissions configured" +# This is counter to control 4.2.1.5?? +- name: "4.2.1.3 | PATCH | Ensure journald is configured to send logs to rsyslog" + lineinfile: + dest: /etc/systemd/journald.conf + regexp: "^#ForwardToSyslog=|^ForwardToSyslog=" + line: ForwardToSyslog=yes + state: present + when: + - rhel9cis_rule_4_2_1_3 + tags: + - level1-server + - level1-workstation + - manual + - patch + - rule_4.2.1.3 + +- name: "4.2.1.4 | PATCH | Ensure rsyslog default file permissions configured" lineinfile: dest: /etc/rsyslog.conf regexp: '^\$FileCreateMode' line: '$FileCreateMode 0640' notify: restart rsyslog when: - - rhel9cis_rule_4_2_1_3 + - rhel9cis_rule_4_2_1_4 tags: - level1-server - level1-workstation + - automated - patch - - rule_4.2.1.3 + - rsyslog + - rule_4.2.1.4 -- name: "4.2.1.4 | L1 | PATCH | Ensure logging is configured" +- name: "4.2.1.5 | PATCH | Ensure logging is configured" block: - - name: "4.2.1.4 | L1 | AUDIT | Ensure logging is configured | rsyslog current config message out" - shell: cat /etc/rsyslog.conf - args: - warn: false - become: true + - name: "4.2.1.5 | AUDIT | Ensure logging is configured | rsyslog current config message out" + command: cat /etc/rsyslog.conf + become: yes changed_when: false - failed_when: false - check_mode: false - register: rhel_09_4_2_1_4_audit + failed_when: no + check_mode: no + register: rhel_08_4_2_1_5_audit - - name: "4.2.1.4 | L1 | AUDIT | Ensure logging is configured | rsyslog current config message out" + - name: "4.2.1.5 | AUDIT | Ensure logging is configured | rsyslog current config message out" debug: msg: - "These are the current logging configurations for rsyslog, please review:" - - "{{ rhel_09_4_2_1_4_audit.stdout_lines }}" + - "{{ rhel_08_4_2_1_5_audit.stdout_lines }}" - - name: "4.2.1.4 | L1 | PATCH | Ensure logging is configured | mail.* log setting" + - name: "4.2.1.5 | PATCH | Ensure logging is configured | mail.* log setting" blockinfile: path: /etc/rsyslog.conf state: present @@ -73,7 +92,7 @@ notify: restart rsyslog when: rhel9cis_rsyslog_ansiblemanaged - - name: "4.2.1.4 | L1 | PATCH | Ensure logging is configured | news.crit log setting" + - name: "4.2.1.5 | PATCH | Ensure logging is configured | news.crit log setting" blockinfile: path: /etc/rsyslog.conf state: present @@ -86,7 +105,7 @@ notify: restart rsyslog when: rhel9cis_rsyslog_ansiblemanaged - - name: "4.2.1.4 | L1 | PATCH | Ensure logging is configured | Misc. log setting" + - name: "4.2.1.5 | PATCH | Ensure logging is configured | Misc. log setting" blockinfile: path: /etc/rsyslog.conf state: present @@ -100,13 +119,13 @@ notify: restart rsyslog when: rhel9cis_rsyslog_ansiblemanaged - - name: "4.2.1.4 | L1 | PATCH | Ensure logging is configured | Local log settings" + - name: "4.2.1.5 | PATCH | Ensure logging is configured | Local log settings" blockinfile: path: /etc/rsyslog.conf state: present marker: "#{mark} LOCAL LOG SETTINGS (ANSIBLE MANAGED)" block: | - # local log settings + # local log settings to meet CIS standards local0,local1.* -/var/log/localmessages local2,local3.* -/var/log/localmessages local4,local5.* -/var/log/localmessages @@ -114,16 +133,39 @@ *.emrg :omusrmsg:* insertafter: '#### RULES ####' notify: restart rsyslog + + - name: "4.2.1.5 | PATCH | Ensure logging is configured | Auth Settings" + blockinfile: + path: /etc/rsyslog.conf + state: present + marker: "#{mark} Auth SETTINGS (ANSIBLE MANAGED)" + block: | + # Private settings to meet CIS standards + auth,authpriv.* -/var/log/secure + insertafter: '#### RULES ####' + notify: restart rsyslog + + - name: "4.2.1.5 | PATCH | Ensure logging is configured | Cron Settings" + blockinfile: + path: /etc/rsyslog.conf + state: present + marker: "#{mark} Auth SETTINGS (ANSIBLE MANAGED)" + block: | + # Cron settings to meet CIS standards + cron.* /var/log/cron + insertafter: '#### RULES ####' + notify: restart rsyslog when: - - rhel9cis_rule_4_2_1_4 + - rhel9cis_rule_4_2_1_5 tags: - level1-server - level1-workstation + - manual - patch - rsyslog - - rule_4.2.1.4 + - rule_4.2.1.5 -- name: "4.2.1.5 | L1 | PATCH | Ensure rsyslog is configured to send logs to a remote log host" +- name: "4.2.1.6 | PATCH | Ensure rsyslog is configured to send logs to a remote log host" blockinfile: path: /etc/rsyslog.conf state: present @@ -137,18 +179,19 @@ - result.rc != 257 notify: restart rsyslog when: - - rhel9cis_rule_4_2_1_5 + - rhel9cis_rule_4_2_1_6 - rhel9cis_remote_log_server is defined tags: - level1-server - level1-workstation + - manual - patch - - rule_4.2.1.5 - rsyslog + - rule_4.2.1.6 -- name: "4.2.1.6 | L1 | PATCH | Ensure remote rsyslog messages are only accepted on designated log hosts." +- name: "4.2.1.7 | PATCH | Ensure rsyslog is not configured to recieve logs from a remote client" block: - - name: "4.2.1.6 | L1 | PATCH | Ensure remote rsyslog messages are only accepted on designated log hosts. | When not log host" + - name: "4.2.1.7 | PATCH | Ensure rsyslog is not configured to recieve logs from a remote client. | When not log host" replace: path: /etc/rsyslog.conf regexp: '({{ item }})' @@ -157,9 +200,11 @@ with_items: - '^(\$ModLoad imtcp)' - '^(\$InputTCPServerRun)' + - '^(module\(load="imtcp"\))' + - '^(input\(type="imtcp")' when: not rhel9cis_system_is_log_server - - name: "4.2.1.6 | L1 | PATCH | Ensure remote rsyslog messages are only accepted on designated log hosts. | When log host" + - name: "4.2.1.7 | PATCH | Ensure rsyslog is not configured to recieve logs from a remote clients. | When log host" replace: path: /etc/rsyslog.conf regexp: '^#(.*{{ item }}.*)' @@ -168,12 +213,15 @@ with_items: - 'ModLoad imtcp' - 'InputTCPServerRun' + - 'module\(load="imtcp"\)' + - 'input\(type="imtcp"' when: rhel9cis_system_is_log_server when: - - rhel9cis_rule_4_2_1_6 + - rhel9cis_rule_4_2_1_7 tags: - level1-server - level1-workstation + - automated - patch - - rule_4.2.1.6 - rsyslog + - rule_4.2.1.7 diff --git a/tasks/section_4/cis_4.2.2.x.yml b/tasks/section_4/cis_4.2.2.x.yml index 1c87ed4..e83d97c 100644 --- a/tasks/section_4/cis_4.2.2.x.yml +++ b/tasks/section_4/cis_4.2.2.x.yml @@ -1,43 +1,206 @@ --- -- name: "4.2.2.1 | L1 | PATCH | Ensure journald is configured to send logs to rsyslog" - lineinfile: - dest: /etc/systemd/journald.conf - regexp: "^#ForwardToSyslog=|^ForwardToSyslog=" - line: ForwardToSyslog=yes +- name: "4.2.2.1.1 | PATCH | Ensure systemd-journal-remote is installed" + package: + name: systemd-journal-remote state: present when: - - rhel9cis_rule_4_2_2_1 + - rhel9cis_rule_4_2_2_1_1 tags: - level1-server - level1-workstation + - manual - patch - - rule_4.2.2.1 + - journald + - rule_4.2.2.1.1 -- name: "4.2.2.2 | L1 | PATCH | Ensure journald is configured to compress large log files" +- name: "4.2.2.1.2 | PATCH | Ensure systemd-journal-remote is configured" + lineinfile: + path: /etc/systemd/journal-upload.conf + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + notify: restart systemd_journal_upload + with_items: + - { regexp: 'URL=', line: 'URL={{ rhel9cis_journal_upload_url }}'} + - { regexp: 'ServerKeyFile=', line: 'ServerKeyFile={{ rhel9cis_journal_upload_serverkeyfile }}'} + - { regexp: 'ServerCertificateFile=', line: 'ServerCertificateFile={{ rhel9cis_journal_servercertificatefile }}'} + - { regexp: 'TrustedCertificateFile=', line: 'TrustedCertificateFile={{ rhel9cis_journal_trustedcertificatefile }}'} + when: + - rhel9cis_rule_4_2_2_1_2 + tags: + - level1-server + - level1-workstation + - manual + - patch + - journald + - rule_4.2.2.1.2 + +- name: "4.2.2.1.3 | PATCH | Ensure systemd-journal-remote is enabled" + systemd: + name: systemd-journal-upload + state: started + enabled: yes + when: + - rhel9cis_rule_4_2_2_1_3 + tags: + - level1-server + - level1-workstation + - manual + - patch + - journald + - rule_4.2.2.1.3 + +- name: "4.2.2.1.4 | PATCH | Ensure journald is not configured to recieve logs from a remote client" + systemd: + name: systemd-journal-remote + state: stopped + enabled: no + masked: yes + when: + - rhel9cis_rule_4_2_2_1_4 + tags: + - level1-server + - level1-workstation + - automated + - patch + - journald + - rule_4.2.2.1.4 + +- name: "4.2.2.2 | PATCH | Ensure journald service is enabled" + block: + - name: "4.2.2.2 | PATCH | Ensure journald service is enabled | Enable service" + systemd: + name: systemd-journald + state: started + enabled: yes + + - name: "4.2.2.2 | AUDIT | Ensure journald service is enabled | Capture status" + shell: systemctl is-enabled systemd-journald.service + changed_when: false + failed_when: false + register: rhel9cis_4_2_2_2_status + + - name: "4.2.2.2 | AUDIT | Ensure journald service is enabled | Alert on bad status" + debug: + msg: + - "ALERT! The status of systemd-journald should be static and it is not. Please investigate" + when: "'static' not in rhel9cis_4_2_2_2_status.stdout" + when: + - rhel9cis_rule_4_2_2_2 + tags: + - level1-server + - level1-workstation + - automated + - audit + - journald + - rule_4.2.2.2 + +- name: "4.2.2.3 | PATCH | Ensure journald is configured to compress large log files" lineinfile: dest: /etc/systemd/journald.conf regexp: "^#Compress=|^Compress=" line: Compress=yes state: present when: - - rhel9cis_rule_4_2_2_2 + - rhel9cis_rule_4_2_2_3 tags: - level1-server - level1-workstation + - automated - patch - - rule_4.2.2.2 + - journald + - rule_4.2.2.3 -- name: "4.2.2.3 | L1 | PATCH | Ensure journald is configured to write logfiles to persistent disk" +- name: "4.2.2.4 | PATCH | Ensure journald is configured to write logfiles to persistent disk" lineinfile: dest: /etc/systemd/journald.conf regexp: "^#Storage=|^Storage=" line: Storage=persistent state: present when: - - rhel9cis_rule_4_2_2_3 + - rhel9cis_rule_4_2_2_4 tags: - level1-server - level1-workstation + - automated - patch - - rule_4.2.2.3 + - journald + - rule_4.2.2.4 + +# This is counter to control 4.2.1.3?? +- name: "4.2.2.5 | PATCH | Ensure journald is not configured to send logs to rsyslog" + lineinfile: + dest: /etc/systemd/journald.conf + regexp: "^ForwardToSyslog=" + line: "#ForwardToSyslog=yes" + state: present + notify: restart systemd_journal_upload + when: + - rhel9cis_rule_4_2_2_5 + tags: + - level1-server + - level2-workstation + - manual + - patch + - journald + - rule_4.2.2.5 + +- name: "4.2.2.6 | PATCH | Ensure journald log rotation is configured per site policy" + lineinfile: + path: /etc/systemd/journald.conf + regexp: "{{ item.regexp }}" + line: "{{ item.line }}" + notify: restart journald + with_items: + - { regexp: '^#SystemMaxUse=|^SystemMaxUse=', line: 'SystemMaxUse={{ rhel9cis_journald_systemmaxuse }}'} + - { regexp: '^#SystemKeepFree=|^SystemKeepFree=', line: 'SystemKeepFree={{ rhel9cis_journald_systemkeepfree }}' } + - { regexp: '^#RuntimeMaxUse=|^RuntimeMaxUse=', line: 'RuntimeMaxUse={{ rhel9cis_journald_runtimemaxuse }}'} + - { regexp: '^#RuntimeKeepFree=|^RuntimeKeepFree=', line: 'RuntimeKeepFree={{ rhel9cis_journald_runtimekeepfree }}'} + - { regexp: '^#MaxFileSec=|^MaxFileSec=', line: 'MaxFileSec={{ rhel9cis_journald_maxfilesec }}'} + when: + - rhel9cis_rule_4_2_2_6 + tags: + - level1-server + - level1-workstation + - manual + - patch + - journald + - rule_4.2.2.6 + +- name: "4.2.2.7 | AUDIT | Ensure journald default file permissions configured" + block: + - name: "4.2.2.7 | AUDIT | Ensure journald default file permissions configured | Check for override file" + find: + paths: /etc/tmpfiles.d + patterns: systemd.conf + register: rhel9cis_4_2_2_7_override_status + + - name: "4.2.2.7 | AUDIT | Ensure journald default file permissions configured | Get override file settings" + shell: cat /etc/tmpfiles.d/systemd.conf + changed_when: false + failed_when: false + register: rhel9cis_4_2_2_7_override_settings + when: rhel9cis_4_2_2_7_override_status.matched >= 1 + + - name: "4.2.2.7 | AUDIT | Ensure journald default file permissions configured | Get non-override file settings" + shell: cat /usr/lib/tmpfiles.d/systemd.conf + changed_when: false + failed_when: false + register: rhel9cis_4_2_2_7_notoverride_settings + when: rhel9cis_4_2_2_7_override_status.matched == 0 + + - name: "4.2.2.7 | AUDIT | Ensure journald default file permissions configured | Display file settings" + debug: + msg: + - "Alert! Below are the current default settings for journald, please confirm they align with your site policies" + # - "{{ rhel9cis_4_2_2_7_override_settings.stdout_lines }}" + - "{{ (rhel9cis_4_2_2_7_override_status.matched >= 1) | ternary(rhel9cis_4_2_2_7_override_settings.stdout_lines, rhel9cis_4_2_2_7_notoverride_settings.stdout_lines) }}" + when: + - rhel9cis_rule_4_2_2_7 + tags: + - level1-server + - level1-workstation + - manual + - patch + - journald + - rule_4.2.2.7 diff --git a/tasks/section_4/cis_4.2.3.yml b/tasks/section_4/cis_4.2.3.yml index bd13030..a1b3bb7 100644 --- a/tasks/section_4/cis_4.2.3.yml +++ b/tasks/section_4/cis_4.2.3.yml @@ -1,9 +1,7 @@ --- -- name: "4.2.3 | L1 | PATCH | Ensure permissions on all logfiles are configured" - shell: find /var/log -type f -exec chmod g-wx,o-rwx "{}" + - args: - warn: false +- name: "4.2.3 | PATCH | Ensure permissions on all logfiles are configured" + command: find /var/log -type f -exec chmod g-wx,o-rwx "{}" + changed_when: false failed_when: false when: @@ -11,5 +9,7 @@ tags: - level1-server - level1-workstation + - automated - patch + - logfiles - rule_4.2.3 diff --git a/tasks/section_4/cis_4.3.yml b/tasks/section_4/cis_4.3.yml index 7e7fafb..e8a4780 100644 --- a/tasks/section_4/cis_4.3.yml +++ b/tasks/section_4/cis_4.3.yml @@ -1,13 +1,13 @@ --- -- name: "4.3 | L1 | PATCH | Ensure logrotate is configured" +- name: "4.3 | PATCH | Ensure logrotate is configured" block: - - name: "4.3 | L1 | AUDIT | Ensure logrotate is configured | Get logrotate settings" + - name: "4.3 | AUDIT | Ensure logrotate is configured | Get logrotate settings" find: paths: /etc/logrotate.d/ register: log_rotates - - name: "4.3 | L1 | PATCH | Ensure logrotate is configured" + - name: "4.3 | PATCH | Ensure logrotate is configured" replace: path: "{{ item.path }}" regexp: '^(\s*)(daily|weekly|monthly|yearly)$' @@ -15,11 +15,14 @@ with_items: - "{{ log_rotates.files }}" - { path: "/etc/logrotate.conf" } + loop_control: + label: "{{ item.path }}" when: - rhel9cis_rule_4_3 - - "'logrotate' in ansible_facts.packages" tags: - level1-server - level1-workstation + - manual - patch + - logrotate - rule_4.3 diff --git a/tasks/section_4/main.yml b/tasks/section_4/main.yml index 8e84241..3b3ab95 100644 --- a/tasks/section_4/main.yml +++ b/tasks/section_4/main.yml @@ -1,21 +1,21 @@ --- -- name: "SECTION | 4.1| Configure System Accounting (auditd)" +- name: "SECTION | 4.1 | Configure System Accounting (auditd)" include_tasks: cis_4.1.1.x.yml when: - not system_is_container -- name: "SECTION | 4.1.2.x| Configure Data Retention" +- name: "SECTION | 4.1.2 | Configure Data Retention" import_tasks: cis_4.1.2.x.yml -- name: "SECTION | 4.1.x| Auditd rules" +- name: "SECTION | 4.1.3 | Configure Auditd rules" import_tasks: cis_4.1.x.yml -- name: "SECTION | 4.2.x| Configure Logging" +- name: "SECTION | 4.2 | Configure Logging" import_tasks: cis_4.2.1.x.yml when: rhel9cis_syslog == 'rsyslog' -- name: "SECTION | 4.2.2.x| Configure journald" +- name: "SECTION | 4.2.2 Configure journald" import_tasks: cis_4.2.2.x.yml - name: "SECTION | 4.2.3 | Configure logile perms" diff --git a/tasks/section_5/cis_5.1.x.yml b/tasks/section_5/cis_5.1.x.yml index dffbeaf..9e8657e 100644 --- a/tasks/section_5/cis_5.1.x.yml +++ b/tasks/section_5/cis_5.1.x.yml @@ -1,18 +1,20 @@ --- -- name: "5.1.1 | L1 | PATCH | Ensure cron daemon is enabled" +- name: "5.1.1 | PATCH | Ensure cron daemon is enabled" service: name: crond - enabled: true + enabled: yes when: - rhel9cis_rule_5_1_1 tags: - level1-server - level1-workstation + - automated - patch + - cron - rule_5.1.1 -- name: "5.1.2 | L1 | PATCH | Ensure permissions on /etc/crontab are configured" +- name: "5.1.2 | PATCH | Ensure permissions on /etc/crontab are configured" file: dest: /etc/crontab owner: root @@ -23,10 +25,12 @@ tags: - level1-server - level1-workstation + - automated - patch + - cron - rule_5.1.2 -- name: "5.1.3 | L1 | PATCH | Ensure permissions on /etc/cron.hourly are configured" +- name: "5.1.3 | PATCH | Ensure permissions on /etc/cron.hourly are configured" file: dest: /etc/cron.hourly state: directory @@ -38,10 +42,12 @@ tags: - level1-server - level1-workstation + - automated - patch + - cron - rule_5.1.3 -- name: "5.1.4 | L1 | PATCH | Ensure permissions on /etc/cron.daily are configured" +- name: "5.1.4 | PATCH | Ensure permissions on /etc/cron.daily are configured" file: dest: /etc/cron.daily state: directory @@ -53,10 +59,12 @@ tags: - level1-server - level1-workstation + - automated - patch + - cron - rule_5.1.4 -- name: "5.1.5 | L1 | PATCH | Ensure permissions on /etc/cron.weekly are configured" +- name: "5.1.5 | PATCH | Ensure permissions on /etc/cron.weekly are configured" file: dest: /etc/cron.weekly state: directory @@ -71,7 +79,7 @@ - patch - rule_5.1.5 -- name: "5.1.6 | L1 | PATCH | Ensure permissions on /etc/cron.monthly are configured" +- name: "5.1.6 | PATCH | Ensure permissions on /etc/cron.monthly are configured" file: dest: /etc/cron.monthly state: directory @@ -83,10 +91,11 @@ tags: - level1-server - level1-workstation + - automated - patch - rule_5.1.6 -- name: "5.1.7 | L1 | PATCH | Ensure permissions on /etc/cron.d are configured" +- name: "5.1.7 | PATCH | Ensure permissions on /etc/cron.d are configured" file: dest: /etc/cron.d state: directory @@ -98,43 +107,27 @@ tags: - level1-server - level1-workstation + - automated - patch + - cron - rule_5.1.7 -- name: "5.1.8 | L1 | PATCH | Ensure at/cron is restricted to authorized users" +- name: "5.1.8 | PATCH | Ensure cron is restricted to authorized users" block: - - name: "5.1.8 | L1 | PATCH | Ensure at/cron is restricted to authorized users | Remove at.deny" - file: - dest: /etc/at.deny - state: absent - - - name: "5.1.8 | L1 | PATCH | Ensure at/cron is restricted to authorized users | Check if at.allow exists" - stat: - path: "/etc/at.allow" - register: p - - - name: "5.1.8 | L1 | PATCH | Ensure at/cron is restricted to authorized users | Ensure at.allow is restricted to authorized users" - file: - dest: /etc/at.allow - state: '{{ "file" if p.stat.exists else "touch" }}' - owner: root - group: root - mode: 0600 - - - name: "5.1.8 | L1 | PATCH | Ensure at/cron is restricted to authorized users | Remove cron.deny" + - name: "5.1.8 | PATCH | Ensure cron is restricted to authorized users | Remove cron.deny" file: dest: /etc/cron.deny state: absent - - name: "5.1.8 | L1 | PATCH | Ensure at/cron is restricted to authorized users | Check if cron.allow exists" + - name: "5.1.8 | PATCH | Ensure cron is restricted to authorized users | Check if cron.allow exists" stat: path: "/etc/cron.allow" - register: p + register: rhel9cis_5_1_8_cron_allow_state - - name: "5.1.8 | L1 | PATCH | Ensure at/cron is restricted to authorized users | Ensure cron.allow is restricted to authorized users" + - name: "5.1.8 | PATCH | Ensure cron is restricted to authorized users | Ensure cron.allow is restricted to authorized users" file: dest: /etc/cron.allow - state: '{{ "file" if p.stat.exists else "touch" }}' + state: '{{ "file" if rhel9cis_5_1_8_cron_allow_state.stat.exists else "touch" }}' owner: root group: root mode: 0600 @@ -143,5 +136,36 @@ tags: - level1-server - level1-workstation + - automated - patch + - cron - rule_5.1.8 + +- name: "5.1.9 | PATCH | Ensure at is restricted to authorized users" + block: + - name: "5.1.9 | PATCH | Ensure at is restricted to authorized users | Remove at.deny" + file: + dest: /etc/at.deny + state: absent + + - name: "5.1.9 | PATCH | Ensure at is restricted to authorized users | Check if at.allow exists" + stat: + path: "/etc/at.allow" + register: rhel9cis_5_1_9_at_allow_state + + - name: "5.1.9 | PATCH | Ensure at is restricted to authorized users | Ensure at.allow is restricted to authorized users" + file: + dest: /etc/at.allow + state: '{{ "file" if rhel9cis_5_1_9_at_allow_state.stat.exists else "touch" }}' + owner: root + group: root + mode: 0600 + when: + - rhel9cis_rule_5_1_9 + tags: + - level1-server + - level1-workstation + - automated + - patch + - cron + - rule_5.1.9 \ No newline at end of file diff --git a/tasks/section_5/cis_5.2.x.yml b/tasks/section_5/cis_5.2.x.yml index 0629cc7..4b28f5b 100644 --- a/tasks/section_5/cis_5.2.x.yml +++ b/tasks/section_5/cis_5.2.x.yml @@ -1,6 +1,6 @@ --- -- name: "5.2.1 | L1 | PATCH | Ensure permissions on /etc/ssh/sshd_config are configured" +- name: "5.2.1 | Ensure permissions on /etc/ssh/sshd_config are configured" file: dest: /etc/ssh/sshd_config state: file @@ -12,12 +12,76 @@ tags: - level1-server - level1-workstation + - automated - patch + - ssh + - permissions - rule_5.2.1 -- name: "5.2.2 | L1 | PATCH | Ensure SSH access is limited" +- name: "5.2.2 | PATCH | Ensure permissions on SSH private host key files are configured" block: - - name: "5.2.2 | L1 | PATCH | Ensure SSH access is limited | Add line to sshd_config for allowusers" + - name: "5.2.2 | AUDIT | Ensure permissions on SSH private host key files are configured | Find the SSH private host keys" + find: + paths: /etc/ssh + patterns: 'ssh_host_*_key' + recurse: true + file_type: any + register: rhel9cis_5_2_2_ssh_private_host_key + + - name: "5.2.2 | PATCH | Ensure permissions on SSH private host key files are configured | Set permissions on SSH private host keys" + file: + path: "{{ item.path }}" + owner: root + group: root + mode: 0600 + with_items: + - "{{ rhel9cis_5_2_2_ssh_private_host_key.files }}" + loop_control: + label: "{{ item.path }}" + when: + - rhel9cis_rule_5_2_2 + tags: + - level1-server + - level1-workstation + - automated + - patch + - ssh + - permissions + - rule_5.2.2 + +- name: "5.2.3 | PATCH | Ensure permissions on SSH public host key files are configured" + block: + - name: "5.2.3 | AUDIT | Ensure permissions on SSH public host key files are configured | Find the SSH public host keys" + find: + paths: /etc/ssh + patterns: 'ssh_host_*_key.pub' + recurse: true + file_type: any + register: rhel9cis_5_2_3_ssh_public_host_key + + - name: "5.2.3 | PATCH | Ensure permissions on SSH public host key files are configured | Set permissions on SSH public host keys" + file: + path: "{{ item.path }}" + owner: root + group: root + mode: 0644 + with_items: + - "{{ rhel9cis_5_2_3_ssh_public_host_key.files }}" + loop_control: + label: "{{ item.path }}" + when: + - rhel9cis_rule_5_2_3 + tags: + - level1-server + - level1-workstation + - automated + - patch + - ssh + - rule_5.2.3 + +- name: "5.2.4 | PATCH | Ensure SSH access is limited" + block: + - name: "5.2.4 | PATCH | Ensure SSH access is limited | Add line to sshd_config for allowusers" lineinfile: state: present dest: /etc/ssh/sshd_config @@ -26,7 +90,7 @@ notify: restart sshd when: "rhel9cis_sshd['allowusers']|default('') | length > 0" - - name: "5.2.2 | L1 | PATCH | Ensure SSH access is limited | Add line to sshd_config for allowgroups" + - name: "5.2.4 | PATCH | Ensure SSH access is limited | Add line to sshd_config for allowgroups" lineinfile: state: present dest: /etc/ssh/sshd_config @@ -35,7 +99,7 @@ notify: restart sshd when: "rhel9cis_sshd['allowgroups']|default('') | length > 0" - - name: "5.2.2 | L1 | PATCH | Ensure SSH access is limited | Add line to sshd_config for denyusers" + - name: "5.2.4 | PATCH | Ensure SSH access is limited | Add line to sshd_config for denyusers" lineinfile: state: present dest: /etc/ssh/sshd_config @@ -44,7 +108,7 @@ notify: restart sshd when: "rhel9cis_sshd['denyusers']|default('') | length > 0" - - name: "5.2.2 | L1 | PATCH | Ensure SSH access is limited | Add line to sshd_config for denygroups" + - name: "5.2.4 | PATCH | Ensure SSH access is limited | Add line to sshd_config for denygroups" lineinfile: state: present dest: /etc/ssh/sshd_config @@ -52,67 +116,17 @@ line: DenyGroups {{ rhel9cis_sshd['denygroups'] }} notify: restart sshd when: "rhel9cis_sshd['denygroups']|default('') | length > 0" - when: - - rhel9cis_rule_5_2_2 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.2.2 - -- name: "5.2.3 | L1 | PATCH | Ensure permissions on SSH private host key files are configured" - block: - - name: "5.2.3 | L1 | AUDIT | Ensure permissions on SSH private host key files are configured | Find the SSH private host keys" - find: - paths: /etc/ssh - patterns: 'ssh_host_*_key' - recurse: true - file_type: any - register: rhel9cis_5_2_3_ssh_private_host_key - - - name: "5.2.3 | L1 | PATCH | Ensure permissions on SSH private host key files are configured | Set permissions on SSH private host keys" - file: - path: "{{ item.path }}" - owner: root - group: root - mode: 0600 - with_items: - - "{{ rhel9cis_5_2_3_ssh_private_host_key.files }}" - when: - - rhel9cis_rule_5_2_3 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.2.3 - -- name: "5.2.4 | L1 | PATCH | Ensure permissions on SSH public host key files are configured" - block: - - name: "5.2.4 | L1 | AUDIT | Ensure permissions on SSH public host key files are configured | Find the SSH public host keys" - find: - paths: /etc/ssh - patterns: 'ssh_host_*_key.pub' - recurse: true - file_type: any - register: rhel9cis_5_2_4_ssh_public_host_key - - - name: "5.2.4 | L1 | PATCH | Ensure permissions on SSH public host key files are configured | Set permissions on SSH public host keys" - file: - path: "{{ item.path }}" - owner: root - group: root - mode: 0644 - with_items: - - "{{ rhel9cis_5_2_4_ssh_public_host_key.files }}" when: - rhel9cis_rule_5_2_4 tags: - level1-server - level1-workstation + - automated - patch + - ssh - rule_5.2.4 -- name: "5.2.5 | L1 | PATCH | Ensure SSH LogLevel is appropriate" +- name: "5.2.5 | PATCH | Ensure SSH LogLevel is appropriate" lineinfile: state: present dest: /etc/ssh/sshd_config @@ -123,145 +137,155 @@ tags: - level1-server - level1-workstation + - automated - patch + - sshs - rule_5.2.5 -- name: "5.2.6 | L2 | PATCH | Ensure SSH X11 forwarding is disabled" +- name: "5.2.6 | PATCH | Ensure SSH PAM is enabled" lineinfile: state: present dest: /etc/ssh/sshd_config - regexp: "^#X11Forwarding|^X11Forwarding" - line: 'X11Forwarding no' + regexp: "^#UsePAM|^UsePAM" + line: 'UsePAM yes' when: - rhel9cis_rule_5_2_6 tags: - - level2-server + - level1-server - level1-workstation + - automated - patch + - ssh - rule_5.2.6 -- name: "5.2.7 | L1 | PATCH | Ensure SSH MaxAuthTries is set to 4 or less" - lineinfile: - state: present - dest: /etc/ssh/sshd_config - regexp: '^(#)?MaxAuthTries \d' - line: 'MaxAuthTries 4' - when: - - rhel9cis_rule_5_2_7 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.2.7 - -- name: "5.2.8 | L1 | PATCH | Ensure SSH IgnoreRhosts is enabled" - lineinfile: - state: present - dest: /etc/ssh/sshd_config - regexp: "^#IgnoreRhosts|^IgnoreRhosts" - line: 'IgnoreRhosts yes' - when: - - rhel9cis_rule_5_2_8 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.2.8 - -- name: "5.2.9 | L1 | PATCH | Ensure SSH HostbasedAuthentication is disabled" - lineinfile: - state: present - dest: /etc/ssh/sshd_config - regexp: ^#HostbasedAuthentication|^HostbasedAuthentication" - line: 'HostbasedAuthentication no' - when: - - rhel9cis_rule_5_2_9 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.2.9 - -- name: "5.2.10 | L1 | PATCH | Ensure SSH root login is disabled" +- name: "5.2.7 | PATCH | Ensure SSH root login is disabled" lineinfile: state: present dest: /etc/ssh/sshd_config regexp: "^#PermitRootLogin|^PermitRootLogin" line: 'PermitRootLogin no' when: - - rhel9cis_rule_5_2_10 + - rhel9cis_rule_5_2_7 tags: - level1-server - level1-workstation + - autoamted - patch - - rule_5.2.10 + - ssh + - rule_5.2.7 -- name: "5.2.11 | L1 | PATCH | Ensure SSH PermitEmptyPasswords is disabled" +- name: "5.2.8 | PATCH | Ensure SSH HostbasedAuthentication is disabled" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: ^#HostbasedAuthentication|^HostbasedAuthentication" + line: 'HostbasedAuthentication no' + when: + - rhel9cis_rule_5_2_8 + tags: + - level1-server + - level1-workstation + - automated + - patch + - ssh + - rule_5.2.8 + +- name: "5.2.9 | PATCH | Ensure SSH PermitEmptyPasswords is disabled" lineinfile: state: present dest: /etc/ssh/sshd_config regexp: "^#PermitEmptyPasswords|^PermitEmptyPasswords" line: 'PermitEmptyPasswords no' when: - - rhel9cis_rule_5_2_11 + - rhel9cis_rule_5_2_9 tags: - level1-server - level1-workstation + - automated - patch - - rule_5.2.11 + - ssh + - rule_5.2.9 -- name: "5.2.12 | L1 | PATCH | Ensure SSH PermitUserEnvironment is disabled" +- name: "5.2.10 | PATCH | Ensure SSH PermitUserEnvironment is disabled" lineinfile: state: present dest: /etc/ssh/sshd_config regexp: "^#PermitUserEnvironment|^PermitUserEnvironment" line: 'PermitUserEnvironment no' when: - - rhel9cis_rule_5_2_12 + - rhel9cis_rule_5_2_10 tags: - level1-server - level1-workstation + - automated - patch - - rule_5.2.12 + - ssh + - rule_5.2.10 -- name: "5.2.13 | L1 | PATCH | Ensure SSH Idle Timeout Interval is configured" - block: - - name: "5.2.13 | L1 | PATCH | Ensure SSH Idle Timeout Interval is configured | Add line in sshd_config for ClientAliveInterval" - lineinfile: - state: present - dest: /etc/ssh/sshd_config - regexp: '^ClientAliveInterval' - line: "ClientAliveInterval {{ rhel9cis_sshd['clientaliveinterval'] }}" - - - name: "5.2.13 | L1 | PATCH | Ensure SSH Idle Timeout Interval is configured | Ensure SSH ClientAliveCountMax set to <= 3" - lineinfile: - state: present - dest: /etc/ssh/sshd_config - regexp: '^ClientAliveCountMax' - line: "ClientAliveCountMax {{ rhel9cis_sshd['clientalivecountmax'] }}" - when: - - rhel9cis_rule_5_2_13 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.2.13 - -- name: "5.2.14 | L1 | PATCH | Ensure SSH LoginGraceTime is set to one minute or less" +- name: "5.2.11 | PATCH | Ensure SSH IgnoreRhosts is enabled" lineinfile: state: present dest: /etc/ssh/sshd_config - regexp: "^#LoginGraceTime|^LoginGraceTime" - line: "LoginGraceTime {{ rhel9cis_sshd['logingracetime'] }}" + regexp: "^#IgnoreRhosts|^IgnoreRhosts" + line: 'IgnoreRhosts yes' + when: + - rhel9cis_rule_5_2_11 + tags: + - level1-server + - level1-workstation + - autoamted + - patch + - ssh + - rule_5.2.11 + +- name: "5.2.12 | PATCH | Ensure SSH X11 forwarding is disabled" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: "^#X11Forwarding|^X11Forwarding" + line: 'X11Forwarding no' + when: + - rhel9cis_rule_5_2_12 + tags: + - level2-server + - level1-workstation + - autoamted + - patch + - ssh + - rule_5.2.12 + +- name: "5.2.13 | PATCH | Ensure SSH AllowTcpForwarding is disabled" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: "^#AllowTcpForwarding|^AllowTcpForwarding" + line: 'AllowTcpForwarding no' + when: + - rhel9cis_rule_5_2_13 + tags: + - level2-server + - level2-workstation + - autoamted + - patch + - ssh + - rule_5.2.13 + +- name: "5.2.14 | PATCH | Ensure system-wide crypto policy is not over-ridden" + shell: sed -ri "s/^\s*(CRYPTO_POLICY\s*=.*)$/# \1/" /etc/sysconfig/sshd + args: + warn: no + notify: restart sshd when: - rhel9cis_rule_5_2_14 tags: - level1-server - level1-workstation + - automated - patch + - ssh - rule_5.2.14 -- name: "5.2.15 | L1 | PATCH | Ensure SSH warning banner is configured" +- name: "5.2.15 | PATCH | Ensure SSH warning banner is configured" lineinfile: state: present dest: /etc/ssh/sshd_config @@ -272,74 +296,96 @@ tags: - level1-server - level1-workstation + - automated - patch + - ssh - rule_5.2.15 -- name: "5.2.16 | L1 | PATCH | Ensure SSH PAM is enabled" +- name: "5.2.16 | PATCH | Ensure SSH MaxAuthTries is set to 4 or less" lineinfile: state: present dest: /etc/ssh/sshd_config - regexp: "^#UsePAM|^UsePAM" - line: 'UsePAM yes' + regexp: '^(#)?MaxAuthTries \d' + line: 'MaxAuthTries 4' when: - rhel9cis_rule_5_2_16 tags: - level1-server - level1-workstation + - autoamted - patch + - ssh - rule_5.2.16 -- name: "5.2.17 | L2 | PATCH | Ensure SSH AllowTcpForwarding is disabled" - lineinfile: - state: present - dest: /etc/ssh/sshd_config - regexp: "^#AllowTcpForwarding|^AllowTcpForwarding" - line: 'AllowTcpForwarding no' - when: - - rhel9cis_rule_5_2_17 - tags: - - level2-server - - level2-workstation - - patch - - rule_5.2.17 - -- name: "5.2.18 | L1 | PATCH | Ensure SSH MaxStartups is configured" +- name: "5.2.17 | PATCH | Ensure SSH MaxStartups is configured" lineinfile: state: present dest: /etc/ssh/sshd_config regexp: "^#MaxStartups|^MaxStartups" line: 'MaxStartups 10:30:60' when: - - rhel9cis_rule_5_2_18 + - rhel9cis_rule_5_2_17 tags: - level1-server - level1-workstation + - autoamted - patch - - rule_5.2.18 + - ssh + - rule_5.2.17 -- name: "5.2.19 | L1 | PATCH | Ensure SSH MaxSessions is set to 4 or less" +- name: "5.2.18 | PATCH | Ensure SSH MaxSessions is set to 10 or less" lineinfile: state: present dest: /etc/ssh/sshd_config regexp: "^#MaxSessions|^MaxSessions" line: 'MaxSessions {{ rhel9cis_ssh_maxsessions }}' + when: + - rhel9cis_rule_5_2_18 + tags: + - level1-server + - level1-workstation + - automated + - patch + - ssh + - rule_5.2.18 + +- name: "5.2.19 | PATCH | Ensure SSH LoginGraceTime is set to one minute or less" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: "^#LoginGraceTime|^LoginGraceTime" + line: "LoginGraceTime {{ rhel9cis_sshd['logingracetime'] }}" when: - rhel9cis_rule_5_2_19 tags: - level1-server - level1-workstation + - automated - patch + - ssh - rule_5.2.19 -- name: "5.2.20 | L1 | PATCH | Ensure system-wide crypto policy is not over-ridden" - shell: sed -ri "s/^\s*(CRYPTO_POLICY\s*=.*)$/# \1/" /etc/sysconfig/sshd - args: - warn: false - notify: restart sshd +- name: "5.2.20 | PATCH | Ensure SSH Idle Timeout Interval is configured" + block: + - name: "5.2.20 | PATCH | Ensure SSH Idle Timeout Interval is configured | Add line in sshd_config for ClientAliveInterval" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: '^ClientAliveInterval' + line: "ClientAliveInterval {{ rhel9cis_sshd['clientaliveinterval'] }}" + + - name: "5.2.20 | PATCH | Ensure SSH Idle Timeout Interval is configured | Ensure SSH ClientAliveCountMax set to <= 3" + lineinfile: + state: present + dest: /etc/ssh/sshd_config + regexp: '^ClientAliveCountMax' + line: "ClientAliveCountMax {{ rhel9cis_sshd['clientalivecountmax'] }}" when: - rhel9cis_rule_5_2_20 tags: - level1-server - level1-workstation + - automated - patch + - ssh - rule_5.2.20 diff --git a/tasks/section_5/cis_5.3.x.yml b/tasks/section_5/cis_5.3.x.yml index 2762302..b6dc07a 100644 --- a/tasks/section_5/cis_5.3.x.yml +++ b/tasks/section_5/cis_5.3.x.yml @@ -1,94 +1,138 @@ --- -- name: "5.3.1 | L1 | PATCH | Create custom authselect profile" - block: - - name: "5.3.1 | L1 | PATCH | Create custom authselect profile | Gather profiles" - shell: 'authselect current | grep "Profile ID: custom/"' - args: - warn: false - failed_when: false - changed_when: false - check_mode: false - register: rhel9cis_5_3_1_profiles - - - name: "5.3.1 | L1 | AUDIT | Create custom authselect profile | Show profiles" - debug: - msg: - - "Below are the current custom profiles" - - "{{ rhel9cis_5_3_1_profiles.stdout_lines }}" - - - name: "5.3.1 | L1 | PATCH | Create custom authselect profile | Create custom profiles" - shell: authselect create-profile {{ rhel9cis_authselect['custom_profile_name'] }} -b {{ rhel9cis_authselect['default_file_to_copy'] }} - args: - warn: false - when: rhel9cis_authselect_custom_profile_create +- name: "5.3.1 | PATCH | Ensure sudo is installed" + package: + name: sudo + state: present when: - rhel9cis_rule_5_3_1 tags: - level1-server - level1-workstation + - automated - patch - - authselect + - sudo - rule_5.3.1 -- name: "5.3.2 | L1 | PATCH | Select authselect profile" - block: - - name: "5.3.2 | L1 | AUDIT | Select authselect profile | Gather profiles and enabled features" - shell: "authselect current" - args: - warn: false - failed_when: false - changed_when: false - check_mode: false - register: rhel9cis_5_3_2_profiles - - - name: "5.3.2 | L1 | AUDIT | Select authselect profile | Show profiles" - debug: - msg: - - "Below are the current custom profiles" - - "{{ rhel9cis_5_3_2_profiles.stdout_lines }}" - - - name: "5.3.2 | L1 | PATCH | Select authselect profile | Create custom profiles" - shell: "authselect select custom/{{ rhel9cis_authselect['custom_profile_name'] }} {{ rhel9cis_authselect['options'] }}" - args: - warn: false - when: rhel9cis_authselect_custom_profile_select +- name: "5.3.2 | PATCH | Ensure sudo commands use pty" + lineinfile: + dest: /etc/sudoers + line: "Defaults use_pty" + state: present when: - rhel9cis_rule_5_3_2 tags: - level1-server - level1-workstation + - automated - patch - - authselect + - sudo - rule_5.3.2 -- name: "5.3.3 | L1 | PATCH | Ensure authselect includes with-faillock" - block: - - name: "5.3.3 | L1 | AUDIT | Ensure authselect includes with-faillock | Gather profiles and enabled features" - shell: "authselect current | grep with-faillock" - args: - warn: false - failed_when: false - changed_when: false - check_mode: false - register: rhel9cis_5_3_3_profiles_faillock - - - name: "5.3.3 | L1 | AUDIT | Ensure authselect includes with-faillock| Show profiles" - debug: - msg: - - "Below are the current custom profiles" - - "{{ rhel9cis_5_3_3_profiles_faillock.stdout_lines }}" - - - name: "5.3.3 | L1 | PATCH | Ensure authselect includes with-faillock | Create custom profiles" - shell: "authselect select custom/{{ rhel9cis_authselect['custom_profile_name'] }} with-faillock" - args: - warn: false - when: rhel9cis_authselect_custom_profile_select +- name: "5.3.3 | PATCH | Ensure sudo log file exists" + lineinfile: + dest: /etc/sudoers + regexp: '^Defaults logfile=' + line: 'Defaults logfile="{{ rhel9cis_varlog_location }}"' + state: present when: - rhel9cis_rule_5_3_3 tags: - level1-server - level1-workstation + - automated - patch - - authselect + - sudo - rule_5.3.3 + +- name: "5.3.4 | PATCH | Ensure users must provide password for escalation" + replace: + path: "{{ item }}" + regexp: '^([^#|{% if system_is_ec2 %}ec2-user{% endif %}].*)NOPASSWD(.*)' + replace: '\1PASSWD\2' + with_items: + - "{{ rhel9cis_sudoers_files.stdout_lines }}" + when: + - rhel9cis_rule_5_3_4 + tags: + - level2-server + - level2-workstation + - automated + - patch + - sudo + - rule_5.3.4 + +- name: "5.3.5 | PATCH | Ensure re-authentication for privilege escalation is not disabled globally" + replace: + path: "{{ item }}" + regexp: '^([^#].*)!authenticate(.*)' + replace: '\1authenticate\2' + with_items: + - "{{ rhel9cis_sudoers_files.stdout_lines }}" + when: + - rhel9cis_rule_5_3_5 + tags: + - level1-server + - level1-workstation + - automated + - patch + - sudo + - rule_5.3.5 + +- name: "5.3.6 | PATCH | Ensure sudo authentication timeout is configured correctly" + block: + - name: "5.3.6 | AUDIT | Ensure sudo authentication timeout is configured correctly | Get files with timeout set" + shell: grep -is 'timestamp_timeout' /etc/sudoers /etc/sudoers.d/* | cut -d":" -f1 | uniq | sort + changed_when: false + failed_when: false + register: rhel9cis_5_3_6_timeout_files + + - name: "5.3.6 | PATCH | Ensure sudo authentication timeout is configured correctly | Set value if no results" + lineinfile: + path: /etc/sudoers + regexp: 'Defaults timestamp_timeout=' + line: "Defaults timestamp_timeout={{ rhel9cis_sudo_timestamp_timeout }}" + validate: '/usr/sbin/visudo -cf %s' + when: rhel9cis_5_3_6_timeout_files.stdout | length == 0 + + - name: "5.3.6 | PATCH | Ensure sudo authentication timeout is configured correctly | Set value if has results" + replace: + path: "{{ item }}" + regexp: 'timestamp_timeout=(\d+)' + replace: "timestamp_timeout={{ rhel9cis_sudo_timestamp_timeout }}" + validate: '/usr/sbin/visudo -cf %s' + with_items: + - "{{ rhel9cis_5_3_6_timeout_files.stdout_lines }}" + when: rhel9cis_5_3_6_timeout_files.stdout | length > 0 + when: + - rhel9cis_rule_5_3_6 + tags: + - level1-server + - level1-workstation + - automated + - patch + - sudo + - rule_5.3.6 + +- name: "5.3.7 | PATCH | Ensure access to the su command is restricted" + block: + - name: "5.3.7 | PATCH | Ensure access to the su command is restricted | Setting pam_wheel to use_uid" + lineinfile: + state: present + dest: /etc/pam.d/su + regexp: '^(#)?auth\s+required\s+pam_wheel\.so' + line: 'auth required pam_wheel.so use_uid {% if rhel9cis_sugroup is defined %}group={{ rhel9cis_sugroup }}{% endif %}' + + - name: "5.3.7 | PATCH | Ensure access to the su command is restricted | wheel group contains root" + user: + name: "{{ rhel9cis_sugroup_users }}" + groups: "{{ rhel9cis_sugroup | default('wheel') }}" + when: + - rhel9cis_rule_5_3_7 + tags: + - level1-server + - level1-workstation + - automated + - patch + - sudo + - rule_5.3.7 diff --git a/tasks/section_5/cis_5.4.x.yml b/tasks/section_5/cis_5.4.x.yml index 05ccefb..501af41 100644 --- a/tasks/section_5/cis_5.4.x.yml +++ b/tasks/section_5/cis_5.4.x.yml @@ -1,131 +1,61 @@ --- -- name: | - "5.4.1 | L1 | PATCH | Ensure password creation requirements are configured - 5.4.2 | L1 | PATCH | Ensure lockout for failed password attempts is configured - 5.4.3 | L1 | PATCH | Ensure password reuse is limited - 5.4.4 | L1 | PATCH | Ensure password hashing algorithm is SHA-512" +- name: "5.4.1 | PATCH | Ensure custom authselect profile is used" block: - - name: "5.4.1 | L1 | PATCH | Ensure password creation requirements are configured | Set pwquality config settings" - lineinfile: - state: present - dest: /etc/security/pwquality.conf - regexp: ^{{ item.name }} - line: "{{ item.name }} = {{ item.value }}" - with_items: - - { name: minlen, value: "{{ rhel9cis_pam_password.minlen }}" } - - { name: minclass, value: "{{ rhel9cis_pam_password.minclass }}" } - when: rhel9cis_rule_5_4_1 + - name: "5.4.1 | AUDIT | Ensure custom authselect profile is used | Gather profiles" + shell: 'authselect current | grep "Profile ID: custom/"' + failed_when: false + changed_when: false + check_mode: no + register: rhel9cis_5_4_1_profiles - - name: | - "5.4.1 | L1 | PATCH | Ensure password creation requirements are configured | Set system-auth retry settings - 5.4.3| L1 | PATCH | Ensure password reuse is limited | Set system-auth remember settings" - lineinfile: - dest: /etc/pam.d/system-auth - state: present - regexp: '^password requisite pam_pwquality.so' - line: "password requisite pam_pwquality.so try_first_pass local_users_only enforce_for_root retry=3 remember={{ rhel9cis_pam_faillock.remember }}" - insertbefore: '^#?password ?' - when: - - rhel9cis_rule_5_4_1 or - rhel9cis_rule_5_4_3 + - name: "5.4.1 | AUDIT | Ensure custom authselect profile is used | Show profiles" + debug: + msg: + - "Below are the current custom profiles" + - "{{ rhel9cis_5_4_1_profiles.stdout_lines }}" - - name: "5.4.1 | L1 | PATCH | Ensure password creation requirements are configured | Set system-auth retry settings" - lineinfile: - dest: /etc/pam.d/password-auth - state: present - regexp: '^password requisite pam_pwquality.so' - line: "password requisite pam_pwquality.so try_first_pass local_users_only enforce_for_root retry=3" - insertbefore: '^#?password ?' - when: rhel9cis_rule_5_4_1 - - - name: "5.4.2 | L1 | PATCH | Ensure lockout for failed password attempts is configured | Add deny count and unlock time for preauth" - lineinfile: - dest: /etc/pam.d/{{ item }} - state: present - regexp: '^auth required pam_faillock.so preauth' - line: "auth required pam_faillock.so preauth silent deny={{ rhel9cis_pam_faillock.attempts }}{{ (rhel9cis_pam_faillock.fail_for_root) | ternary(' even_deny_root ',' ') }}unlock_time={{ rhel9cis_pam_faillock.unlock_time }}" - insertafter: '^#?auth ?' - with_items: - - "system-auth" - - "password-auth" - when: rhel9cis_rule_5_4_2 - - - name: "5.4.2 | L1 | PATCH | Ensure lockout for failed password attempts is configured | Add deny count and unlock times for authfail" - lineinfile: - dest: /etc/pam.d/{{ item }} - state: present - regexp: '^auth required pam_faillock.so authfail' - line: "auth required pam_faillock.so authfail deny={{ rhel9cis_pam_faillock.attempts }}{{ (rhel9cis_pam_faillock.fail_for_root) | ternary(' even_deny_root ',' ') }}unlock_time={{ rhel9cis_pam_faillock.unlock_time }}" - insertafter: '^#?auth ?' - with_items: - - "system-auth" - - "password-auth" - when: rhel9cis_rule_5_4_2 - - - name: | - "5.4.3 | L1 | PATCH | Ensure password reuse is limited | Set system-auth remember remember settings - 5.4.4 | L1 | PATCH | Ensure password hashing algorithm is SHA-512 | Set system-auth pwhash settings" - lineinfile: - dest: /etc/pam.d/system-auth - state: present - regexp: '^password sufficient pam_unix.so' - line: "password sufficient pam_unix.so {{ rhel9cis_pam_faillock.pwhash }} shadow try_first_pass use_authtok remember={{ rhel9cis_pam_faillock.remember }}" - insertafter: '^#?password ?' - when: - - rhel9cis_rule_5_4_3 or - rhel9cis_rule_5_4_4 - - - name: "5.4.4 | L1 | PATCH | Ensure password hashing algorithm is SHA-512 | Set system-auth pwhash settings" - lineinfile: - dest: /etc/pam.d/password-auth - state: present - regexp: '^password sufficient pam_unix.so' - line: "password sufficient pam_unix.so {{ rhel9cis_pam_faillock.pwhash }} shadow try_first_pass use_authtok" - insertafter: '^#?password ?' - when: rhel9cis_rule_5_4_4 - - # The two steps below were added to keep authconfig from overwritting the above configs. This follows steps from here: https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/html/security_guide/chap-hardening_your_system_with_tools_and_services - # With the steps below you will score five (5) points lower due to false positive results - - name: | - "5.4.1 | L1 | PATCH | Ensure password creation requirements are configured - 5.4.2 | L1 | PATCH | Ensure lockout for failed password attempts is configured - 5.4.3 | L1 | PATCH | Ensure password reuse is limited - 5.4.4 | L1 | PATCH | Ensure password hashing algorithm is SHA-512" - copy: - src: /etc/pam.d/{{ item }} - dest: /etc/pam.d/{{ item }}-local - remote_src: true - owner: root - group: root - mode: '0644' - with_items: - - "system-auth" - - "password-auth" - - - name: | - "5.4.1 | L1 | PATCH | Ensure password creation requirements are configured - 5.4.2 | L1 | PATCH | Ensure lockout for failed password attempts is configured - 5.4.3 | L1 | PATCH | Ensure password reuse is limited - 5.4.4 | L1 | PATCH | Ensure password hashing algorithm is SHA-512" - file: - src: /etc/pam.d/{{ item }}-local - dest: /etc/pam.d/{{ item }} - state: link - force: true - with_items: - - "system-auth" - - "password-auth" + - name: "5.4.1 | PATCH | Ensure custom authselect profile is used | Create custom profiles" + shell: authselect create-profile {{ rhel9cis_authselect['custom_profile_name'] }} -b {{ rhel9cis_authselect['default_file_to_copy'] }} + args: + warn: no + when: rhel9cis_authselect_custom_profile_create when: - - rhel9cis_rule_5_4_1 or - rhel9cis_rule_5_4_2 or - rhel9cis_rule_5_4_3 or - rhel9cis_rule_5_4_4 + - rhel9cis_rule_5_4_1 tags: - level1-server - level1-workstation + - manual - patch + - authselect - rule_5.4.1 + +- name: "5.4.2 | PATCH | Ensure authselect includes with-faillock" + block: + - name: "5.4.2 | AUDIT | Ensure authselect includes with-faillock | Gather profiles and enabled features" + shell: "authselect current | grep with-faillock" + failed_when: false + changed_when: false + check_mode: no + register: rhel9cis_5_4_2_profiles_faillock + + - name: "5.4.2 | AUDIT | Ensure authselect includes with-faillock| Show profiles" + debug: + msg: + - "Below are the current custom profiles" + - "{{ rhel9cis_5_4_2_profiles_faillock.stdout_lines }}" + + - name: "5.4.2 | PATCH | Ensure authselect includes with-faillock | Create custom profiles" + shell: "authselect select custom/{{ rhel9cis_authselect['custom_profile_name'] }} with-faillock" + args: + warn: no + when: rhel9cis_authselect_custom_profile_select + when: + - rhel9cis_rule_5_4_2 + tags: + - level1-server + - level1-workstation + - automated + - patch + - authselect - rule_5.4.2 - - rule_5.4.3 - - rule_5.4.4 diff --git a/tasks/section_5/cis_5.5.1.x.yml b/tasks/section_5/cis_5.5.1.x.yml deleted file mode 100644 index c7486e1..0000000 --- a/tasks/section_5/cis_5.5.1.x.yml +++ /dev/null @@ -1,131 +0,0 @@ ---- - -- name: "5.5.1.1 | L1 | PATCH | Ensure password expiration is 365 days or less" - lineinfile: - state: present - dest: /etc/login.defs - regexp: '^PASS_MAX_DAYS' - line: "PASS_MAX_DAYS {{ rhel9cis_pass['max_days'] }}" - when: - - rhel9cis_rule_5_5_1_1 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.5.1.1 - -- name: "5.5.1.2 | L1 | PATCH | Ensure minimum days between password changes is 7 or more" - lineinfile: - state: present - dest: /etc/login.defs - regexp: '^PASS_MIN_DAYS' - line: "PASS_MIN_DAYS {{ rhel9cis_pass['min_days'] }}" - when: - - rhel9cis_rule_5_5_1_2 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.5.1.2 - -- name: "5.5.1.3 | L1 | PATCH | Ensure password expiration warning days is 7 or more" - lineinfile: - state: present - dest: /etc/login.defs - regexp: '^PASS_WARN_AGE' - line: "PASS_WARN_AGE {{ rhel9cis_pass['warn_age'] }}" - when: - - rhel9cis_rule_5_5_1_3 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.5.1.3 - -- name: "5.5.1.4 | L1 | PATCH | Ensure inactive password lock is 30 days or less" - block: - - name: "5.5.1.4 | L1 | AUDIT | Ensure inactive password lock is 30 days or less | Check current settings" - shell: useradd -D | grep INACTIVE={{ rhel9cis_inactivelock.lock_days }} | cut -f2 -d= - args: - warn: false - changed_when: false - failed_when: false - check_mode: false - register: rhel9cis_5_5_1_4_inactive_settings - - - name: "5.5.1.4 | L1 | PATCH | Ensure inactive password lock is 30 days or less | Set default inactive setting" - shell: useradd -D -f {{ rhel9cis_inactivelock.lock_days }} - args: - warn: false - when: rhel9cis_5_5_1_4_inactive_settings.stdout | length == 0 - - - name: "5.5.1.4 | L1 | AUDIT | Ensure inactive password lock is 30 days or less | Getting user list" - shell: 'egrep ^[^:]+:[^\!*] /etc/shadow | cut -d: -f1' - args: - warn: false - check_mode: false - register: rhel_09_5_5_1_4_audit - changed_when: false - - - name: "5.5.1.4 | L1 | PATCH | Ensure inactive password lock is 30 days or less | Apply Inactive setting to existing accounts" - shell: chage --inactive {{ rhel9cis_inactivelock.lock_days }} "{{ item }}" - args: - warn: false - with_items: - - "{{ rhel_09_5_5_1_4_audit.stdout_lines }}" - when: - - rhel9cis_rule_5_5_1_4 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.5.1.4 - -- name: "5.5.1.5 | L1 | PATCH | Ensure all users last password change date is in the past" - block: - - name: "5.5.1.5 | L1 | AUDIT | Ensure all users last password change date is in the past | Get current date in Unix Time" - shell: echo $(($(date --utc --date "$1" +%s)/86400)) - args: - warn: false - failed_when: false - changed_when: false - check_mode: false - register: rhel9cis_5_5_1_5_currentut - - - name: "5.5.1.5 | L1 | AUDIT | Ensure all users last password change date is in the past | Get list of users with last changed pw date in the future" - shell: "cat /etc/shadow | awk -F: '{if($3>{{ rhel9cis_5_5_1_5_currentut.stdout }})print$1}'" - args: - warn: false - changed_when: false - failed_when: false - check_mode: false - register: rhel9cis_5_5_1_5_user_list - - - name: "5.5.1.5 | L1 | AUDIT | Ensure all users last password change date is in the past | Alert no pw change in the future exist" - debug: - msg: "Good News! All accounts have PW change dates that are in the past" - when: rhel9cis_5_5_1_5_user_list.stdout | length == 0 - - - name: "5.5.1.5 | L1 | AUDIT | Ensure all users last password change date is in the past | Alert on accounts with pw change in the future" - debug: - msg: "Warning! The following accounts have the last PW change date in the future: {{ rhel9cis_5_5_1_5_user_list.stdout_lines }}" - when: - - rhel9cis_5_5_1_5_user_list.stdout | length > 0 - - not rhel9cis_futurepwchgdate_autofix - - - name: "5.5.1.5 | L1 | PATCH | Ensure all users last password change date is in the past | Fix accounts with pw change in the future" - shell: passwd --expire {{ item }} - args: - warn: false - when: - - rhel9cis_5_5_1_5_user_list | length > 0 - - rhel9cis_futurepwchgdate_autofix - with_items: - - "{{ rhel9cis_5_5_1_5_user_list.stdout_lines }}" - when: - - rhel9cis_rule_5_5_1_5 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.5.1.5 diff --git a/tasks/section_5/cis_5.5.x.yml b/tasks/section_5/cis_5.5.x.yml index ebed1bd..8c5d301 100644 --- a/tasks/section_5/cis_5.5.x.yml +++ b/tasks/section_5/cis_5.5.x.yml @@ -1,8 +1,8 @@ --- -- name: "5.5.2 | L1 | PATCH | Ensure system accounts are secured" +- name: "5.5.2 | PATCH | Ensure system accounts are secured" block: - - name: "5.5.2 | L1 | Ensure system accounts are secured | Set nologin" + - name: "5.5.2 | Ensure system accounts are secured | Set nologin" user: name: "{{ item.id }}" shell: /usr/sbin/nologin @@ -13,11 +13,11 @@ - item.id != "sync" - item.id != "shutdown" - item.id != "halt" - - item.uid < 1000 + - rhel9cis_int_gid | int > item.gid - item.shell != " /bin/false" - item.shell != " /usr/sbin/nologin" - - name: "5.5.2 | L1 | PATCH | Ensure system accounts are secured | Lock accounts" + - name: "5.5.2 | PATCH | Ensure system accounts are secured | Lock accounts" user: name: "{{ item.id }}" password_lock: true @@ -28,7 +28,7 @@ - item.id != "shutdown" - item.id != "sync" - item.id != "root" - - min_int_uid | int >= item.uid + - rhel9cis_int_gid | int > item.gid - item.shell != " /bin/false" - item.shell != " /usr/sbin/nologin" when: @@ -39,15 +39,15 @@ - patch - rule_5.5.2 -- name: "5.5.3 | L1 | PATCH | Ensure default user shell timeout is 900 seconds or less" +- name: "5.5.3 | PATCH | Ensure default user shell timeout is 900 seconds or less" blockinfile: - create: true + create: yes mode: 0644 dest: "{{ item.dest }}" state: "{{ item.state }}" marker: "# {mark} ANSIBLE MANAGED" block: | - # Set session timeout - CIS ID RHEL-09-5.4.5 + # Set session timeout - CIS ID RHEL-08-5.4.5 TMOUT={{ rhel9cis_shell_session_timeout.timeout }} export TMOUT readonly TMOUT @@ -62,10 +62,8 @@ - patch - rule_5.5.3 -- name: "5.5.4 | L1 | PATCH | Ensure default group for the root account is GID 0" - shell: usermod -g 0 root - args: - warn: false +- name: "5.5.4 | PATCH | Ensure default group for the root account is GID 0" + command: usermod -g 0 root changed_when: false failed_when: false when: @@ -76,15 +74,15 @@ - patch - rule_5.5.4 -- name: "5.5.5 | L1 | PATCH | Ensure default user umask is 027 or more restrictive" +- name: "5.5.5 | PATCH | Ensure default user umask is 027 or more restrictive" block: - - name: "5.5.5 | L1 | PATCH | Ensure default user umask is 027 or more restrictive | Set umask for /etc/bashrc" + - name: "5.5.5 | PATCH | Ensure default user umask is 027 or more restrictive | Set umask for /etc/bashrc" replace: path: /etc/bashrc regexp: '(^\s+umask) 0[012][0-6]' replace: '\1 027' - - name: "5.5.5 | L1 | PATCH | Ensure default user umask is 027 or more restrictive | Set umask for /etc/profile" + - name: "5.5.5 | PATCH | Ensure default user umask is 027 or more restrictive | Set umask for /etc/profile" replace: path: /etc/profile regexp: '(^\s+umask) 0[012][0-6]' diff --git a/tasks/section_5/cis_5.6.1.x.yml b/tasks/section_5/cis_5.6.1.x.yml new file mode 100644 index 0000000..744c6d6 --- /dev/null +++ b/tasks/section_5/cis_5.6.1.x.yml @@ -0,0 +1,125 @@ +--- + +- name: "5.6.1.1 | PATCH | Ensure password expiration is 365 days or less" + lineinfile: + state: present + dest: /etc/login.defs + regexp: '^PASS_MAX_DAYS' + line: "PASS_MAX_DAYS {{ rhel9cis_pass['max_days'] }}" + when: + - rhel9cis_rule_5_6_1_1 + tags: + - level1-server + - level1-workstation + - automated + - patch + - password + - rule_5.5.1.1 + +- name: "5.6.1.2 | PATCH | Ensure minimum days between password changes is 7 or more" + lineinfile: + state: present + dest: /etc/login.defs + regexp: '^PASS_MIN_DAYS' + line: "PASS_MIN_DAYS {{ rhel9cis_pass['min_days'] }}" + when: + - rhel9cis_rule_5_6_1_2 + tags: + - level1-server + - level1-workstation + - automated + - patch + - password + - rule_5.6.1.2 + +- name: "5.6.1.3 | PATCH | Ensure password expiration warning days is 7 or more" + lineinfile: + state: present + dest: /etc/login.defs + regexp: '^PASS_WARN_AGE' + line: "PASS_WARN_AGE {{ rhel9cis_pass['warn_age'] }}" + when: + - rhel9cis_rule_5_6_1_3 + tags: + - level1-server + - level1-workstation + - automated + - patch + - password + - rule_5.5.1.3 + +- name: "5.6.1.4 | PATCH | Ensure inactive password lock is 30 days or less" + block: + - name: "5.6.1.4 | AUDIT | Ensure inactive password lock is 30 days or less | Check current settings" + shell: useradd -D | grep INACTIVE={{ rhel9cis_inactivelock.lock_days }} | cut -f2 -d= + changed_when: false + failed_when: false + check_mode: no + register: rhel9cis_5_6_1_4_inactive_settings + + - name: "5.6.1.4 | PATCH | Ensure inactive password lock is 30 days or less | Set default inactive setting" + command: useradd -D -f {{ rhel9cis_inactivelock.lock_days }} + when: rhel9cis_5_6_1_4_inactive_settings.stdout | length == 0 + + - name: "5.6.1.4 | AUDIT | Ensure inactive password lock is 30 days or less | Getting user list" + shell: 'egrep ^[^:]+:[^\!*] /etc/shadow | cut -d: -f1' + changed_when: false + check_mode: no + register: rhel_8_5_6_1_4_user_list + + - name: "5.6.1.4 | PATCH | Ensure inactive password lock is 30 days or less | Apply Inactive setting to existing accounts" + command: chage --inactive {{ rhel9cis_inactivelock.lock_days }} "{{ item }}" + with_items: + - "{{ rhel_8_5_6_1_4_user_list.stdout_lines }}" + when: + - rhel9cis_rule_5_6_1_4 + tags: + - level1-server + - level1-workstation + - automated + - patch + - password + - rule_5.6.1.4 + +- name: "5.6.1.5 | PATCH | Ensure all users last password change date is in the past" + block: + - name: "5.6.1.5 | AUDIT | Ensure all users last password change date is in the past | Get current date in Unix Time" + shell: echo $(($(date --utc --date "$1" +%s)/86400)) + changed_when: false + failed_when: false + check_mode: no + register: rhel9cis_5_6_1_5_currentut + + - name: "5.6.1.5 | AUDIT | Ensure all users last password change date is in the past | Get list of users with last changed pw date in the future" + shell: "cat /etc/shadow | awk -F: '{if($3>{{ rhel9cis_5_6_1_5_currentut.stdout }})print$1}'" + changed_when: false + failed_when: false + check_mode: no + register: rhel9cis_5_6_1_5_user_list + + - name: "5.6.1.5 | AUDIT | Ensure all users last password change date is in the past | Alert no pw change in the future exist" + debug: + msg: "Good News! All accounts have PW change dates that are in the past" + when: rhel9cis_5_6_1_5_user_list.stdout | length == 0 + + - name: "5.6.1.5 | AUDIT | Ensure all users last password change date is in the past | Alert on accounts with pw change in the future" + debug: + msg: "Warning! The following accounts have the last PW change date in the future: {{ rhel9cis_5_6_1_5_user_list.stdout_lines }}" + when: + - rhel9cis_5_6_1_5_user_list.stdout | length > 0 + - not rhel9cis_futurepwchgdate_autofix + + - name: "5.6.1.5 | PATCH | Ensure all users last password change date is in the past | Fix accounts with pw change in the future" + command: passwd --expire {{ item }} + when: + - rhel9cis_5_6_1_5_user_list | length > 0 + - rhel9cis_futurepwchgdate_autofix + with_items: + - "{{ rhel9cis_5_6_1_5_user_list.stdout_lines }}" + when: + - rhel9cis_rule_5_6_1_5 + tags: + - level1-server + - level1-workstation + - patch + - rule_5.5.1.5 diff --git a/tasks/section_5/cis_5.6.x.yml b/tasks/section_5/cis_5.6.x.yml new file mode 100644 index 0000000..3d9cf32 --- /dev/null +++ b/tasks/section_5/cis_5.6.x.yml @@ -0,0 +1,108 @@ +--- + +- name: "5.6.2 | PATCH | Ensure system accounts are secured" + block: + - name: "5.6.2 | Ensure system accounts are secured | Set nologin" + user: + name: "{{ item.id }}" + shell: /usr/sbin/nologin + with_items: + - "{{ rhel9cis_passwd }}" + when: + - item.id != "root" + - item.id != "sync" + - item.id != "shutdown" + - item.id != "halt" + - rhel9cis_int_gid | int < item.gid + - item.shell != " /bin/false" + - item.shell != " /usr/sbin/nologin" + loop_control: + label: "{{ item.id }}" + + - name: "5.6.2 | PATCH | Ensure system accounts are secured | Lock accounts" + user: + name: "{{ item.id }}" + password_lock: true + with_items: + - "{{ rhel9cis_passwd }}" + when: + - item.id != "halt" + - item.id != "shutdown" + - item.id != "sync" + - item.id != "root" + - rhel9cis_int_gid | int < item.gid + - item.shell != " /bin/false" + - item.shell != " /usr/sbin/nologin" + loop_control: + label: "{{ item.id }}" + when: + - rhel9cis_rule_5_6_2 + tags: + - level1-server + - level1-workstation + - automated + - patch + - accounts + - rule_5.6.2 + +- name: "5.6.3 | PATCH | Ensure default user shell timeout is 900 seconds or less" + blockinfile: + create: yes + mode: 0644 + dest: "{{ item.dest }}" + state: "{{ item.state }}" + marker: "# {mark} ANSIBLE MANAGED" + block: | + # Set session timeout - CIS ID RHEL-08-5.4.5 + TMOUT={{ rhel9cis_shell_session_timeout.timeout }} + export TMOUT + readonly TMOUT + with_items: + - { dest: "{{ rhel9cis_shell_session_timeout.file }}", state: present } + - { dest: /etc/profile, state: "{{ (rhel9cis_shell_session_timeout.file == '/etc/profile') | ternary('present', 'absent') }}" } + when: + - rhel9cis_rule_5_6_3 + tags: + - level1-server + - level1-workstation + - automated + - patch + - accounts + - rule_5.6.3 + +- name: "5.6.4 | PATCH | Ensure default group for the root account is GID 0" + command: usermod -g 0 root + changed_when: false + failed_when: false + when: + - rhel9cis_rule_5_6_4 + tags: + - level1-server + - level1-workstation + - automated + - patch + - accounts + - rule_5.6.4 + +- name: "5.6.5 | PATCH | Ensure default user umask is 027 or more restrictive" + block: + - name: "5.6.5 | PATCH | Ensure default user umask is 027 or more restrictive | Set umask for /etc/bashrc" + replace: + path: /etc/bashrc + regexp: '(^\s+umask) 0[012][0-6]' + replace: '\1 027' + + - name: "5.6.5 | PATCH | Ensure default user umask is 027 or more restrictive | Set umask for /etc/profile" + replace: + path: /etc/profile + regexp: '(^\s+umask) 0[012][0-6]' + replace: '\1 027' + when: + - rhel9cis_rule_5_6_5 + tags: + - level1-server + - level1-workstation + - automated + - patch + - accounts + - rule_5.6.5 diff --git a/tasks/section_5/cis_5.6.yml b/tasks/section_5/cis_5.6.yml deleted file mode 100644 index 6262c3c..0000000 --- a/tasks/section_5/cis_5.6.yml +++ /dev/null @@ -1,37 +0,0 @@ ---- - -# this will just display the list of consoles. The site will need to confirm the allowed consoles are correct and change manually if needed. -- name: "5.6 | L1 | AUDIT | Ensure root login is restricted to system console" - block: - - name: "5.6 | L1 | AUDIT | Ensure root login is restricted to system console | Check if securetty file exists" - stat: - path: /etc/securetty - register: rhel9cis_securetty_check - - - name: "5.6 | L1 | AUDIT | Ensure root login is restricted to system console | Capture consoles" - shell: cat /etc/securetty - args: - warn: false - changed_when: false - register: rhel_09_5_6_audit - when: rhel9cis_securetty_check.stat.exists - - - name: "5.6 | L1 | AUDIT |Ensure root login is restricted to system console | Display Console" - debug: - msg: - - "These are the consoles with root login access, please review:" - - "{{ rhel_09_5_6_audit.stdout_lines }}" - when: rhel9cis_securetty_check.stat.exists - - - name: "5.6 | L1 | AUDIT | Ensure root login is restricted to system console | Display that no securetty file exists" - debug: - msg: - - "There is no /etc/securetty file, this has been removed by default in RHEL9" - when: not rhel9cis_securetty_check.stat.exists - when: - - rhel9cis_rule_5_6 - tags: - - level1-server - - level1-workstation - - audit - - rule_5.6 diff --git a/tasks/section_5/cis_5.7.yml b/tasks/section_5/cis_5.7.yml deleted file mode 100644 index 9e7bbec..0000000 --- a/tasks/section_5/cis_5.7.yml +++ /dev/null @@ -1,22 +0,0 @@ ---- - -- name: "5.7 | L1 | PATCH | Ensure access to the su command is restricted" - block: - - name: "5.7 | L1 | PATCH | Ensure access to the su command is restricted | Setting pam_wheel to use_uid" - lineinfile: - state: present - dest: /etc/pam.d/su - regexp: '^(#)?auth\s+required\s+pam_wheel\.so' - line: 'auth required pam_wheel.so use_uid {% if rhel9cis_sugroup is defined %}group={{ rhel9cis_sugroup }}{% endif %}' - - - name: "5.7 | L1 | PATCH | Ensure access to the su command is restricted | wheel group contains root" - user: - name: "{{ rhel9cis_sugroup_users }}" - groups: "{{ rhel9cis_sugroup | default('wheel') }}" - when: - - rhel9cis_rule_5_7 - tags: - - level1-server - - level1-workstation - - patch - - rule_5.7 diff --git a/tasks/section_5/main.yml b/tasks/section_5/main.yml index 08e5c45..b7db859 100644 --- a/tasks/section_5/main.yml +++ b/tasks/section_5/main.yml @@ -1,5 +1,7 @@ --- +# Access, Authentication, and Authorization + - name: "SECTION | 5.1 | Configure time-based job schedulers" import_tasks: cis_5.1.x.yml @@ -8,22 +10,17 @@ when: - "'openssh-server' in ansible_facts.packages" -- name: "SECTION | 5.3 | Configure Profiles" +- name: "SECTION | 5.3 | Configure privilege escalation" include_tasks: cis_5.3.x.yml - when: - - rhel9cis_use_authconfig -- name: "SECTION | 5.4 | Configure PAM " +- name: "SECTION | 5.4 | Configure authselect" import_tasks: cis_5.4.x.yml -- name: "SECTION | 5.5.1.x | Passwords and Accounts" - import_tasks: cis_5.5.1.x.yml - -- name: "SECTION | 5.5.x | System Accounts and User Settings" +- name: "SECTION | 5.5 | Configure PAM " import_tasks: cis_5.5.x.yml -- name: "SECTION | 5.6 | Root Login" - import_tasks: cis_5.6.yml +- name: "SECTION | 5.6.1.x | Shadow Password Suite Parameters" + import_tasks: cis_5.6.1.x.yml -- name: Section | 5.7 | su Command Restriction - import_tasks: cis_5.7.yml +- name: "SECTION | 5.6.x | Misc. User Account Settings" + import_tasks: cis_5.6.x.yml diff --git a/tasks/section_6/cis_6.1.x.yml b/tasks/section_6/cis_6.1.x.yml index c596ed1..be85af0 100644 --- a/tasks/section_6/cis_6.1.x.yml +++ b/tasks/section_6/cis_6.1.x.yml @@ -1,30 +1,30 @@ --- -- name: "6.1.1 | L2 | AUDIT | Audit system file permissions" +- name: "6.1.1 | AUDIT | Audit system file permissions" block: - - name: "6.1.1 | L2 | AUDIT | Audit system file permissions | Audit the packages" + - name: "6.1.1 | AUDIT | Audit system file permissions | Audit the packages" shell: rpm -Va --nomtime --nosize --nomd5 --nolinkto args: - warn: false + warn: no changed_when: false failed_when: false register: rhel9cis_6_1_1_packages_rpm - - name: "6.1.1 | L2 | AUDIT | Audit system file permissions | Create list and warning" + - name: "6.1.1 | AUDIT | Audit system file permissions | Create list and warning" block: - - name: "6.1.1 | L2 | Audit system file permissions | Add file discrepancy list to system" + - name: "6.1.1 | Audit system file permissions | Add file discrepancy list to system" copy: dest: "{{ rhel9cis_rpm_audit_file }}" content: "{{ rhel9cis_6_1_1_packages_rpm.stdout }}" - - name: "6.1.1 | L2 | AUDIT | Audit system file permissions | Message out alert for package descrepancies" + - name: "6.1.1 | AUDIT | Audit system file permissions | Message out alert for package descrepancies" debug: msg: | "Warning! You have some package descrepancies issues. The file list can be found in {{ rhel9cis_rpm_audit_file }}" when: rhel9cis_6_1_1_packages_rpm.stdout|length > 0 - - name: "6.1.1 | L2 | AUDIT | Audit system file permissions | Message out no package descrepancies" + - name: "6.1.1 | AUDIT | Audit system file permissions | Message out no package descrepancies" debug: msg: "Good News! There are no package descrepancies" when: rhel9cis_6_1_1_packages_rpm.stdout|length == 0 @@ -33,26 +33,32 @@ tags: - level2-server - level2-workstation + - manual - audit + - permissions - rule_6.1.1 -- name: "6.1.2 | L1 | PATCH | Ensure permissions on /etc/passwd are configured" - file: - dest: /etc/passwd - owner: root - group: root - mode: 0644 +- name: "6.1.2 | PATCH | Ensure sticky bit is set on all world-writable directories" + shell: df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type d -perm -0002 2>/dev/null | xargs chmod a+t + args: + warn: no + changed_when: false + failed_when: false when: - rhel9cis_rule_6_1_2 tags: + - skip_ansible_lint - level1-server - level1-workstation + - automated - patch - - rule_6.1.2 + - stickybits + - permissons + - rule_1.1.21 -- name: "6.1.3 | L1 | PATCH | Ensure permissions on /etc/passwd- are configured" +- name: "6.1.3 | PATCH | Ensure permissions on /etc/passwd are configured" file: - dest: /etc/passwd- + dest: /etc/passwd owner: root group: root mode: 0644 @@ -61,10 +67,12 @@ tags: - level1-server - level1-workstation + - automated - patch + - permissions - rule_6.1.3 -- name: "6.1.4 | L1 | PATCH | Ensure permissions on /etc/shadow are configured" +- name: "6.1.4 | PATCH | Ensure permissions on /etc/shadow are configured" file: dest: /etc/shadow owner: root @@ -75,24 +83,28 @@ tags: - level1-server - level1-workstation + - automated - patch + - permissions - rule_6.1.4 -- name: "6.1.5 | L1 | PATCH | Ensure permissions on /etc/shadow- are configured" +- name: "6.1.5 | PATCH | Ensure permissions on /etc/group are configured" file: - dest: /etc/shadow- + dest: /etc/group- owner: root group: root - mode: 0000 + mode: 0644 when: - rhel9cis_rule_6_1_5 tags: - level1-server - level1-workstation + - automated - patch + - permissions - rule_6.1.5 -- name: "6.1.6 | L1 | PATCH | Ensure permissions on /etc/gshadow are configured" +- name: "6.1.6 | PATCH | Ensure permissions on /etc/gshadow are configured" file: dest: /etc/gshadow owner: root @@ -103,38 +115,44 @@ tags: - level1-server - level1-workstation + - automated - patch + - permissions - rule_6.1.6 -- name: "6.1.7 | L1 | PATCH | Ensure permissions on /etc/gshadow- are configured" +- name: "6.1.7 | PATCH | Ensure permissions on /etc/passwd- are configured" file: - dest: /etc/gshadow- + dest: /etc/passwd- owner: root group: root - mode: 0000 + mode: 0644 when: - rhel9cis_rule_6_1_7 tags: - level1-server - level1-workstation + - autoamted - patch + - permissions - rule_6.1.7 -- name: "6.1.8 | L1 | PATCH | Ensure permissions on /etc/group are configured" +- name: "6.1.6 | PATCH | Ensure permissions on /etc/shadow- are configured" file: - dest: /etc/group- + dest: /etc/shadow- owner: root group: root - mode: 0644 + mode: 0000 when: - - rhel9cis_rule_6_1_8 + - rhel9cis_rule_6_1_6 tags: - level1-server - level1-workstation + - automated - patch - - rule_6.1.8 + - permissions + - rule_6.1.6 -- name: "6.1.9 | L1 | PATCH | Ensure permissions on /etc/group- are configured" +- name: "6.1.9 | PATCH | Ensure permissions on /etc/group- are configured" file: dest: /etc/group- owner: root @@ -145,87 +163,78 @@ tags: - level1-server - level1-workstation + - automated - patch + - permissionss - rule_6.1.9 -- name: "6.1.10 | L1 | PATCH | Ensure no world writable files exist" - block: - - name: "6.1.10 | L1 | AUDIT | Ensure no world writable files exist | Get list of world-writable files" - shell: df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type f -perm -0002 - args: - warn: false - failed_when: false - changed_when: false - register: rhel_09_6_1_10_perms_results - - - name: "6.1.10 | L1 | AUDIT | Ensure no world writable files exist | Alert no world-writable files exist" - debug: - msg: "Good news! We have not found any world-writable files on your system" - when: - - rhel_09_6_1_10_perms_results.stdout is not defined - - - name: "6.1.10 | L1 | PATCH | Ensure no world writable files exist | Adjust world-writable files if they exist (Configurable)" - file: - path: '{{ item }}' - mode: o-w - state: touch - with_items: "{{ rhel_09_6_1_10_perms_results.stdout_lines }}" - when: - - rhel_09_6_1_10_perms_results.stdout_lines is defined - - rhel9cis_no_world_write_adjust +- name: "6.1.10 | PATCH | Ensure permissions on /etc/gshadow- are configured" + file: + dest: /etc/gshadow- + owner: root + group: root + mode: 0000 when: - rhel9cis_rule_6_1_10 tags: - level1-server - level1-workstation + - automated - patch + - permissions - rule_6.1.10 -- name: "6.1.11 | L1 | AUDIT | Ensure no unowned files or directories exist" +- name: "6.1.11 | PATCH | Ensure no world writable files exist" block: - - name: "6.1.11 | L1 | AUDIT | Ensure no unowned files or directories exist | Finding all unowned files or directories" - shell: find "{{ item.mount }}" -xdev -nouser - args: - warn: false - check_mode: false + - name: "6.1.11 | AUDIT | Ensure no world writable files exist | Get list of world-writable files" + shell: df --local -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type f -perm -0002 failed_when: false changed_when: false - with_items: "{{ ansible_mounts }}" - register: rhel_09_6_1_11_audit - when: item['device'].startswith('/dev') and not 'bind' in item['options'] + register: rhel_08_6_1_11_perms_results - - name: "6.1.11 | L1 | AUDIT | Ensure no unowned files or directories exist | Displaying any unowned files or directories" + - name: "6.1.11 | AUDIT | Ensure no world writable files exist | Alert no world-writable files exist" debug: - msg: "Manual intervention is required -- missing owner on items in {{ item.item.mount }}: {{ item.stdout_lines | join(', ') }}" - with_items: "{{ rhel_09_6_1_11_audit.results }}" + msg: "Good news! We have not found any world-writable files on your system" when: - - item.stdout_lines is defined - - item.stdout_lines | length > 0 + - rhel_08_6_1_11_perms_results.stdout is not defined + + - name: "6.1.11 | PATCH | Ensure no world writable files exist | Adjust world-writable files if they exist (Configurable)" + file: + path: '{{ item }}' + mode: o-w + state: touch + with_items: "{{ rhel_08_6_1_11_perms_results.stdout_lines }}" + when: + - rhel_08_6_1_11_perms_results.stdout_lines is defined + - rhel9cis_no_world_write_adjust when: - rhel9cis_rule_6_1_11 tags: - level1-server - level1-workstation - - audit + - automated + - patch + - files + - permissions - rule_6.1.11 -- name: "6.1.12 | L1 | AUDIT | Ensure no ungrouped files or directories exist" +- name: "6.1.12 | AUDIT | Ensure no unowned files or directories exist" block: - - name: "6.1.12 | L1 | AUDIT | Ensure no ungrouped files or directories exist | Finding all ungrouped files or directories" - shell: find "{{ item.mount }}" -xdev -nogroup - args: - warn: false - check_mode: false - failed_when: false + - name: "6.1.12 | AUDIT | Ensure no unowned files or directories exist | Finding all unowned files or directories" + command: find "{{ item.mount }}" -xdev -nouser changed_when: false - register: rhel_09_6_1_12_audit + failed_when: false + check_mode: false + register: rhel_08_6_1_12_audit with_items: "{{ ansible_mounts }}" + loop_control: + label: "{{ item.mount }}" when: item['device'].startswith('/dev') and not 'bind' in item['options'] - - name: "6.1.12 | L1 | AUDIT | Ensure no ungrouped files or directories exist | Displaying all ungrouped files or directories" + - name: "6.1.12 | AUDIT | Ensure no unowned files or directories exist | Displaying any unowned files or directories" debug: - msg: "Manual intervention is required -- missing group on items in {{ item.item.mount }}: {{ item.stdout_lines | join(', ') }}" - with_items: "{{ rhel_09_6_1_12_audit.results }}" + msg: "Manual intervention is required -- missing owner on items in {{ item.item.mount }}: {{ item.stdout_lines | join(', ') }}" + with_items: "{{ rhel_08_6_1_12_audit.results }}" when: - item.stdout_lines is defined - item.stdout_lines | length > 0 @@ -234,71 +243,109 @@ tags: - level1-server - level1-workstation - - patch + - automated + - audit + - files + - permissions - rule_6.1.12 -- name: "6.1.13 | L1 | AUDIT | Audit SUID executables" +- name: "6.1.13 | AUDIT | Ensure no ungrouped files or directories exist" block: - - name: "6.1.13 | L1 | AUDIT | Audit SUID executables | Find all SUID executables" - shell: df {{ item.mount }} -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type f -perm -4000 - args: - warn: false + - name: "6.1.13 | AUDIT | Ensure no ungrouped files or directories exist | Finding all ungrouped files or directories" + command: find "{{ item.mount }}" -xdev -nogroup + check_mode: false failed_when: false changed_when: false - register: rhel_09_6_1_13_perms_results + register: rhel_08_6_1_13_audit with_items: "{{ ansible_mounts }}" + loop_control: + label: "{{ item.mount }}" + when: item['device'].startswith('/dev') and not 'bind' in item['options'] - - name: "6.1.13 | L1 | AUDIT | Audit SUID executables | Alert no SUID executables exist" + - name: "6.1.13 | AUDIT | Ensure no ungrouped files or directories exist | Displaying all ungrouped files or directories" debug: - msg: "Good news! We have not found any SUID executable files on your system" - failed_when: false - changed_when: false + msg: "Manual intervention is required -- missing group on items in {{ item.item.mount }}: {{ item.stdout_lines | join(', ') }}" + with_items: "{{ rhel_08_6_1_13_audit.results }}" when: - - rhel_09_6_1_13_perms_results.stdout is not defined - - - name: "6.1.13 | L1 | AUDIT | Audit SUID executables | Alert SUID executables exist" - debug: - msg: "Manual intervention is required -- SUID set on items in {{ item.item.mount }}: {{ item.stout_lines | join(', ') }}" - with_items: "{{ rhel_09_6_1_13_perms_results.stdout_lines }}" - when: - - rhel_09_6_1_13_perms_results.stdout is defined + - item.stdout_lines is defined + - item.stdout_lines | length > 0 when: - rhel9cis_rule_6_1_13 tags: - level1-server - level1-workstation + - automated - audit + - files + - permissions - rule_6.1.13 -- name: "6.1.14 | L1 | AUDIT | Audit SGID executables" +- name: "6.1.14 | AUDIT | Audit SUID executables" block: - - name: "6.1.14 | L1 | AUDIT | Audit SGID executables | Find all SGID executables" - shell: df {{ item.mount }} -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type f -perm -2000 - args: - warn: false + - name: "6.1.14 | AUDIT | Audit SUID executables | Find all SUID executables" + shell: df {{ item.mount }} -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type f -perm -4000 failed_when: false changed_when: false - register: rhel_09_6_1_14_perms_results + register: rhel_08_6_1_14_perms_results with_items: "{{ ansible_mounts }}" + loop_control: + label: "{{ item.mount }}" - - name: "6.1.14 | L1 | AUDIT | Audit SGID executables | Alert no SGID executables exist" + - name: "6.1.14 | AUDIT | Audit SUID executables | Alert no SUID executables exist" debug: - msg: "Good news! We have not found any SGID executable files on your system" + msg: "Good news! We have not found any SUID executable files on your system" failed_when: false changed_when: false when: - - rhel_09_6_1_14_perms_results.stdout is not defined + - rhel_08_6_1_14_perms_results.stdout is not defined - - name: "6.1.14 | L1 | AUDIT | Audit SGID executables | Alert SGID executables exist" + - name: "6.1.14 | AUDIT | Audit SUID executables | Alert SUID executables exist" debug: - msg: "Manual intervention is required -- SGID set on items in {{ item.item.mount }}: {{ item.stout_lines | join(', ') }}" - with_items: "{{ rhel_09_6_1_14_perms_results.stdout_lines }}" + msg: "Manual intervention is required -- SUID set on items in {{ item.item.mount }}: {{ item.stout_lines | join(', ') }}" + with_items: "{{ rhel_08_6_1_14_perms_results.stdout_lines }}" when: - - rhel_09_6_1_14_perms_results.stdout is defined + - rhel_08_6_1_14_perms_results.stdout is defined when: - rhel9cis_rule_6_1_14 tags: - level1-server - level1-workstation - - patch + - manual + - audit + - files - rule_6.1.14 + +- name: "6.1.15 | AUDIT | Audit SGID executables" + block: + - name: "6.1.15 | AUDIT | Audit SGID executables | Find all SGID executables" + shell: df {{ item.mount }} -P | awk {'if (NR!=1) print $6'} | xargs -I '{}' find '{}' -xdev -type f -perm -2000 + failed_when: false + changed_when: false + register: rhel_08_6_1_15_perms_results + with_items: "{{ ansible_mounts }}" + loop_control: + label: "{{ item.mount }}" + + - name: "6.1.15 | AUDIT | Audit SGID executables | Alert no SGID executables exist" + debug: + msg: "Good news! We have not found any SGID executable files on your system" + failed_when: false + changed_when: false + when: + - rhel_08_6_1_15_perms_results.stdout is not defined + + - name: "6.1.15 | AUDIT | Audit SGID executables | Alert SGID executables exist" + debug: + msg: "Manual intervention is required -- SGID set on items in {{ item.item.mount }}: {{ item.stout_lines | join(', ') }}" + with_items: "{{ rhel_08_6_1_15_perms_results.stdout_lines }}" + when: + - rhel_08_6_1_15_perms_results.stdout is defined + when: + - rhel9cis_rule_6_1_15 + tags: + - level1-server + - level1-workstation + - manual + - audit + - files + - rule_6.1.15 diff --git a/tasks/section_6/cis_6.2.x.yml b/tasks/section_6/cis_6.2.x.yml index 7b9523b..ff2b0c3 100644 --- a/tasks/section_6/cis_6.2.x.yml +++ b/tasks/section_6/cis_6.2.x.yml @@ -1,9 +1,7 @@ --- -- name: "6.2.1 | L1 | AUDIT | Ensure password fields are not empty" - shell: passwd -l {{ item }} - args: - warn: false +- name: "6.2.1 | PATCH | Ensure password fields are not empty" + command: passwd -l {{ item }} changed_when: false failed_when: false with_items: "{{ empty_password_accounts.stdout_lines }}" @@ -13,177 +11,268 @@ tags: - level1-server - level1-workstation + - automated - patch + - accounts - rule_6.2.1 -- name: "6.2.2 | L1 | PATCH | Ensure no legacy '+' entries exist in /etc/passwd" - shell: sed -i '/^+/ d' /etc/passwd - args: - warn: false - changed_when: false - failed_when: false + +- name: "6.2.2 | AUDIT | Ensure all groups in /etc/passwd exist in /etc/group" + block: + - name: "6.2.2 | AUDIT | Ensure all groups in /etc/passwd exist in /etc/group | Check /etc/passwd entries" + shell: pwck -r | grep 'no group' | awk '{ gsub("[:\47]",""); print $2}' + changed_when: false + failed_when: false + check_mode: false + register: rhel9cis_6_2_2_passwd_gid_check + + - name: "6.2.2 | AUDIT | Ensure all groups in /etc/passwd exist in /etc/group | Print message that all groups match between passwd and group files" + debug: + msg: "Good News! There are no users that have non-existent GUIDs (Groups)" + when: rhel9cis_6_2_2_passwd_gid_check.stdout is not defined + + - name: "6.2.2 | AUDIT | Ensure all groups in /etc/passwd exist in /etc/group | Print warning about users with invalid GIDs missing GID entries in /etc/group" + debug: + msg: "WARNING: The following users have non-existent GIDs (Groups): {{ rhel9cis_6_2_2_passwd_gid_check.stdout_lines | join (', ') }}" + when: rhel9cis_6_2_2_passwd_gid_check.stdout is defined when: - rhel9cis_rule_6_2_2 tags: - level1-server - level1-workstation - - patch + - automated + - audit + - accounts + - groups - rule_6.2.2 - - skip_ansible_lint -- name: "6.2.3 | L1 | PATCH | Ensure root PATH Integrity" +- name: "6.2.3 | AUDIT Ensure no duplicate UIDs exist" block: - - name: "6.2.3 | L1 | AUDIT | Ensure root PATH Integrity | Determine empty value" + - name: "6.2.3 | AUDIT | Ensure no duplicate UIDs exist | Check for duplicate UIDs" + shell: "pwck -r | awk -F: '{if ($3 in uid) print $1 ; else uid[$3]}' /etc/passwd" + changed_when: false + failed_when: false + register: rhel9cis_6_2_3_user_uid_check + + - name: "6.2.3 | AUDIT | Ensure no duplicate UIDs exist | Print message that no duplicate UIDs exist" + debug: + msg: "Good News! There are no duplicate UID's in the system" + when: rhel9cis_6_2_3_user_uid_check.stdout is not defined + + - name: "6.2.3 | AUDIT| Ensure no duplicate UIDs exist | Print warning about users with duplicate UIDs" + debug: + msg: "Warning: The following users have UIDs that are duplicates: {{ rhel9cis_6_2_3_user_uid_check.stdout_lines }}" + when: rhel9cis_6_2_3_user_uid_check.stdout is defined + when: + - rhel9cis_rule_6_2_3 + tags: + - level1-server + - level1-workstation + - automated + - audit + - accounts + - users + - rule_6.2.3 + +- name: "6.2.4 | AUDIT | Ensure no duplicate GIDs exist" + block: + - name: "6.2.4 | AUDIT | Ensure no duplicate GIDs exist | Check for duplicate GIDs" + shell: "pwck -r | awk -F: '{if ($3 in users) print $1 ; else users[$3]}' /etc/group" + changed_when: false + failed_when: false + register: rhel9cis_6_2_4_user_user_check + + - name: "6.2.4 | AUDIT | Ensure no duplicate GIDs exist | Print message that no duplicate GID's exist" + debug: + msg: "Good News! There are no duplicate GIDs in the system" + when: rhel9cis_6_2_4_user_user_check.stdout is not defined + + - name: "6.2.4 | AUDIT | Ensure no duplicate GIDs exist | Print warning about users with duplicate GIDs" + debug: + msg: "Warning: The following groups have duplicate GIDs: {{ rhel9cis_6_2_4_user_user_check.stdout_lines }}" + when: rhel9cis_6_2_4_user_user_check.stdout is defined + when: + - rhel9cis_rule_6_2_4 + tags: + - level1-server + - level1-workstation + - automated + - audit + - accounts + - groups + - rule_6.2.4 + +- name: "6.2.5 | AUDIT | Ensure no duplicate user names exist" + block: + - name: "6.2.5 | AUDIT | Ensure no duplicate user names exist | Check for duplicate User Names" + shell: "pwck -r | awk -F: '{if ($1 in users) print $1 ; else users[$1]}' /etc/passwd" + changed_when: false + failed_when: false + register: rhel9cis_6_2_5_user_username_check + + - name: "6.2.5 | AUDIT | Ensure no duplicate user names exist | Print message that no duplicate user names exist" + debug: + msg: "Good News! There are no duplicate user names in the system" + when: rhel9cis_6_2_5_user_username_check.stdout is not defined + + - name: "6.2.5 | AUDIT | Ensure no duplicate user names exist | Print warning about users with duplicate User Names" + debug: + msg: "Warning: The following user names are duplicates: {{ rhel9cis_6_2_5_user_username_check.stdout_lines }}" + when: rhel9cis_6_2_5_user_username_check.stdout is defined + when: + - rhel9cis_rule_6_2_5 + tags: + - level1-server + - level1-workstation + - automated + - audit + - accounts + - users + - rule_6.2.5 + +- name: "6.2.6 | AUDIT |Ensure no duplicate group names exist" + block: + - name: "6.2.6 | AUDIT | Ensure no duplicate group names exist | Check for duplicate group names" + shell: 'getent passwd | cut -d: -f1 | sort -n | uniq -d' + changed_when: false + failed_when: false + check_mode: no + register: rhel9cis_6_2_6_group_group_check + + - name: "6.2.6 | AUDIT | Ensure no duplicate group names exist | Print message that no duplicate groups exist" + debug: + msg: "Good News! There are no duplicate group names in the system" + when: rhel9cis_6_2_6_group_group_check.stdout is defined + + - name: "6.2.6 | AUDIT | Ensure no duplicate group names exist | Print warning about users with duplicate group names" + debug: + msg: "Warning: The following group names are duplicates: {{ rhel9cis_6_2_6_group_group_check.stdout_lines }}" + when: rhel9cis_6_2_6_group_group_check.stdout is not defined + when: + - rhel9cis_rule_6_2_6 + tags: + - level1-server + - level1-workstation + - automated + - audit + - accounts + - groups + - rule_6.2.6 + +- name: "6.2.7 | PATCH | Ensure root PATH Integrity" + block: + - name: "6.2.7 | AUDIT | Ensure root PATH Integrity | Determine empty value" shell: 'echo $PATH | grep ::' - args: - warn: false - check_mode: false - register: path_colon changed_when: False - failed_when: path_colon.rc == 0 + failed_when: rhel9cis_6_2_7_path_colon.rc == 0 + check_mode: no + register: rhel9cis_6_2_7_path_colon - - name: "6.2.3 | L1 | AUDIT | Ensure root PATH Integrity | Determin colon end" + - name: "6.2.7 | AUDIT | Ensure root PATH Integrity | Determin colon end" shell: 'echo $PATH | grep :$' - args: - warn: false - check_mode: false - register: path_colon_end changed_when: False - failed_when: path_colon_end.rc == 0 + failed_when: rhel9cis_6_2_7_path_colon_end.rc == 0 + check_mode: no + register: rhel9cis_6_2_7_path_colon_end - - name: "6.2.3 | L1 | AUDIT | Ensure root PATH Integrity | Determine dot in path" + - name: "6.2.7 | AUDIT | Ensure root PATH Integrity | Determine dot in path" shell: "/bin/bash --login -c 'env | grep ^PATH=' | sed -e 's/PATH=//' -e 's/::/:/' -e 's/:$//' -e 's/:/\\n/g'" - args: - warn: false - check_mode: false - register: dot_in_path changed_when: False - failed_when: '"." in dot_in_path.stdout_lines' + failed_when: '"." in rhel9cis_6_2_7_dot_in_path.stdout_lines' + check_mode: no + register: rhel9cis_6_2_7_dot_in_path - - name: "6.2.3 | L1 | AUDIT | Ensure root PATH Integrity | Alert on empty value, colon end, and dot in path" + - name: "6.2.7 | AUDIT | Ensure root PATH Integrity | Alert on empty value, colon end, and dot in path" debug: msg: - - "The following paths have an empty value: {{ path_colon.stdout_lines }}" - - "The following paths have colon end: {{ path_colon_end.stdout_lines }}" - - "The following paths have a dot in the path: {{ dot_in_path.stdout_lines }}" + - "The following paths have an empty value: {{ rhel9cis_6_2_7_path_colon.stdout_lines }}" + - "The following paths have colon end: {{ rhel9cis_6_2_7_path_colon_end.stdout_lines }}" + - "The following paths have a dot in the path: {{ rhel9cis_6_2_7_dot_in_path.stdout_lines }}" - - name: "6.2.3 | L1 | PATCH | Ensure root PATH Integrity (Scored) | Determine rights and owner" + - name: "6.2.7 | PATCH | Ensure root PATH Integrity (Scored) | Determine rights and owner" file: > path='{{ item }}' follow=yes state=directory owner=root mode='o-w,g-w' - with_items: "{{ dot_in_path.stdout_lines }}" + with_items: "{{ rhel9cis_6_2_7_dot_in_path.stdout_lines }}" when: - - rhel9cis_rule_6_2_3 + - rhel9cis_rule_6_2_7 tags: - level1-server - level1-workstation + - automated - patch - - rule_6.2.3 + - paths + - rule_6.2.7 -- name: "6.2.4 | L1 | PATCH | Ensure no legacy '+' entries exist in /etc/shadow" - shell: sed -i '/^+/ d' /etc/shadow - args: - warn: false +- name: "6.2.8 | PATCH | Ensure root is the only UID 0 account" + command: passwd -l {{ item }} changed_when: false failed_when: false + with_items: "{{ rhel9cis_uid_zero_accounts_except_root.stdout_lines }}" when: - - rhel9cis_rule_6_2_4 + - rhel9cis_uid_zero_accounts_except_root.rc + - rhel9cis_rule_6_2_8 tags: - level1-server - level1-workstation + - automated - patch - - rule_6.2.4 - - skip_ansible_lint + - accounts + - users + - rule_6.2.8 -- name: "6.2.5 | L1 | PATCH | Ensure no legacy '+' entries exist in /etc/group" - shell: sed -i '/^+/ d' /etc/group - args: - warn: false - changed_when: false - failed_when: false - when: - - rhel9cis_rule_6_2_5 - tags: - - level1-server - - level1-workstation - - patch - - rule_6.2.5 - - skip_ansible_lint - -- name: "6.2.6 | L1 | PATCH | Ensure root is the only UID 0 account" - shell: passwd -l {{ item }} - args: - warn: false - changed_when: false - failed_when: false - with_items: "{{ uid_zero_accounts_except_root.stdout_lines }}" - when: - - uid_zero_accounts_except_root.rc - - rhel9cis_rule_6_2_6 - tags: - - level1-server - - level1-workstation - - patch - - rule_6.2.6 - -- name: "6.2.7 | L1 | PATCH | Ensure users' home directories permissions are 750 or more restrictive" +- name: "6.2.9 | PATCH | Ensure all users' home directories exist" block: - - name: "6.2.7 | L1 | AUDIT | Ensure users' home directories permissions are 750 or more restrictive" + - name: "6.2.9 | AUDIT | Ensure all users' home directories exist" stat: path: "{{ item }}" - with_items: "{{ rhel9cis_passwd | selectattr('uid', '>=', min_int_uid | int) | selectattr('uid', '<', max_int_uid | int) | selectattr('dir', '!=', '/') | map(attribute='dir') | list }}" - register: rhel_09_6_2_7_audit + register: rhel_08_6_2_9_audit + with_items: "{{ rhel9cis_passwd | selectattr('uid', '>=', rhel9cis_int_gid) | selectattr('uid', '!=', 65534) | map(attribute='dir') | list }}" - - debug: - var: rhel_09_6_2_7_audit - - - name: "6.2.7 | L1 | AUDIT | Ensure users' home directories permissions are 750 or more restrictive" - shell: find -H {{ item.0 | quote }} -not -type l -perm /027 - args: - warn: false + - name: "6.2.9 | AUDIT | Ensure all users' home directories exist" + command: find -H {{ item.0 | quote }} -not -type l -perm /027 check_mode: false - changed_when: rhel_09_6_2_7_patch_audit.stdout | length > 0 - register: rhel_09_6_2_7_patch_audit + changed_when: rhel_08_6_2_9_patch_audit.stdout | length > 0 + register: rhel_08_6_2_9_patch_audit when: - ansible_check_mode - item.1.exists with_together: - - "{{ rhel_09_6_2_7_audit.results | map(attribute='item') | list }}" - - "{{ rhel_09_6_2_7_audit.results | map(attribute='stat') | list }}" + - "{{ rhel_08_6_2_9_audit.results | map(attribute='item') | list }}" + - "{{ rhel_08_6_2_9_audit.results | map(attribute='stat') | list }}" loop_control: label: "{{ item.0 }}" - - name: "6.2.7 | L1 | PATCH | Ensure users' home directories permissions are 750 or more restrictive" + - name: "6.2.9 | PATCH | Ensure all users' home directories exist" file: path: "{{ item.0 }}" - recurse: true + recurse: yes mode: a-st,g-w,o-rwx - register: rhel_09_6_2_7_patch + register: rhel_08_6_2_9_patch when: - not ansible_check_mode - item.1.exists with_together: - - "{{ rhel_09_6_2_7_audit.results | map(attribute='item') | list }}" - - "{{ rhel_09_6_2_7_audit.results | map(attribute='stat') | list }}" + - "{{ rhel_08_6_2_9_audit.results | map(attribute='item') | list }}" + - "{{ rhel_08_6_2_9_audit.results | map(attribute='stat') | list }}" loop_control: label: "{{ item.0 }}" # set default ACLs so the homedir has an effective umask of 0027 - - name: "6.2.7 | L1 | PATCH | Ensure users' home directories permissions are 750 or more restrictive" + - name: "6.2.9 | PATCH | Ensure all users' home directories exist" acl: path: "{{ item.0 }}" - default: true + default: yes state: present - recursive: true + recursive: yes etype: "{{ item.1.etype }}" permissions: "{{ item.1.mode }}" - when: - - not system_is_container + when: not rhel9cis_system_is_container with_nested: - - "{{ (ansible_check_mode | ternary(rhel_09_6_2_7_patch_audit, rhel_09_6_2_7_patch)).results | + - "{{ (ansible_check_mode | ternary(rhel_08_6_2_9_patch_audit, rhel_08_6_2_9_patch)).results | rejectattr('skipped', 'defined') | map(attribute='item') | map('first') | list }}" - - etype: group @@ -191,14 +280,17 @@ - etype: other mode: '0' when: - - rhel9cis_rule_6_2_7 + - rhel9cis_rule_6_2_9 tags: - level1-server - level1-workstation + - automated - patch - - rule_6.2.7 + - users + - rule_6.2.9 -- name: "6.2.8 | L1 | PATCH | Ensure users own their home directories" + +- name: "6.2.10 | PATCH | Ensure users own their home directories" file: path: "{{ item.dir }}" owner: "{{ item.id }}" @@ -207,348 +299,66 @@ loop_control: label: "{{ rhel9cis_passwd_label }}" when: - - min_int_uid | int >= item.uid - - rhel9cis_rule_6_2_8 + - item.uid >= rhel9cis_int_gid + - rhel9cis_rule_6_2_10 tags: - skip_ansible_lint # settings found on 6_2_7 - level1-server - level1-workstation + - autoamted - patch - - rule_6.2.8 - -- name: "6.2.9 | L1 | PATCH | Ensure users' dot files are not group or world-writable" - block: - - name: "6.2.9 | L1 | AUDIT | Ensure users' dot files are not group or world-writable | Check for files" - shell: find /home/ -name "\.*" -perm /g+w,o+w - args: - warn: false - changed_when: false - failed_when: false - register: rhel9cis_6_2_9_audit - - - name: "6.2.9 | L1 | AUDIT | Ensure users' dot files are not group or world-writable | Alert on files found" - debug: - msg: "Good news! We have not found any group or world-writable dot files on your sytem" - when: - - rhel9cis_6_2_9_audit.stdout is not defined - - - name: "6.2.9 | L1 | PATCH | Ensure users' dot files are not group or world-writable | Changes files if configured" - file: - path: '{{ item }}' - mode: go-w - with_items: "{{ rhel9cis_6_2_9_audit.stdout_lines }}" - when: - - rhel9cis_6_2_9_audit.stdout is defined - - rhel9cis_dotperm_ansiblemanaged - when: - - rhel9cis_rule_6_2_9 - tags: - - level1-server - - level1-workstation - - patch - - rule_6.2.9 - -- name: "6.2.10 | L1 | PATCH | Ensure no users have .forward files" - file: - state: absent - dest: "~{{ item }}/.forward" - with_items: "{{ users.stdout_lines }}" - when: - - rhel9cis_rule_6_2_10 - tags: - - level1-server - - level1-workstation - - patch + - users - rule_6.2.10 -- name: "6.2.11 | L1 | PATCH | Ensure no users have .netrc files" - file: - state: absent - dest: "~{{ item }}/.netrc" - with_items: "{{ users.stdout_lines }}" - when: - - rhel9cis_rule_6_2_11 - tags: - - level1-server - - level1-workstation - - patch - - rule_6.2.11 - -- name: "6.2.12 | L1 | PATCH | Ensure users' .netrc Files are not group or world accessible" - shell: /bin/true - args: - warn: false - changed_when: false - failed_when: false - when: - - rhel9cis_rule_6_2_12 - tags: - - level1-server - - level1-workstation - - patch - - rule_6.2.12 - -- name: "6.2.13 | L1 | PATCH | Ensure no users have .rhosts files" - file: - state: absent - dest: "~{{ item }}/.rhosts" - with_items: "{{ users.stdout_lines }}" - when: - - rhel9cis_rule_6_2_13 - tags: - - level1-server - - level1-workstation - - patch - - rule_6.2.13 - -- name: "6.2.14 | L1 | AUDIT | Ensure all groups in /etc/passwd exist in /etc/group" +- name: "6.2.11 | PATCH | Ensure users' home directories permissions are 750 or more restrictive" block: - - name: "6.2.14 | L1 | AUDIT | Ensure all groups in /etc/passwd exist in /etc/group | Check /etc/passwd entries" - shell: pwck -r | grep 'no group' | awk '{ gsub("[:\47]",""); print $2}' - args: - warn: false - changed_when: false - failed_when: false - check_mode: false - register: passwd_gid_check - - - name: "6.2.14 | L1 | AUDIT | Ensure all groups in /etc/passwd exist in /etc/group | Print message that all groups match between passwd and group files" - debug: - msg: "Good News! There are no users that have non-existent GUIDs (Groups)" - when: passwd_gid_check.stdout is not defined - - - name: "6.2.14 | L1 | AUDIT | Ensure all groups in /etc/passwd exist in /etc/group | Print warning about users with invalid GIDs missing GID entries in /etc/group" - debug: - msg: "WARNING: The following users have non-existent GIDs (Groups): {{ passwd_gid_check.stdout_lines | join (', ') }}" - when: passwd_gid_check.stdout is defined - when: - - rhel9cis_rule_6_2_14 - tags: - - level1-server - - level1-workstation - - audit - - rule_6.2.14 - -- name: "6.2.15 | L1 | AUDIT Ensure no duplicate UIDs exist" - block: - - name: "6.2.15 | L1 | AUDIT | Ensure no duplicate UIDs exist | Check for duplicate UIDs" - shell: "pwck -r | awk -F: '{if ($3 in uid) print $1 ; else uid[$3]}' /etc/passwd" - args: - warn: false - changed_when: false - failed_when: false - register: user_uid_check - - - name: "6.2.15 | L1 | AUDIT | Ensure no duplicate UIDs exist | Print message that no duplicate UIDs exist" - debug: - msg: "Good News! There are no duplicate UID's in the system" - when: user_uid_check.stdout is not defined - - - name: "6.2.15 | L1 | AUDIT| Ensure no duplicate UIDs exist | Print warning about users with duplicate UIDs" - debug: - msg: "Warning: The following users have UIDs that are duplicates: {{ user_uid_check.stdout_lines }}" - when: user_uid_check.stdout is defined - when: - - rhel9cis_rule_6_2_15 - tags: - - level1-server - - level1-workstation - - patch - - rule_6.2.15 - -- name: "6.2.16 | L1 | AUDIT | Ensure no duplicate GIDs exist" - block: - - name: "6.2.16 | L1 | AUDIT | Ensure no duplicate GIDs exist | Check for duplicate GIDs" - shell: "pwck -r | awk -F: '{if ($3 in users) print $1 ; else users[$3]}' /etc/group" - args: - warn: false - changed_when: false - failed_when: false - register: user_user_check - - - name: "6.2.16 | L1 | AUDIT | Ensure no duplicate GIDs exist | Print message that no duplicate GID's exist" - debug: - msg: "Good News! There are no duplicate GIDs in the system" - when: user_user_check.stdout is not defined - - - name: "6.2.16 | L1 | AUDIT | Ensure no duplicate GIDs exist | Print warning about users with duplicate GIDs" - debug: - msg: "Warning: The following groups have duplicate GIDs: {{ user_user_check.stdout_lines }}" - when: user_user_check.stdout is defined - when: - - rhel9cis_rule_6_2_16 - tags: - - level1-server - - level1-workstation - - audit - - rule_6.2.16 - -- name: "6.2.17 | L1 | AUDIT | Ensure no duplicate user names exist" - block: - - name: "6.2.17 | L1 | AUDIT | Ensure no duplicate user names exist | Check for duplicate User Names" - shell: "pwck -r | awk -F: '{if ($1 in users) print $1 ; else users[$1]}' /etc/passwd" - args: - warn: false - changed_when: false - failed_when: false - register: user_username_check - - - name: "6.2.17 | L1 | AUDIT | Ensure no duplicate user names exist | Print message that no duplicate user names exist" - debug: - msg: "Good News! There are no duplicate user names in the system" - when: user_username_check.stdout is not defined - - - name: "6.2.17 | L1 | AUDIT | Ensure no duplicate user names exist | Print warning about users with duplicate User Names" - debug: - msg: "Warning: The following user names are duplicates: {{ user_username_check.stdout_lines }}" - when: user_username_check.stdout is defined - when: - - rhel9cis_rule_6_2_17 - tags: - - level1-server - - level1-workstation - - audit - - rule_6.2.17 - -- name: "6.2.18 | L1 | AUDIT |Ensure no duplicate group names exist" - block: - - name: "6.2.18 | L1 | AUDIT | Ensure no duplicate group names exist | Check for duplicate group names" - shell: 'getent passwd | cut -d: -f1 | sort -n | uniq -d' - args: - warn: false - changed_when: false - failed_when: false - check_mode: false - register: group_group_check - - - name: "6.2.18 | L1 | AUDIT | Ensure no duplicate group names exist | Print message that no duplicate groups exist" - debug: - msg: "Good News! There are no duplicate group names in the system" - when: group_group_check.stdout is defined - - - name: "6.2.18 | L1 | AUDIT | Ensure no duplicate group names exist | Print warning about users with duplicate group names" - debug: - msg: "Warning: The following group names are duplicates: {{ group_group_check.stdout_lines }}" - when: group_group_check.stdout is not defined - when: - - rhel9cis_rule_6_2_18 - tags: - - level1-server - - level1-workstation - - audit - - rule_6.2.18 - -- name: "6.2.19 | L1 | AUDIT | Ensure shadow group is empty" - block: - - name: "6.2.19 | L1 | AUDIT | Ensure shadow group is empty | Check for shadow group and pull group id" - shell: "getent group shadow | cut -d: -f3" - args: - warn: false - changed_when: false - failed_when: false - check_mode: false - register: rhel9cis_shadow_gid - - - name: "6.2.19 | L1 | AUDIT | Ensure shadow group is empty | Check /etc/group for empty shadow group" - shell: grep ^shadow:[^:]*:[^:]*:[^:]+ /etc/group - args: - warn: false - changed_when: false - failed_when: false - check_mode: false - register: rhel9cis_empty_shadow - - - name: "6.2.19 | L1 | AUDIT | Ensure shadow group is empty | Check for users assigned to shadow" - shell: "getent passwd | awk -F: '$4 == '{{ rhel9cis_shadow_gid.stdout }}' {print $1}'" - args: - warn: false - changed_when: false - failed_when: false - check_mode: false - register: rhel9cis_shadow_passwd - - - name: "6.2.19 | L1 | AUDIT | Ensure shadow group is empty | Alert shadow group is empty and no users assigned" - debug: - msg: - - " Good News! The shadow group is empty and there are no users assigned to shadow" - when: - - rhel9cis_empty_shadow.stdout | length == 0 - - rhel9cis_shadow_passwd.stdout | length == 0 - - - name: "6.2.19 | L1 | AUDIT | Ensure shadow group is empty | Alert shadow group is not empty" - debug: - msg: - - "Alert! The shadow group is not empty" - when: - - rhel9cis_empty_shadow.stdout | length > 0 - - - name: "6.2.19 | L1 | AUDIT | Ensure shadow group is empty | Alert users are using shadow group" - debug: - msg: - - "Alert! The following users are assigned to the shadow group, please assing them to the appropriate group" - - "{{ rhel9cis_shadow_passwd.stdout_lines }}" - when: - - rhel9cis_shadow_passwd.stdout | length > 0 - when: - - rhel9cis_rule_6_2_19 - tags: - - level1-server - - level1-workstation - - audit - - rule_6.2.19 - -- name: "6.2.20 | L1 | PATCH | Ensure all users' home directories exist" - block: - - name: "6.2.20 | L1 | AUDIT | Ensure all users' home directories exist" + - name: "6.2.11 | AUDIT | Ensure users' home directories permissions are 750 or more restrictive" stat: path: "{{ item }}" - register: rhel_09_6_2_20_audit - with_items: "{{ rhel9cis_passwd | selectattr('uid', '>=', min_int_uid | int) | selectattr('uid', '<', max_int_uid | int) | selectattr('dir', '!=', '/') | map(attribute='dir') | list }}" + with_items: "{{ rhel9cis_passwd | selectattr('uid', '>=', rhel9cis_int_gid) | selectattr('uid', '!=', 65534) | map(attribute='dir') | list }}" + register: rhel_08_6_2_11_audit - - name: "6.2.20 | L1 | AUDIT | Ensure all users' home directories exist" - shell: find -H {{ item.0 | quote }} -not -type l -perm /027 - args: - warn: false + - name: "6.2.11 | AUDIT | Ensure users' home directories permissions are 750 or more restrictive" + command: find -H {{ item.0 | quote }} -not -type l -perm /027 check_mode: false - changed_when: rhel_09_6_2_20_patch_audit.stdout | length > 0 - register: rhel_09_6_2_20_patch_audit + changed_when: rhel_08_6_2_11_patch_audit.stdout | length > 0 + register: rhel_08_6_2_11_patch_audit when: - ansible_check_mode - item.1.exists with_together: - - "{{ rhel_09_6_2_20_audit.results | map(attribute='item') | list }}" - - "{{ rhel_09_6_2_20_audit.results | map(attribute='stat') | list }}" + - "{{ rhel_08_6_2_11_audit.results | map(attribute='item') | list }}" + - "{{ rhel_08_6_2_11_audit.results | map(attribute='stat') | list }}" loop_control: label: "{{ item.0 }}" - - name: "6.2.20 | L1 | PATCH | Ensure all users' home directories exist" + - name: "6.2.11 | PATCH | Ensure users' home directories permissions are 750 or more restrictive" file: path: "{{ item.0 }}" - recurse: true + recurse: yes mode: a-st,g-w,o-rwx - register: rhel_09_6_2_20_patch + register: rhel_08_6_2_11_patch when: - not ansible_check_mode - item.1.exists with_together: - - "{{ rhel_09_6_2_20_audit.results | map(attribute='item') | list }}" - - "{{ rhel_09_6_2_20_audit.results | map(attribute='stat') | list }}" + - "{{ rhel_08_6_2_11_audit.results | map(attribute='item') | list }}" + - "{{ rhel_08_6_2_11_audit.results | map(attribute='stat') | list }}" loop_control: label: "{{ item.0 }}" # set default ACLs so the homedir has an effective umask of 0027 - - name: "6.2.20 | L1 | PATCH | Ensure all users' home directories exist" + - name: "6.2.11 | PATCH | Ensure users' home directories permissions are 750 or more restrictive" acl: path: "{{ item.0 }}" - default: true + default: yes state: present - recursive: true + recursive: yes etype: "{{ item.1.etype }}" permissions: "{{ item.1.mode }}" - when: - - not system_is_container + when: not rhel9cis_system_is_container with_nested: - - "{{ (ansible_check_mode | ternary(rhel_09_6_2_20_patch_audit, rhel_09_6_2_20_patch)).results | + - "{{ (ansible_check_mode | ternary(rhel_08_6_2_11_patch_audit, rhel_08_6_2_11_patch)).results | rejectattr('skipped', 'defined') | map(attribute='item') | map('first') | list }}" - - etype: group @@ -556,9 +366,111 @@ - etype: other mode: '0' when: - - rhel9cis_rule_6_2_20 + - rhel9cis_rule_6_2_11 tags: - level1-server - level1-workstation + - automated - patch - - rule_6.2.20 + - users + - permissions + - rule_6.2.11 + +- name: "6.2.12 | PATCH | Ensure users' dot files are not group or world-writable" + block: + - name: "6.2.12 | AUDIT | Ensure users' dot files are not group or world-writable | Check for files" + shell: find /home/ -maxdepth 2 -name "\.*" -perm /g+w,o+w + changed_when: false + failed_when: false + register: rhel9cis_6_2_12_audit + + - name: "6.2.12 | AUDIT | Ensure users' dot files are not group or world-writable | Alert on files found" + debug: + msg: "Good news! We have not found any group or world-writable dot files on your sytem" + when: + - rhel9cis_6_2_12_audit.stdout is not defined + + - name: "6.2.12 | PATCH | Ensure users' dot files are not group or world-writable | Changes files if configured" + file: + path: '{{ item }}' + mode: go-w + with_items: "{{ rhel9cis_6_2_12_audit.stdout_lines }}" + when: + - rhel9cis_6_2_12_audit.stdout is defined + - rhel9cis_dotperm_ansiblemanaged + when: + - rhel9cis_rule_6_2_12 + tags: + - level1-server + - level1-workstation + - automated + - patch + - users + - permissions + - rule_6.2.12 + +- name: "6.2.13 | PATCH | Ensure users' .netrc Files are not group or world accessible" + command: /bin/true + changed_when: false + failed_when: false + when: + - rhel9cis_rule_6_2_13 + tags: + - level1-server + - level1-workstation + - automated + - patch + - users + - permissions + - notimplemented + - rule_6.2.13 + +- name: "6.2.14 | PATCH | Ensure no users have .forward files" + file: + state: absent + dest: "~{{ item }}/.forward" + with_items: + - "{{ users.stdout_lines }}" + when: + - rhel9cis_rule_6_2_14 + tags: + - level1-server + - level1-workstation + - automated + - patch + - users + - files + - rule_6.2.14 + +- name: "6.2.15 | PATCH | Ensure no users have .netrc files" + file: + state: absent + dest: "~{{ item }}/.netrc" + with_items: + - "{{ users.stdout_lines }}" + when: + - rhel9cis_rule_6_2_15 + tags: + - level1-server + - level1-workstation + - automated + - patch + - users + - files + - rule_6.2.15 + +- name: "6.2.16 | PATCH | Ensure no users have .rhosts files" + file: + state: absent + dest: "~{{ item }}/.rhosts" + with_items: "{{ users.stdout_lines }}" + when: + - rhel9cis_rule_6_2_16 + tags: + - level1-server + - level1-workstation + - automated + - patch + - users + - files + - rule_6.2.16 diff --git a/tasks/section_6/main.yml b/tasks/section_6/main.yml index b6acabf..6161273 100644 --- a/tasks/section_6/main.yml +++ b/tasks/section_6/main.yml @@ -4,4 +4,4 @@ import_tasks: cis_6.1.x.yml - name: "SECTION | 6.2 | User and Group Settings" - import_tasks: cis_6.2.x.yml + import_tasks: cis_6.2.x.yml \ No newline at end of file diff --git a/templates/audit/99_auditd.rules.j2 b/templates/audit/99_auditd.rules.j2 index 43897d7..4716376 100644 --- a/templates/audit/99_auditd.rules.j2 +++ b/templates/audit/99_auditd.rules.j2 @@ -1,79 +1,92 @@ -# File created initially via RHEL9 CIS ansible-lockdown remdiation role -{% if rhel9cis_rule_4_1_3 %} +# This template will set all of the auditd configurations via a handler in the role in one task instead of individually +{% if rhel9cis_rule_4_1_3_1 %} -w /etc/sudoers -p wa -k scope -w /etc/sudoers.d/ -p wa -k scope {% endif %} -{% if rhel9cis_rule_4_1_4 %} --w /var/log/faillog -p wa -k logins --w /var/log/lastlog -p wa -k logins +{% if rhel9cis_rule_4_1_3_2 %} +-a always,exit -F arch=b64 -C euid!=uid -F auid!=unset -S execve -k user_emulation +-a always,exit -F arch=b32 -C euid!=uid -F auid!=unset -S execve -k user_emulation {% endif %} -{% if rhel9cis_rule_4_1_5 %} --w /var/run/utmp -p wa -k session --w /var/log/wtmp -p wa -k logins --w /var/log/btmp -p wa -k logins +{% if rhel9cis_rule_4_1_3_3 %} +-w {{ rhel9cis_varlog_location }} -p wa -k sudo_log_file {% endif %} -{% if rhel9cis_rule_4_1_6 %} --a always,exit -F arch=b64 -S adjtimex -S settimeofday -k time-change --a always,exit -F arch=b32 -S adjtimex -S settimeofday -S stime -k time-change --a always,exit -F arch=b64 -S clock_settime -k time-change --a always,exit -F arch=b32 -S clock_settime -k time-change +{% if rhel9cis_rule_4_1_3_4 %} +-a always,exit -F arch=b64 -S adjtimex,settimeofday,clock_settime -k time-change +-a always,exit -F arch=b32 -S adjtimex,settimeofday,clock_settime -k time-change -w /etc/localtime -p wa -k time-change {% endif %} -{% if rhel9cis_rule_4_1_7 %} --w /etc/selinux/ -p wa -k MAC-policy --w /usr/share/selinux/ -p wa -k MAC-policy -{% endif %} -{% if rhel9cis_rule_4_1_8 %} --a always,exit -F arch=b64 -S sethostname -S setdomainname -k system-locale --a always,exit -F arch=b32 -S sethostname -S setdomainname -k system-locale +{% if rhel9cis_rule_4_1_3_5 %} +-a always,exit -F arch=b64 -S sethostname,setdomainname -F key=system-locale +-a always,exit -F arch=b32 -S sethostname,setdomainname -F key=system-locale -w /etc/issue -p wa -k system-locale -w /etc/issue.net -p wa -k system-locale -w /etc/hosts -p wa -k system-locale -w /etc/sysconfig/network -p wa -k system-locale +-w /etc/sysconfig/network-scripts -p wa -k system-locale {% endif %} -{% if rhel9cis_rule_4_1_9 %} --a always,exit -F arch=b32 -S chmod -S fchmod -S fchmodat -F auid>={{ min_int_uid }} -F auid!=4294967295 -k perm_mod --a always,exit -F arch=b32 -S chown -S fchown -S fchownat -S lchown -F auid>={{ min_int_uid }} -F auid!=4294967295 -k perm_mod --a always,exit -F arch=b32 -S setxattr -S lsetxattr -S fsetxattr -S removexattr -S lremovexattr -S fremovexattr -F auid>={{ min_int_uid }} -F auid!=4294967295 -k perm_mod --a always,exit -F arch=b64 -S chmod -S fchmod -S fchmodat -F auid>={{ min_int_uid }} -F auid!=4294967295 -k perm_mod --a always,exit -F arch=b64 -S chown -S fchown -S fchownat -S lchown -F auid>={{ min_int_uid }} -F auid!=4294967295 -k perm_mod --a always,exit -F arch=b64 -S setxattr -S lsetxattr -S fsetxattr -S removexattr -S lremovexattr -S fremovexattr -F auid>={{ min_int_uid }} -F auid!=4294967295 -k perm_mod +{% if rhel9cis_rule_4_1_3_6 %} +{% for proc in priv_procs.stdout_lines -%} +-a always,exit -F path={{ proc }} -F perm=x -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -k privileged +{% endfor %} {% endif %} -{% if rhel9cis_rule_4_1_10 %} --a always,exit -F arch=b32 -S creat,open,openat,open_by_handle_at,truncate,ftruncate -F exit=-EACCES -F auid>={{ min_int_uid }} -F auid!=4294967295 -F key=access --a always,exit -F arch=b32 -S creat,open,openat,open_by_handle_at,truncate,ftruncate -F exit=-EPERM -F auid>={{ min_int_uid }} -F auid!=4294967295 -F key=access --a always,exit -F arch=b64 -S creat,open,openat,open_by_handle_at,truncate,ftruncate -F exit=-EACCES -F auid>={{ min_int_uid }} -F auid!=4294967295 -F key=access --a always,exit -F arch=b64 -S creat,open,openat,open_by_handle_at,truncate,ftruncate -F exit=-EPERM -F auid>={{ min_int_uid }} -F auid!=4294967295 -F key=access +{% if rhel9cis_rule_4_1_3_7 %} +-a always,exit -F arch=b64 -S creat,open,openat,truncate,ftruncate -F exit=-EACCES -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -F key=access +-a always,exit -F arch=b64 -S creat,open,openat,truncate,ftruncate -F exit=-EPERM -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -F key=access +-a always,exit -F arch=b32 -S creat,open,openat,truncate,ftruncate -F exit=-EACCES -F auid>={{ rhel9cis_int_gid }} -F auid!=-4294967295 -F key=access +-a always,exit -F arch=b32 -S creat,open,openat,truncate,ftruncate -F exit=-EPERM -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -F key=access {% endif %} -{% if rhel9cis_rule_4_1_11 %} +{% if rhel9cis_rule_4_1_3_8 %} -w /etc/group -p wa -k identity -w /etc/passwd -p wa -k identity -w /etc/gshadow -p wa -k identity -w /etc/shadow -p wa -k identity -w /etc/security/opasswd -p wa -k identity {% endif %} -{% if rhel9cis_rule_4_1_12 %} --a always,exit -F arch=b32 -S mount -F auid>={{ min_int_uid }} -F auid!=4294967295 -k mounts --a always,exit -F arch=b64 -S mount -F auid>={{ min_int_uid }} -F auid!=4294967295 -k mounts +{% if rhel9cis_rule_4_1_3_9 %} +-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -F key=perm_mod +-a always,exit -F arch=b64 -S chown,fchown,lchown,fchownat -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -F key=perm_mod +-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -F key=perm_mod +-a always,exit -F arch=b32 -S lchown,fchown,chown,fchownat -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -F key=perm_mod +-a always,exit -F arch=b64 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -F key=perm_mod +-a always,exit -F arch=b32 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -F key=perm_mod {% endif %} -{% if rhel9cis_rule_4_1_13 %} -{% for proc in priv_procs.stdout_lines -%} --a always,exit -F path={{ proc }} -F perm=x -F auid>={{ min_int_uid }} -F auid!=4294967295 -k privileged -{% endfor %} +{% if rhel9cis_rule_4_1_3_10 %} +-a always,exit -F arch=b32 -S mount -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -k mounts +-a always,exit -F arch=b64 -S mount -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -k mounts {% endif %} -{% if rhel9cis_rule_4_1_14 %} --a always,exit -F arch=b32 -S rmdir,unlink,unlinkat,rename -S renameat -F auid>={{ min_int_uid }} -F auid!=4294967295 -F key=delete --a always,exit -F arch=b64 -S rmdir,unlink,unlinkat,rename -S renameat -F auid>={{ min_int_uid }} -F auid!=4294967295 -F key=delete +{% if rhel9cis_rule_4_1_3_11 %} +-w /var/run/utmp -p wa -k session +-w /var/log/wtmp -p wa -k session +-w /var/log/btmp -p wa -k session {% endif %} -{% if rhel9cis_rule_4_1_15 %} --w /usr/sbin/insmod -p x -k modules --w /usr/sbin/rmmod -p x -k modules --w /usr/sbin/modprobe -p x -k modules --a always,exit -F arch=b64 -S init_module -S delete_module -k modules +{% if rhel9cis_rule_4_1_3_12 %} +-w /var/log/lastlog -p wa -k logins +-w /var/run/faillock -p wa -k logins {% endif %} -{% if rhel9cis_rule_4_1_16 %} --w /var/log/sudo.log -p wa -k actions +{% if rhel9cis_rule_4_1_3_13 %} +-a always,exit -F arch=b64 -S rename,unlink,unlinkat,renameat -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -F key=delete +-a always,exit -F arch=b32 -S rename,unlink,unlinkat,renameat -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -F key=delete {% endif %} -{% if rhel9cis_rule_4_1_17 %} +{% if rhel9cis_rule_4_1_3_14 %} +-w /etc/selinux/ -p wa -k MAC-policy +-w /usr/share/selinux/ -p wa -k MAC-policy +{% endif %} +{% if rhel9cis_rule_4_1_3_15 %} +-a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -k perm_chng +{% endif %} +{% if rhel9cis_rule_4_1_3_16 %} +-a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -k perm_chng +{% endif %} +{% if rhel9cis_rule_4_1_3_17 %} +-a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -k priv_cmd +{% endif %} +{% if rhel9cis_rule_4_1_3_18 %} +-a always,exit -F path=/usr/sbin/usermod -F perm=x -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -k usermod +{% endif %} +{% if rhel9cis_rule_4_1_3_19 %} +-a always,exit -F arch=b64 -S init_module,finit_module,delete_module,create_module,query_module -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -k kernel_modules +-a always,exit -F path=/usr/bin/kmod -F perm=x -F auid>={{ rhel9cis_int_gid }} -F auid!=4294967295 -k kernel_modules +{% endif %} +{% if rhel9cis_rule_4_1_3_20 %} -e 2 {% endif %}