The Linux kernel exposes hundreds of tunable parameters through the sysctl interface that control network behavior, memory protection, and file system security. Many of these defaults prioritize compatibility over security. By writing a hardening configuration to /etc/sysctl.d/, you can reduce the kernel attack surface, enable mitigations against common network attacks, and enforce memory safety features — all without installing any additional software. This tutorial covers the most impactful kernel hardening parameters for a RHEL 9 server.

Prerequisites

  • RHEL 9 system with sudo or root access
  • Basic understanding of TCP/IP networking concepts
  • Note: some network parameters such as IP forwarding must remain enabled on routers and Kubernetes nodes — adjust accordingly

Step 1 — Create the Hardening Configuration File

Place all hardening parameters in a single drop-in file under /etc/sysctl.d/. Files in this directory are processed in alphanumeric order at boot, after the main /etc/sysctl.conf. Using the 99- prefix ensures your settings are applied last and override any earlier defaults.

# Back up any existing custom sysctl config
sudo cp /etc/sysctl.conf /etc/sysctl.conf.bak 2>/dev/null || true

# Check current values of a few key parameters before changing them
sysctl net.ipv4.ip_forward
sysctl kernel.randomize_va_space
sysctl fs.protected_hardlinks

Step 2 — Configure Network Hardening Parameters

Network hardening parameters protect against IP spoofing, SYN flood attacks, ICMP-based attacks, and unauthorized packet routing through the host. These are safe to apply on any server that is not acting as a router.

sudo tee /etc/sysctl.d/99-hardening.conf > /dev/null << 'EOF'
##############################################################################
# NETWORK HARDENING
##############################################################################

# Disable IPv4 packet forwarding (only needed on routers/gateways)
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0

# Enable TCP SYN cookies to defend against SYN flood attacks
net.ipv4.tcp_syncookies = 1

# Ignore ICMP broadcast requests (smurf attack mitigation)
net.ipv4.icmp_echo_ignore_broadcasts = 1

# Ignore bogus ICMP error responses
net.ipv4.icmp_ignore_bogus_error_responses = 1

# Disable IP source routing (prevents packets from specifying their own route)
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

# Enable reverse path filtering (drop packets with impossible source addresses)
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Log packets with impossible source or destination addresses (martians)
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1

# Do not accept ICMP redirects (MITM prevention)
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

# Do not send ICMP redirects
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0

# Disable IPv6 router advertisements
net.ipv6.conf.all.accept_ra = 0
net.ipv6.conf.default.accept_ra = 0

EOF
echo "Network parameters written"

Step 3 — Configure Memory Protection Parameters

Memory protection parameters enable kernel-level mitigations against code injection and information disclosure. ASLR randomizes the location of the stack, heap, and libraries in memory, making exploits that rely on fixed addresses unreliable. Restricting access to dmesg and kernel pointers prevents unprivileged processes from harvesting addresses to use in privilege escalation attacks.

sudo tee -a /etc/sysctl.d/99-hardening.conf > /dev/null << 'EOF'

##############################################################################
# MEMORY PROTECTION
##############################################################################

# Enable full Address Space Layout Randomization (ASLR)
# 0 = disabled, 1 = conservative, 2 = full randomization
kernel.randomize_va_space = 2

# Restrict access to kernel ring buffer (dmesg) to root only
# Prevents unprivileged users from reading kernel addresses and messages
kernel.dmesg_restrict = 1

# Restrict kernel pointer exposure in /proc
# 0 = unrestricted, 1 = hashed for unprivileged, 2 = zeros for unprivileged
kernel.kptr_restrict = 2

# Restrict access to performance events to root only (prevents side-channel leaks)
kernel.perf_event_paranoid = 3

# Disable the SysRq key combination (prevents local console attacks)
kernel.sysrq = 0

# Restrict loading of kernel modules to root only
# (set to 1 if no runtime module loading is needed after boot)
# kernel.modules_disabled = 1

EOF
echo "Memory protection parameters written"

Step 4 — Configure File System Hardening Parameters

File system hardening parameters close two common privilege escalation vectors: hard link attacks (where an unprivileged user creates a hard link to a file they do not own, then exploits a race condition in a privileged program) and symlink attacks (where an attacker tricks a privileged program into following a symlink to a file in a directory the attacker owns).

sudo tee -a /etc/sysctl.d/99-hardening.conf > /dev/null << 'EOF'

##############################################################################
# FILE SYSTEM HARDENING
##############################################################################

# Protect against hard link attacks:
# Prevents unprivileged users from creating hard links to files they don't own
fs.protected_hardlinks = 1

# Protect against symlink attacks in world-writable sticky directories:
# Prevents following symlinks owned by other users in /tmp etc.
fs.protected_symlinks = 1

# Protect fifos in world-writable sticky directories
fs.protected_fifos = 2

# Protect regular files in world-writable sticky directories
fs.protected_regular = 2

EOF
echo "File system parameters written"

Step 5 — Apply the Configuration

Sysctl settings written to /etc/sysctl.d/ are applied automatically at boot. To apply them immediately in the running kernel without rebooting, use sysctl --system.

# Apply all sysctl.d files including the new hardening config
sudo sysctl --system

# View only the output from our file
sudo sysctl --system 2>&1 | grep "99-hardening"

# Alternatively, apply only the single file
sudo sysctl -p /etc/sysctl.d/99-hardening.conf

# Verify changes are active in the running kernel
sysctl kernel.randomize_va_space
sysctl net.ipv4.ip_forward
sysctl fs.protected_hardlinks
sysctl net.ipv4.tcp_syncookies

Step 6 — Verify All Hardening Parameters

After applying, verify all parameters have the expected values. This step is also useful as an audit check to run on systems you need to assess.

# Verify all parameters from the hardening file
while IFS='=' read -r key value; do
  # Skip comments and empty lines
  [[ "$key" =~ ^#.*$ || -z "$key" ]] && continue
  key=$(echo "$key" | tr -d ' ')
  expected=$(echo "$value" | tr -d ' ')
  actual=$(sysctl -n "$key" 2>/dev/null)
  if [ "$actual" = "$expected" ]; then
    echo "OK  : $key = $actual"
  else
    echo "FAIL: $key expected=$expected actual=$actual"
  fi
done < /dev/null | grep "net.ipv4.conf.all"

# Confirm no parameters failed to load (errors appear in system journal)
sudo journalctl -b | grep -i sysctl | grep -i error

Conclusion

You have created a comprehensive /etc/sysctl.d/99-hardening.conf that disables IP forwarding, enables SYN cookie protection, blocks ICMP broadcast and redirect attacks, enables reverse path filtering, enforces full ASLR, restricts dmesg and kernel pointer access, and enables hard link and symlink protections. These parameters are applied at boot via the sysctl drop-in directory and take effect immediately with sysctl --system. Together they address the majority of CIS RHEL 9 Benchmark Section 3 (Network Configuration) and Section 1.6 (Kernel Parameters) requirements.

Next steps: How to Configure firewalld on RHEL 9, How to Install and Configure AIDE on RHEL 9, and How to Audit Kernel Parameters with OpenSCAP on RHEL 9.