Ubuntu and RHEL Linux CIS Benchmark Hardening: sysctl Parameters, AppArmor/SELinux, and Automated Compliance Verification

Retool's new app builder is where AI-generated code ships safely
Building apps with AI is easy. Getting them to production safely is another story.
Linux servers deployed from standard cloud provider base images (Ubuntu 22.04 LTS, RHEL 9) do not meet the CIS Level 1 benchmark without additional hardening. The default settings are optimized for broad compatibility rather than security: ICMP redirects are accepted, ASLR may not be at full strength, AppArmor is in complain mode rather than enforce mode on Ubuntu, and SELinux is in permissive mode rather than enforcing mode on RHEL. These defaults are documented, systematic, and remediable.
The CIS benchmark provides a prioritized checklist and OpenSCAP provides automated assessment and remediation scripting, making Linux CIS hardening more accessible than manual configuration review. The key challenge is not identifying what needs to change — the benchmark provides that — but testing changes in a staging environment and applying them systematically without disrupting running services.
Hardening sequence: test in staging before production
CIS hardening changes range from zero-disruption (sysctl parameters applied with sysctl -p) to high-disruption (SELinux enforce mode blocking syscalls that services depend on). Applying changes in the wrong order or skipping staging validation is the most common reason hardening efforts cause production incidents. This section covers starting with sysctl parameters as the safest first change, using the auditd and AppArmor allow logs to identify what would break before switching to enforce mode, and monitoring application logs between each hardening phase to catch issues before they compound.
Apply sysctl hardening first as the lowest-disruption change
Apply sysctl parameter hardening as the first hardening step because it is fully reversible, does not affect running processes, and can be tested immediately with sysctl -p. Create /etc/sysctl.d/99-cis-hardening.conf with all CIS-required sysctl parameters and apply with sysctl -p /etc/sysctl.d/99-cis-hardening.conf without a reboot. Monitor application logs for 30 minutes after applying to confirm no services are affected. The parameters that occasionally affect services are net.ipv4.ip_forward = 0 (required on routing systems), net.ipv4.tcp_syncookies = 1 (occasionally conflicts with load balancer health check behavior), and kernel.randomize_va_space = 2 (rarely conflicts with older applications that hardcode memory addresses). These can be addressed by reverting the specific parameter while keeping the rest of the hardening in place.
Switch AppArmor or SELinux from complain/permissive to enforce mode only after 48 hours of AVC log review
The transition from AppArmor complain mode (Ubuntu) or SELinux permissive mode (RHEL) to enforce mode is the highest-risk CIS hardening step because it blocks operations that were previously allowed, potentially breaking services. Run in complain/permissive mode on production for 48 hours before switching to enforce mode, and review the audit log daily: on Ubuntu, grep /var/log/syslog for apparmor=ALLOWED to see what would be blocked; on RHEL, use ausearch -m avc --start recent to review recent AVC denials. For each legitimate operation appearing in the allow/deny log, configure the appropriate AppArmor profile exception or SELinux boolean before switching to enforce mode. This 48-hour review period catches service-specific exceptions that testing in staging may have missed due to different workload patterns.
Automated compliance: OpenSCAP and continuous verification
A server that passes the CIS benchmark on deployment day and drifts back toward default settings over 18 months of OS updates, package installations, and administrator changes provides only temporary security value. OpenSCAP automates compliance verification with oscap xccdf eval, produces HTML reports showing each control's pass/fail status, and can generate bash remediation scripts. Integrating OpenSCAP into the CI/CD deployment pipeline and scheduling monthly production scans provides the continuous evidence trail that separates a maintained hardened baseline from a one-time hardening event.
Integrate OpenSCAP assessment into the server deployment pipeline
Run an OpenSCAP CIS assessment as the final step in the server deployment pipeline before a new server is promoted to production status. In a CI/CD context, configure the Ansible hardening playbook as a provisioning step, then run the OpenSCAP assessment against the server and fail the pipeline if the CIS compliance score falls below your target (typically 80% or higher for Level 1 controls). This prevents deploying unhardened servers to production because a hardening step was skipped or failed silently. The OpenSCAP XCCDF result file generated in the pipeline can be archived as the compliance evidence artifact for the server's provisioning record.
Schedule monthly OpenSCAP scans to detect configuration drift
Schedule monthly OpenSCAP compliance scans on production servers using a cron job or Ansible playbook run triggered by a configuration management tool. Configuration drift — software package installations that modify security settings, OS updates that change default configurations, and manual changes by administrators — degrades the hardened baseline over time. Compare each month's OpenSCAP scan results against the previous month to identify newly failing controls. Investigate each new failure to determine whether it resulted from an intentional change (that needs to be documented as an exception) or an unintentional change (that needs to be reversed). Automating this detection prevents the common scenario where a server is hardened at deployment and gradually drifts back toward a default configuration over 12-18 months of production operation.
Briefings like this, every morning before 9am.
Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.
The bottom line
Ubuntu and RHEL Linux CIS benchmark hardening addresses the systematic configuration gaps in default Linux server deployments: sysctl network security parameters, AppArmor enforce mode (Ubuntu) or SELinux enforcing mode (RHEL), filesystem hardening with noexec/nosuid/nodev on temporary mounts, SSH configuration hardening, and disabled unnecessary services. Apply sysctl hardening first as the lowest-disruption change, then transition AppArmor/SELinux to enforce mode after 48 hours of audit log review in the production environment. Use OpenSCAP for automated assessment in the deployment pipeline and monthly drift detection. Ansible CIS hardening roles from ansible-lockdown automate the full CIS benchmark application across server fleets, reducing the manual configuration work to a single playbook run with pre-deployment check mode review.
Frequently asked questions
What are the most important sysctl security parameters to configure on Linux servers?
The highest-priority sysctl security parameters from the CIS Linux Benchmark: net.ipv4.ip_forward = 0 (disable IP forwarding on non-router systems), net.ipv4.conf.all.accept_redirects = 0 and net.ipv6.conf.all.accept_redirects = 0 (disable ICMP redirect acceptance which can be used for routing manipulation), net.ipv4.conf.all.log_martians = 1 (log packets with impossible source addresses for anomaly detection), net.ipv4.tcp_syncookies = 1 (enable SYN cookies for SYN flood protection), kernel.randomize_va_space = 2 (full ASLR), kernel.dmesg_restrict = 1 (restrict dmesg access to root only, preventing information disclosure of kernel addresses), fs.protected_hardlinks = 1 and fs.protected_symlinks = 1 (prevent privilege escalation via hardlink and symlink attacks in world-writable directories), kernel.core_uses_pid = 1 (include PID in core dump filenames), and net.ipv4.conf.all.send_redirects = 0 (disable ICMP redirect sending on non-router systems). Apply all settings to /etc/sysctl.d/99-cis-hardening.conf and run sysctl -p /etc/sysctl.d/99-cis-hardening.conf to apply.
How do I enable AppArmor enforce mode on Ubuntu without breaking services?
Enable AppArmor enforce mode safely by checking the current profile status first with aa-status, which shows profiles in enforce versus complain mode. Run aa-status | grep complain to list profiles currently in complain mode. Before switching a profile to enforce mode, review the AppArmor audit log (/var/log/syslog on Ubuntu, grep for apparmor=ALLOWED to see what would be blocked) to identify operations the service is performing that the current profile allows but that might be denied in enforce mode after a software update or configuration change. To switch all installed profiles to enforce mode: sudo aa-enforce /etc/apparmor.d/* which is safe for stock Ubuntu profiles that are well-tested. For custom application profiles: test by checking the complain log for 24 hours after a configuration change, confirm no legitimate operations appear in the deny log, then switch to enforce mode. Reload a modified profile with sudo apparmor_parser -r /etc/apparmor.d/profile_name.
How do I enable SELinux enforcing mode on RHEL without causing service failures?
Enable SELinux enforcing mode on RHEL by following a staged process to avoid service disruptions. First, check the current SELinux status with sestatus and getenforce. If SELinux is currently disabled (not just permissive), you must relabel the filesystem before enabling enforcing mode: set SELINUX=permissive in /etc/sysconfig/selinux, reboot (which triggers filesystem relabeling based on the SELinux policy), then review /var/log/audit/audit.log for AVC denials using ausearch -m avc which shows what would be blocked in enforcing mode. For each AVC denial, either configure the appropriate SELinux boolean (setsebool -P httpd_enable_homedirs on for the relevant service) or generate a custom policy module using audit2allow -a -M mymodule followed by semodule -i mymodule.pp. After confirming no unexpected AVC denials for 24-48 hours in permissive mode, switch to enforcing: setenforce 1 and set SELINUX=enforcing in /etc/sysconfig/selinux.
How do I configure /tmp and other temporary filesystem mounts with CIS-required security options?
The CIS benchmark requires mounting /tmp, /var/tmp, /dev/shm, and removable media with nodev (no device files), nosuid (no setuid execution), and noexec (no direct script execution) mount options to prevent these world-writable directories from being used to stage and execute malicious code. For /tmp on systems using systemd, override the default systemd-tmpfiles configuration: create /etc/systemd/system/tmp.mount with [Mount] options line: Options=mode=1777,strictatime,noexec,nodev,nosuid, then run systemctl daemon-reload and systemctl enable tmp.mount. For /var/tmp, add or modify the /var/tmp entry in /etc/fstab: /var/tmp tmpfs defaults,noexec,nodev,nosuid 0 0. For /dev/shm, add: none /dev/shm tmpfs defaults,noexec,nodev,nosuid 0 0 to /etc/fstab. Run mount -o remount /dev/shm to apply without a reboot. Verify with mount | grep /tmp to confirm the options are active.
How do I run an OpenSCAP CIS benchmark assessment on Ubuntu or RHEL?
Run an OpenSCAP assessment against the CIS benchmark using the oscap command-line tool with the appropriate XCCDF profile. On Ubuntu: install openscap-scanner and the Ubuntu SCAP content (apt install libopenscap8 ssg-debderived). Run the assessment with sudo oscap xccdf eval --profile xccdf_org.ssgproject.content_profile_cis_level1_server --report report.html --results results.xml /usr/share/xml/scap/ssg/content/ssg-ubuntu2204-xccdf.xml. On RHEL: install openscap-scanner and scap-security-guide (dnf install openscap-scanner scap-security-guide). Run: sudo oscap xccdf eval --profile xccdf_org.ssgproject.content_profile_cis --report report.html --results results.xml /usr/share/xml/scap/ssg/content/ssg-rhel9-xccdf.xml. The HTML report shows each CIS control with a pass/fail/not-applicable result and a description of the finding. Use the --remediation bash option to generate a remediation script: sudo oscap xccdf generate fix --profile cis --fix-type bash results.xml > remediate.sh, review the script before running, then execute to remediate failing controls automatically.
What SSH configuration changes does the CIS benchmark require?
The CIS Linux Benchmark SSH hardening requirements for /etc/ssh/sshd_config include: PermitRootLogin no (prevent direct root SSH login, require login as regular user and then sudo), MaxAuthTries 4 (limit authentication attempts per connection to reduce brute force risk), PermitEmptyPasswords no (require a password or key), Protocol 2 (SSH protocol 2 only, protocol 1 is cryptographically broken), X11Forwarding no (disable unless X11 application display is required), AllowTcpForwarding no (disable TCP tunnel creation through SSH unless specifically needed), ClientAliveInterval 300 and ClientAliveCountMax 0 (terminate idle sessions after 5 minutes), LoginGraceTime 60 (limit time allowed to complete authentication), PermitUserEnvironment no (prevent users from passing custom environment variables that could affect security), and Ciphers aes128-ctr,aes192-ctr,aes256-ctr (restrict to CTR mode AES ciphers, excluding CBC mode which has known padding oracle attacks). After editing sshd_config, run sshd -t to test the configuration syntax before restarting the SSH service.
How do I use Ansible to automate CIS hardening across a fleet of Linux servers?
Use the community-maintained Ansible CIS hardening role from the ansible-lockdown organization on GitHub (UBUNTU22-CIS for Ubuntu 22.04, RHEL9-CIS for RHEL 9) which implements the full CIS benchmark as an Ansible playbook with each control as a tagged task. Install the role with ansible-galaxy role install ansible-lockdown.UBUNTU22-CIS. Create a playbook that applies the role to your server inventory: configure the role variables to enable or disable specific sections (ubtu22cis_section1 through ubtu22cis_section6 cover the six CIS benchmark sections). Run the playbook in check mode first (ansible-playbook --check site.yml) to see what changes would be made without applying them. After reviewing the check mode output, run without check mode to apply. The role includes tags for each CIS control number, so you can run only specific sections: ansible-playbook site.yml --tags level1-server to apply only CIS Level 1 server controls. Use the role's built-in audit mode to generate a compliance report without making changes.
Sources & references
Free resources
Critical CVE Reference Card 2025–2026
25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.
Ransomware Incident Response Playbook
Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.
Get threat intel before your inbox does.
50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.
Unsubscribe anytime. We never sell your data.

Founder & Cybersecurity Evangelist, Decryption Digest
Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.
Win a $2,495 Black Hat pass.
Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.
