# AlmaLinux 10 — CIS Level 1 Hardening Decisions **Created:** 2026-03-27 **Updated:** 2026-03-28 **Reference:** CIS AlmaLinux OS 10 Benchmark (tracks RHEL 10) **Script:** `work/KickStart/cfg/AlmaLinux-10.1-x86_64/ks.d/S940A-cis-hardening` --- ## Summary of Decisions | CIS Control | Description | Decision | |---|---|---| | 1.1.1 | Disable unused filesystem modules | **Applied** | | 1.1.2 | /tmp as separate partition or tmpfs | **Deferred** — pending dev review | | 1.6 | Disable core dumps | **Applied** | | 3.3.1 | Disable IP forwarding | **Applied** (probes/servers are not routers) | | 3.3.2 | Disable packet redirect sending | **Applied** | | 3.3.3 | Refuse source-routed packets | **Applied** | | 3.3.4 | Refuse ICMP redirects | **Applied** | | 3.3.5 | Refuse secure ICMP redirects | **Applied** | | 3.3.6 | Log martian packets | **Applied** | | 3.3.7 | Ignore broadcast ICMP echo requests | **Applied** | | 3.3.8 | Ignore bogus ICMP error responses | **Applied** | | 3.3.9 | Enable TCP SYN cookies | **Applied** | | 3.3.10 | Disable IPv6 router advertisements | **Applied** | | 4.1.2 | auditd enabled at boot | **Applied** | | 4.1.3 | Audit processes prior to auditd start | **Applied** (`audit=1 audit_backlog_limit=8192` kernel args) | | 4.1.4 | Date/time change events | **Applied** | | 4.1.5 | User/group identity changes | **Applied** | | 4.1.6 | Network environment changes | **Applied** | | 4.1.7 | MAC policy changes (SELinux) | **Applied** | | 4.1.8 | Login/logout events | **Applied** | | 4.1.9 | Session initiation | **Applied** | | 4.1.10 | Permission modification events | **Applied** | | 4.1.11 | Unauthorized file access attempts | **Applied** | | 4.1.12 | Privileged command usage | **Applied** (generated dynamically via `find`) | | 4.1.13 | File system mounts | **Applied** | | 4.1.14 | File deletion by users | **Applied** | | 4.1.15 | sudoers scope changes | **Applied** | | 4.1.16 | sudo log monitoring | **Applied** | | 4.1.17 | Kernel module load/unload | **Applied** | | 4.1.18 | Audit rules immutable (`-e 2`) | **Applied** | | 5.3.2 | sudo: require pty | **Applied** | | 5.3.3 | sudo: log all usage | **Applied** | | 5.4.1 | Password quality (pwquality) | **Applied** | | 5.4.2 | Password aging | **Excluded** — no expiration policy in this environment | | 5.4.3 | Account lockout (pam_faillock) | **Applied** (pre-configured; active after `authselect enable-feature with-faillock` post-IPA) | | squashfs module blacklist | CIS recommends disabling | **Excluded** — containers (Docker/Podman) require squashfs | | udf module blacklist | CIS recommends disabling | **Excluded** — not prohibited in this environment | | AIDE cron | CIS recommends local AIDE cron | **Excluded** — managed centrally, not locally | | authselect profile change | Required to activate faillock in PAM | **Excluded from kickstart** — IPA owns the authselect profile | --- ## Applied Controls ### 1.1.1 — Disable Unused Filesystem Modules **File:** `/etc/modprobe.d/cis-fs-blacklist.conf` ``` install cramfs /bin/true install freevxfs /bin/true install hfs /bin/true install hfsplus /bin/true install jffs2 /bin/true blacklist cramfs blacklist freevxfs blacklist hfs blacklist hfsplus blacklist jffs2 ``` Both `install` (prevents modprobe load) and `blacklist` (prevents udev autoload) directives are used for belt-and-suspenders. **Excluded from this list:** - `squashfs` — Docker/Podman containers require it. Re-evaluate if container usage changes. - `udf` — Not prohibited in this environment. Re-evaluate if needed. ### 1.6 — Core Dump Restrictions Three layers applied: **`/etc/security/limits.d/cis-coredump.conf`** (PAM limits): ``` * hard core 0 ``` **`/etc/sysctl.d/20-cis-coredump.conf`** (kernel — disables setuid core dumps): ``` fs.suid_dumpable = 0 ``` **`/etc/systemd/coredump.conf.d/cis.conf`** (systemd coredump handler): ``` [Coredump] Storage=none ProcessSizeMax=0 ``` ### 3.3 — Network Sysctl Hardening **File:** `/etc/sysctl.d/30-cis-network.conf` ```ini # 3.3.1 — disable IP forwarding net.ipv4.ip_forward = 0 net.ipv6.conf.all.forwarding = 0 # 3.3.2 — disable packet redirect sending net.ipv4.conf.all.send_redirects = 0 net.ipv4.conf.default.send_redirects = 0 # 3.3.3 — refuse source-routed packets net.ipv4.conf.all.accept_source_route = 0 net.ipv4.conf.default.accept_source_route = 0 net.ipv6.conf.all.accept_source_route = 0 net.ipv6.conf.default.accept_source_route = 0 # 3.3.4 — refuse ICMP redirects net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.default.accept_redirects = 0 net.ipv6.conf.all.accept_redirects = 0 net.ipv6.conf.default.accept_redirects = 0 # 3.3.5 — refuse secure ICMP redirects net.ipv4.conf.all.secure_redirects = 0 net.ipv4.conf.default.secure_redirects = 0 # 3.3.6 — log martian packets net.ipv4.conf.all.log_martians = 1 net.ipv4.conf.default.log_martians = 1 # 3.3.7 — ignore broadcast ICMP echo requests net.ipv4.icmp_echo_ignore_broadcasts = 1 # 3.3.8 — ignore bogus ICMP error responses net.ipv4.icmp_ignore_bogus_error_responses = 1 # 3.3.9 — enable TCP SYN cookies net.ipv4.tcp_syncookies = 1 # 3.3.10 — disable IPv6 router advertisements net.ipv6.conf.all.accept_ra = 0 net.ipv6.conf.default.accept_ra = 0 # Kernel ASLR kernel.randomize_va_space = 2 ``` **Note on `net.ipv4.ip_forward`:** The default is already `0` on RHEL 10 for non-router systems. This is explicitly set for audit compliance. If Docker/Podman networking requires it, Docker daemon config (`"ip-forward": true`) re-enables it automatically — but explicitly setting `0` here means Docker/Podman will need to override it at startup. Verify if container networking is affected. ### 4.x — Auditd Configuration **Added 2026-03-28.** #### Kernel boot flag (4.1.3) ```bash grubby --update-kernel=ALL --args="audit=1 audit_backlog_limit=8192" ``` Ensures processes that start before auditd is running are still audited. `audit_backlog_limit=8192` prevents kernel audit buffer overflow during boot. #### Rules file: `/etc/audit/rules.d/cis.rules` Controls 4.1.4–4.1.17 are written as a static heredoc, with 4.1.12 (privileged commands) appended dynamically: ```bash 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!=4294967295 -k privileged"}' \ >> /etc/audit/rules.d/cis.rules ``` `-e 2` (immutable flag, 4.1.18) is appended last so it takes effect after all rules including the dynamic privileged-command list. #### Network environment path note (4.1.6) CIS references `/etc/sysconfig/network-scripts/` which does not exist in RHEL 10. Replaced with `/etc/NetworkManager/` which is the canonical location for NM keyfiles. #### auditd service ```bash systemctl enable auditd ``` `audit` package is a dependency of `audit-libs` which is pulled in transitively. No explicit `KS_Packages.cfg` entry required. --- ### 5.3 — sudo Hardening **File:** `/etc/sudoers.d/cis-sudo` (mode `0440`) ``` # 5.3.2 — require pty (prevents background sudo abuse) Defaults use_pty # 5.3.3 — log all sudo usage Defaults logfile=/var/log/sudo.log # credential caching limit Defaults timestamp_timeout=5 ``` ### 5.4.1 — Password Quality (pwquality) **File:** `/etc/security/pwquality.conf.d/cis.conf` ```ini # CIS 5.4.1 — password complexity requirements minlen = 14 minclass = 4 dcredit = -1 ucredit = -1 ocredit = -1 lcredit = -1 maxrepeat = 3 maxsequence = 3 ``` Applies to all interactive password changes. Does not affect pre-hashed passwords set in kickstart. ### 5.4.3 — Account Lockout (pam_faillock) **File:** `/etc/security/faillock.conf` ```ini # 5.4.3 — lock after 5 failures in a 15-minute window deny = 5 fail_interval = 900 unlock_time = 900 even_deny_root root_unlock_time = 60 ``` **Important:** This configuration is pre-staged but **not active** until PAM is wired to use it. `ipa-client-install` owns the authselect profile. After IPA enrolment, enable faillock: ```bash authselect enable-feature with-faillock ``` Do **not** run this in kickstart — IPA resets the authselect profile during enrolment. --- ## Deferred Controls ### 1.1.2 — /tmp as Separate Partition or tmpfs **Status:** Deferred pending dev review. **Reason:** `/var/tmp` may need `exec` permissions for some application stack components. Current kickstart uses `autopart --type=lvm` which places `/tmp` on the root LVM volume. Mounting `/tmp` as `tmpfs` or a separate partition requires validating that: 1. No application code writes large temporary files to `/tmp` that would exhaust a size-limited tmpfs 2. `/var/tmp` exec requirements are understood — CIS also recommends `noexec` on `/var/tmp`, which may conflict with application use **Action:** Revisit with dev team. If approved, add to kickstart: ``` %pre # ... partition layout %end ``` or post-install: ```bash echo "tmpfs /tmp tmpfs defaults,nodev,nosuid,noexec,size=2G 0 0" >> /etc/fstab ``` --- ## Excluded Controls ### 5.4.2 — Password Aging No password expiration policy for any accounts in this environment. `PASS_MAX_DAYS`, `PASS_MIN_DAYS`, `PASS_WARN_AGE` are left at system defaults. Service accounts and probe accounts do not rotate passwords on a schedule. ### squashfs Module Blacklist CIS recommends blacklisting `squashfs`. Excluded because Docker and Podman use squashfs for container image layers. If container usage is removed from these hosts, re-evaluate. ### udf Module Blacklist CIS recommends blacklisting `udf` (Universal Disk Format). Not prohibited in this environment and excluded from scope. ### AIDE Cron AIDE is installed (`aide` package in `KS_Packages.cfg`) but cron-based integrity scanning is managed centrally by a dedicated machine — not configured locally on each probe/server. Local AIDE cron is not added. ### authselect Profile Change `ipa-client-install` owns and resets the authselect profile. Any pre-kickstart authselect change would be overwritten during IPA enrolment. `faillock.conf` is pre-staged; `authselect enable-feature with-faillock` is a manual post-enrolment step. --- ## Kernel ASLR Note `kernel.randomize_va_space = 2` (full ASLR) is set in `30-cis-network.conf`. This is the RHEL 10 default but is explicitly set for audit compliance. No known application compatibility issues with this value. --- ## Future Review Items - **SELinux verification:** `audit2allow` outputs CIL format by default in RHEL 10 (changed from `.te`). Any local SELinux policy management scripts need to be updated. Verify in test VM. - **Docker/container network compatibility with `ip_forward=0`:** If containers use bridged networking, Docker daemon re-enables `ip_forward` at startup. Confirm no conflict with the sysctl set above.