diff --git a/docs/user/README.md b/docs/user/README.md index fb004b73ef..6ac76eacab 100644 --- a/docs/user/README.md +++ b/docs/user/README.md @@ -10,6 +10,7 @@ List of the documents in alphabetical file name order. - [AMQ Broker on MicroShift](./howto_amq_broker.md) - [Cluster-to-Cluster Connectivity (C2CC)](./howto_c2cc.md) - [Encrypting C2CC Traffic with IPsec](./howto_c2cc_ipsec.md) +- [CIS Level 2 Hardening for MicroShift](./howto_cis_hardening.md) - [MicroShift Configuration](./howto_config.md) - [Firewall Configuration](./howto_firewall.md) - [Gateway API](./howto_gateway_api.md) diff --git a/docs/user/howto_cis_hardening.md b/docs/user/howto_cis_hardening.md new file mode 100644 index 0000000000..36be22be50 --- /dev/null +++ b/docs/user/howto_cis_hardening.md @@ -0,0 +1,107 @@ +# CIS Level 2 Hardening for MicroShift + +This guide describes how to run MicroShift on a CIS Level 2 hardened RHEL system. It covers which CIS rules MicroShift affects, the required hardening playbook overrides, and how to verify compliance. + +## MicroShift's CIS Impact + +MicroShift introduces changes to a hardened system in three categories. These rules will fail on any system running Kubernetes containers and cannot be avoided without disabling core functionality. + +### IP Forwarding + +OVN-Kubernetes requires IP forwarding for pod networking. MicroShift enables `net.ipv4.ip_forward` and `net.ipv6.conf.all.forwarding` at startup. + +| Rule ID | RHEL 9 | RHEL 10 | +|:--------|:------:|:-------:| +| `sysctl_net_ipv4_ip_forward` | x | x | +| `sysctl_net_ipv6_conf_all_forwarding` | x | x | +| `sysctl_net_ipv4_conf_all_forwarding` | | x | +| `sysctl_net_ipv4_conf_default_forwarding` | | x | +| `sysctl_net_ipv6_conf_default_forwarding` | | x | + +### Container File Ownership + +Container images contain files owned by UIDs and GIDs that do not exist in the host's `/etc/passwd` and `/etc/group`. These are stored in `/var/lib/containers/storage/overlay/` and are an inherent characteristic of any container runtime. + +| Rule ID | RHEL 9 | RHEL 10 | +|:--------|:------:|:-------:| +| `file_permissions_ungroupowned` | x | | +| `no_files_unowned_by_user` | x | | +| `no_files_or_dirs_ungroupowned` | | x | +| `no_files_or_dirs_unowned_by_user` | | x | + +### Kubelet Volume Permissions + +Kubelet creates 0777 directories for ConfigMap and EmptyDir volumes so that pods running as any UID can access their projected configuration. It also creates 0666 container termination log files. + +| Rule ID | RHEL 9 | RHEL 10 | +|:--------|:------:|:-------:| +| `dir_perms_world_writable_sticky_bits` | x | x | +| `file_permissions_unauthorized_world_writable` | x | x | + +### Audit Rules + +CIS requires audit rules for all setuid/setgid binaries. If MicroShift is installed after running the CIS hardening role, the audit rules will not cover binaries added by MicroShift RPMs. + +| Rule ID | RHEL 9 | RHEL 10 | +|:--------|:------:|:-------:| +| `audit_rules_privileged_commands` | x | x | + +This rule can be resolved by regenerating audit rules after installing MicroShift: + +```bash +sudo find / -xdev \( -perm -4000 -o -perm -2000 \) -type f 2>/dev/null | \ + awk '{print "-a always,exit -F path=" $1 " -F perm=x -F auid>=1000 -F auid!=unset -k privileged"}' | \ + sudo tee /etc/audit/rules.d/99-privileged-post-install.rules > /dev/null +sudo augenrules --load +``` + +## Hardening Playbook Overrides + +When using the RedHatOfficial CIS ansible roles, the hardening playbook must override the IP forwarding variables to prevent the role from disabling forwarding before MicroShift starts. + +For RHEL 9: + +```yaml +--- +- name: Apply CIS Level 2 hardening + hosts: localhost + connection: local + become: true + roles: + - role: ansible-role-rhel9-cis + vars: + sysctl_net_ipv4_ip_forward: false + sysctl_net_ipv6_conf_all_forwarding: false +``` + +For RHEL 10, the CIS benchmark adds per-interface forwarding checks: + +```yaml +--- +- name: Apply CIS Level 2 hardening + hosts: localhost + connection: local + become: true + roles: + - role: ansible-role-rhel10-cis + vars: + sysctl_net_ipv4_ip_forward: false + sysctl_net_ipv4_conf_all_forwarding: false + sysctl_net_ipv4_conf_default_forwarding: false + sysctl_net_ipv6_conf_all_forwarding: false + sysctl_net_ipv6_conf_default_forwarding: false +``` + +> Each variable is set to `false` to tell the role **not** to disable forwarding. This does not enable forwarding — MicroShift does that at startup. + +## Firewall Configuration + +CIS hardening enables `firewalld` and locks down all traffic. MicroShift requires several ports and trusted network sources to be opened as described in [Firewall Configuration](howto_firewall.md). + +## References + +- [RedHatOfficial ansible-role-rhel9-cis](https://github.com/RedHatOfficial/ansible-role-rhel9-cis) +- [RedHatOfficial ansible-role-rhel10-cis](https://github.com/RedHatOfficial/ansible-role-rhel10-cis) +- [OpenSCAP Project](https://www.open-scap.org/) +- [CIS Benchmarks](https://www.cisecurity.org/cis-benchmarks) +- [Firewall Configuration](howto_firewall.md) diff --git a/test/assets/cis/cis-harden-el10.yml b/test/assets/cis/cis-harden-el10.yml new file mode 100644 index 0000000000..b70502fbf1 --- /dev/null +++ b/test/assets/cis/cis-harden-el10.yml @@ -0,0 +1,16 @@ +--- +- name: Apply CIS Level 2 hardening + hosts: localhost + connection: local + become: true + roles: + - role: ansible-role-rhel10-cis + vars: + # MicroShift OVN networking requires IP forwarding + sysctl_net_ipv4_ip_forward: false + sysctl_net_ipv4_conf_all_forwarding: false + sysctl_net_ipv4_conf_default_forwarding: false + sysctl_net_ipv6_conf_all_forwarding: false + sysctl_net_ipv6_conf_default_forwarding: false + # CI requires passwordless sudo + sudo_remove_nopasswd: false diff --git a/test/assets/cis/cis-harden-el9.yml b/test/assets/cis/cis-harden-el9.yml new file mode 100644 index 0000000000..7c6f050b1e --- /dev/null +++ b/test/assets/cis/cis-harden-el9.yml @@ -0,0 +1,13 @@ +--- +- name: Apply CIS Level 2 hardening + hosts: localhost + connection: local + become: true + roles: + - role: ansible-role-rhel9-cis + vars: + # MicroShift OVN networking requires IP forwarding + sysctl_net_ipv4_ip_forward: false + sysctl_net_ipv6_conf_all_forwarding: false + # CI requires passwordless sudo + sudo_remove_nopasswd: false diff --git a/test/assets/cis/cis-requirements-el10.yml b/test/assets/cis/cis-requirements-el10.yml new file mode 100644 index 0000000000..fd2088ff6c --- /dev/null +++ b/test/assets/cis/cis-requirements-el10.yml @@ -0,0 +1,7 @@ +roles: + - name: ansible-role-rhel10-cis + src: https://github.com/RedHatOfficial/ansible-role-rhel10-cis + version: "0.1.80" +collections: + - community.general + - ansible.posix diff --git a/test/assets/cis/cis-requirements-el9.yml b/test/assets/cis/cis-requirements-el9.yml new file mode 100644 index 0000000000..d7930ad2e0 --- /dev/null +++ b/test/assets/cis/cis-requirements-el9.yml @@ -0,0 +1,7 @@ +roles: + - name: ansible-role-rhel9-cis + src: https://github.com/RedHatOfficial/ansible-role-rhel9-cis + version: "0.1.80" +collections: + - community.general + - ansible.posix diff --git a/test/scenarios-bootc/el10/periodics/el102-src@cis-lvl2.sh b/test/scenarios-bootc/el10/periodics/el102-src@cis-lvl2.sh new file mode 100644 index 0000000000..835e59f2dc --- /dev/null +++ b/test/scenarios-bootc/el10/periodics/el102-src@cis-lvl2.sh @@ -0,0 +1,154 @@ +#!/bin/bash + +# Sourced from scenario.sh and uses functions defined there. + +# CIS hardening runs inside the Robot suite and takes ~20 minutes +# shellcheck disable=SC2034 # used elsewhere +TEST_EXECUTION_TIMEOUT=60m + +# The RPM-based image used to create the VM for this test does not +# include MicroShift or greenboot, so tell the framework not to wait +# for greenboot to finish when creating the VM. +export SKIP_GREENBOOT=true + +configure_microshift_mirror() { + local -r repo=$1 + + if [[ -z "${repo}" ]] ; then + return + fi + + if [[ ! "${repo}" =~ ^http ]]; then + return + fi + + local -r tmp_file=$(mktemp) + tee "${tmp_file}" >/dev/null </dev/null </dev/null </dev/null </dev/null </dev/null </dev/null < 0 + Fail MicroShift introduced unexpected CIS failures: ${unexpected} + END + +Setup Smoke Test + [Documentation] Create hello-microshift pod and expose via route + ${ns}= Create Unique Namespace + VAR ${NAMESPACE}= ${ns} scope=TEST + Create Hello MicroShift Pod + Expose Hello MicroShift + Oc Expose svc hello-microshift --hostname hello-microshift.cluster.local -n ${NAMESPACE} + +Teardown Smoke Test + [Documentation] Clean up smoke test resources + Run Keyword And Ignore Error Oc Delete route/hello-microshift -n ${NAMESPACE} + Run Keyword And Ignore Error Delete Hello MicroShift Pod And Service + Run Keyword And Ignore Error Remove Namespace ${NAMESPACE}