OS and Kernel Hardening
Overview
Kernel and OS hardening focuses on reducing the attack surface of the node operating system itself. Every unnecessary package, service, or kernel feature is a potential entry point for attackers. The principle is straightforward: if you don't need it, remove it or disable it.
This section covers the host-level security measures that complement container-level controls like AppArmor, seccomp, and capabilities.
CKS Exam Context
While the exam is primarily focused on Kubernetes-level security, you may encounter questions that require SSH-ing into a node to:
- Disable unnecessary services
- Check or modify kernel parameters
- Verify installed packages
- Inspect the host OS configuration
Kernel Security Layers
Minimizing Host OS Attack Surface
Principle: Minimal Base OS
A Kubernetes node should run the minimum software necessary to function as a cluster member. Purpose-built container OSes include:
| OS | Description |
|---|---|
| Ubuntu Minimal / Server | Reduced package set, widely used |
| Amazon Linux 2 | AWS-optimized, minimal by default |
| Flatcar Container Linux | Immutable OS designed for containers |
| Bottlerocket | AWS container OS, read-only root |
| Talos Linux | Kubernetes-focused, API-managed, no SSH |
| Google Container-Optimized OS | GKE nodes, minimal and auto-updated |
Reducing Installed Packages
# List all installed packages (Debian/Ubuntu)
dpkg -l | wc -l
# List packages with descriptions
dpkg -l
# Remove unnecessary packages
sudo apt remove --purge <package-name>
# Remove unused dependencies
sudo apt autoremove
# List installed packages (RHEL/CentOS)
rpm -qa | wc -l
# Remove a package
sudo yum remove <package-name>
# or
sudo dnf remove <package-name>What to Remove
Common packages that should not be on a Kubernetes node:
- Desktop environments (GNOME, KDE, X11)
- Web browsers (firefox, chromium)
- Office suites (libreoffice)
- Development tools (gcc, make) -- unless needed for kernel modules
- FTP servers (vsftpd, proftpd)
- Mail servers (postfix, sendmail)
- Unused language runtimes (PHP, Ruby, Perl)
- Legacy remote access (telnet, rsh)
Checking for Unnecessary Software
# Find packages that provide network services
dpkg -l | grep -E '(apache|nginx|mysql|postgres|ftp|telnet|mail|samba)'
# Find setuid binaries (potential privilege escalation)
find / -perm -4000 -type f 2>/dev/null
# Find setgid binaries
find / -perm -2000 -type f 2>/dev/null
# Find world-writable files
find / -perm -0002 -type f 2>/dev/null
# Find world-writable directories
find / -perm -0002 -type d 2>/dev/nullDisabling Unnecessary Services
Every running service is a potential attack vector. Disable services that are not required for Kubernetes node operation.
Listing and Disabling Services
# List all active services
systemctl list-units --type=service --state=running
# List all enabled services (start on boot)
systemctl list-unit-files --type=service --state=enabled
# Disable and stop a service
sudo systemctl disable --now <service-name>
# Check if a service is running
systemctl status <service-name>
# Mask a service (prevent it from being started at all)
sudo systemctl mask <service-name>Services to Keep on a Kubernetes Node
| Service | Purpose | Required? |
|---|---|---|
kubelet | Kubernetes node agent | Yes |
containerd / cri-o | Container runtime | Yes |
systemd-resolved | DNS resolution | Yes |
systemd-networkd / NetworkManager | Network management | Yes |
sshd | Remote access (for management) | Usually yes |
chrony / ntp | Time synchronization | Yes |
auditd | Audit logging | Recommended |
Services to Disable on a Kubernetes Node
# Disable common unnecessary services
sudo systemctl disable --now cups.service # Print service
sudo systemctl disable --now avahi-daemon.service # mDNS/DNS-SD
sudo systemctl disable --now bluetooth.service # Bluetooth
sudo systemctl disable --now apache2.service # Web server
sudo systemctl disable --now nginx.service # Web server
sudo systemctl disable --now postfix.service # Mail
sudo systemctl disable --now smbd.service # Samba/SMB
sudo systemctl disable --now nmbd.service # NetBIOS
sudo systemctl disable --now snapd.service # Snap packages
sudo systemctl disable --now ModemManager.service # Modemsysctl Security Parameters
sysctl controls kernel parameters at runtime. Several parameters are critical for node security.
Network Security Parameters
# Prevent IP forwarding (unless node is a router/gateway)
# Note: Kubernetes REQUIRES ip_forward to be enabled for pod networking
sudo sysctl -w net.ipv4.ip_forward=1 # Keep enabled for Kubernetes
# Disable source routing (prevent IP spoofing)
sudo sysctl -w net.ipv4.conf.all.accept_source_route=0
sudo sysctl -w net.ipv4.conf.default.accept_source_route=0
# Enable reverse path filtering (prevent IP spoofing)
sudo sysctl -w net.ipv4.conf.all.rp_filter=1
sudo sysctl -w net.ipv4.conf.default.rp_filter=1
# Disable ICMP redirects (prevent routing manipulation)
sudo sysctl -w net.ipv4.conf.all.accept_redirects=0
sudo sysctl -w net.ipv4.conf.default.accept_redirects=0
sudo sysctl -w net.ipv4.conf.all.send_redirects=0
# Ignore ICMP broadcast requests (prevent Smurf attacks)
sudo sysctl -w net.ipv4.icmp_echo_ignore_broadcasts=1
# Enable SYN cookies (prevent SYN flood attacks)
sudo sysctl -w net.ipv4.tcp_syncookies=1
# Log suspicious packets (martians)
sudo sysctl -w net.ipv4.conf.all.log_martians=1Kernel Security Parameters
# Restrict kernel pointer leaks (prevent KASLR bypass)
sudo sysctl -w kernel.kptr_restrict=2
# Restrict dmesg access to root
sudo sysctl -w kernel.dmesg_restrict=1
# Restrict perf_event access
sudo sysctl -w kernel.perf_event_paranoid=3
# Disable SysRq key (prevent system manipulation)
sudo sysctl -w kernel.sysrq=0
# Restrict ptrace scope (prevent process tracing)
# 0 = no restrictions, 1 = only child processes, 2 = admin only, 3 = disabled
sudo sysctl -w kernel.yama.ptrace_scope=2
# Enable ASLR (Address Space Layout Randomization)
sudo sysctl -w kernel.randomize_va_space=2
# Restrict core dumps
sudo sysctl -w fs.suid_dumpable=0
# Restrict unprivileged user namespaces (prevent container escape vectors)
sudo sysctl -w kernel.unprivileged_userns_clone=0Making sysctl Changes Persistent
# Add to /etc/sysctl.d/99-kubernetes-hardening.conf
cat <<EOF | sudo tee /etc/sysctl.d/99-kubernetes-hardening.conf
# Network hardening
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.log_martians = 1
# Kernel hardening
kernel.kptr_restrict = 2
kernel.dmesg_restrict = 1
kernel.perf_event_paranoid = 3
kernel.sysrq = 0
kernel.yama.ptrace_scope = 2
kernel.randomize_va_space = 2
fs.suid_dumpable = 0
EOF
# Apply all sysctl settings
sudo sysctl --systemKubernetes Pod sysctl Settings
Kubernetes allows pods to set certain "safe" sysctl parameters:
apiVersion: v1
kind: Pod
metadata:
name: sysctl-pod
spec:
securityContext:
sysctls:
- name: net.ipv4.ip_local_port_range
value: "1024 65535"
- name: net.ipv4.tcp_syncookies
value: "1"
containers:
- name: app
image: nginx:1.27Safe vs Unsafe Sysctls
Kubernetes categorizes sysctls as:
- Safe sysctls: Namespaced and can be set per-pod without affecting the host. Allowed by default.
kernel.shm_rmid_forcednet.ipv4.ip_local_port_rangenet.ipv4.tcp_syncookiesnet.ipv4.ping_group_rangenet.ipv4.ip_unprivileged_port_start
- Unsafe sysctls: Could affect other pods or the host. Must be explicitly allowed by the kubelet flag
--allowed-unsafe-sysctls.
/proc and /sys Filesystem Restrictions
/proc Filesystem
The /proc filesystem exposes kernel and process information. It is a critical target for attackers because it reveals:
- Process memory maps (
/proc/<pid>/maps) - Kernel configuration (
/proc/config.gz) - System information (
/proc/cpuinfo,/proc/meminfo) - Kernel symbols (
/proc/kallsyms) - Process credentials (
/proc/<pid>/status)
Default Container /proc Masking
Kubernetes and container runtimes mask sensitive /proc paths by default:
| Masked Path | Why It's Sensitive |
|---|---|
/proc/acpi | Hardware information |
/proc/kcore | Physical memory access |
/proc/keys | Kernel keyring |
/proc/latency_stats | Performance data |
/proc/timer_list | Timing information (side-channel attacks) |
/proc/timer_stats | Timer statistics |
/proc/sched_debug | Scheduler debug info |
/proc/scsi | SCSI device info |
/proc/sys | Made read-only (prevents sysctl changes from containers) |
/sys Filesystem
The /sys filesystem provides access to kernel subsystems, devices, and drivers:
# By default, /sys is mounted read-only in containers
# This prevents containers from:
# - Modifying device configurations
# - Changing kernel parameters
# - Accessing hardware directly
# Privileged containers get read-write /sys access -- another reason to avoid privileged modeKernel Module Restrictions
Why Kernel Modules Are Dangerous
Kernel modules run with full kernel privileges. If an attacker can load a kernel module, they can:
- Execute arbitrary code in kernel space
- Bypass all security controls
- Install rootkits
- Access any memory or device
Restricting Module Loading
# Disable module loading entirely (irreversible until reboot)
echo 1 | sudo tee /proc/sys/kernel/modules_disabled
# Blacklist specific dangerous modules
cat <<EOF | sudo tee /etc/modprobe.d/kubernetes-hardening.conf
# Disable uncommon network protocols
install cramfs /bin/true
install freevxfs /bin/true
install jffs2 /bin/true
install hfs /bin/true
install hfsplus /bin/true
install squashfs /bin/true
install udf /bin/true
# Disable uncommon network protocols
install dccp /bin/true
install sctp /bin/true
install rds /bin/true
install tipc /bin/true
# Disable USB storage (if not needed)
install usb-storage /bin/true
EOFCaution
Setting kernel.modules_disabled=1 prevents any module loading, including legitimate ones needed by Kubernetes networking. Only use this after ensuring all required modules are already loaded.
SSH Hardening
If SSH is enabled on nodes (for maintenance), it should be hardened:
# /etc/ssh/sshd_config recommended settings
# Disable root login
PermitRootLogin no
# Use key-based authentication only
PasswordAuthentication no
PubkeyAuthentication yes
# Disable empty passwords
PermitEmptyPasswords no
# Set maximum authentication attempts
MaxAuthTries 3
# Set login grace time
LoginGraceTime 30
# Disable X11 forwarding
X11Forwarding no
# Disable agent forwarding
AllowAgentForwarding no
# Use SSH protocol 2 only (default in modern versions)
Protocol 2
# Restrict SSH to specific users/groups
AllowUsers kubeadmin
# Or: AllowGroups kubernetes-admins
# Set idle timeout
ClientAliveInterval 300
ClientAliveCountMax 2# Apply SSH changes
sudo systemctl restart sshd
# Verify SSH configuration
sudo sshd -T | grep -E '(permitrootlogin|passwordauthentication|maxauthtries)'File System Hardening
Important File Permissions
# Secure critical Kubernetes files
sudo chmod 600 /etc/kubernetes/admin.conf
sudo chmod 600 /etc/kubernetes/scheduler.conf
sudo chmod 600 /etc/kubernetes/controller-manager.conf
sudo chmod 644 /etc/kubernetes/kubelet.conf
# Secure etcd data directory
sudo chmod 700 /var/lib/etcd
# Secure PKI directory
sudo chmod 700 /etc/kubernetes/pki
sudo chmod 600 /etc/kubernetes/pki/*.key
# Check permissions
ls -la /etc/kubernetes/
ls -la /etc/kubernetes/pki/Mount Options
# Check current mounts
mount | grep -E '(nosuid|noexec|nodev)'
# Recommended mount options for /tmp
# In /etc/fstab:
# tmpfs /tmp tmpfs defaults,nosuid,nodev,noexec 0 0
# nosuid - Ignore setuid/setgid bits
# nodev - Do not interpret device files
# noexec - Do not allow execution of binariesHardening Checklist
Node Hardening Checklist
Packages:
- [ ] Remove unnecessary packages (desktop, dev tools, servers)
- [ ] Keep only packages required for Kubernetes node operation
- [ ] Enable automatic security updates
Services:
- [ ] Disable unnecessary services (cups, avahi, bluetooth, etc.)
- [ ] Mask services that should never start
- [ ] Verify only required services are running
Kernel:
- [ ] Apply recommended sysctl parameters
- [ ] Restrict kernel module loading
- [ ] Enable ASLR (
kernel.randomize_va_space=2) - [ ] Restrict ptrace (
kernel.yama.ptrace_scope=2) - [ ] Restrict dmesg access (
kernel.dmesg_restrict=1)
Network:
- [ ] Disable ICMP redirects
- [ ] Enable SYN cookies
- [ ] Enable reverse path filtering
- [ ] Disable source routing
Access:
- [ ] Harden SSH configuration
- [ ] Disable root SSH login
- [ ] Use key-based authentication
- [ ] Set proper file permissions on Kubernetes configs
Filesystem:
- [ ] Mount /tmp with
nosuid,nodev,noexec - [ ] Secure Kubernetes PKI files
- [ ] Secure etcd data directory
Quick Reference
Exam Speed Reference
# Check running services
systemctl list-units --type=service --state=running
# Disable a service
sudo systemctl disable --now <service>
# Check sysctl value
sysctl <parameter>
# Set sysctl value
sudo sysctl -w <parameter>=<value>
# Apply all sysctl configs
sudo sysctl --system
# Find setuid binaries
find / -perm -4000 -type f 2>/dev/null
# Check installed packages
dpkg -l | wc -l
# Check SSH configuration
sudo sshd -TKey Exam Takeaways
- Minimize packages -- remove anything not needed for Kubernetes node operation
- Disable services -- every running service is an attack vector
- Apply sysctl hardening -- especially network and kernel security parameters
- Restrict /proc and /sys -- Kubernetes does this by default, but privileged containers bypass it
- Harden SSH -- disable root login, use keys, limit attempts
- The exam may require you to SSH into a node and check/fix OS-level configurations
- Remember:
net.ipv4.ip_forward=1must stay enabled for Kubernetes networking