Skip to main content

Ensure Protect Kernel Defaults Argument Is Enabled

More Info:

Protect tuned kernel parameters from overriding kubelet default kernel parameter values.

Risk Level

High

Address

Security

Compliance Standards

  • APRA CPS 234 (Australia)
  • BSI C5 (Germany)
  • Brazil LGPD
  • CCPA / CPRA (California)
  • CIS Critical Security Controls v8
  • CIS EKS
  • CMMC 2.0
  • CSA Cloud Controls Matrix v4
  • DPDPA
  • Digital Operational Resilience Act (EU)
  • Essential 8
  • ISO/IEC 27017
  • ISO/IEC 27018
  • ISO/IEC 27701
  • KSA PDPL
  • MAS Technology Risk Management (Singapore)
  • MITRE ATT&CK (Cloud)
  • NIST SP 800-171
  • NYDFS 23 NYCRR 500
  • SWIFT Customer Security Controls Framework
  • Sarbanes-Oxley IT General Controls
  • UK NCSC Cyber Assessment Framework

Triage and Remediation

Remediation

Manual Steps
  1. Edit the Kubelet config file on every worker node

    sudo vi /var/lib/kubelet/config.yaml

    In the top-level YAML (same level as kind: / apiVersion:), add or set:

    protectKernelDefaults: true
  2. (If also using kubelet flags) Edit the kubelet systemd drop-in on every worker node

    sudo vi /etc/systemd/system/kubelet.service.d/10-kubeadm.conf

    In the KUBELET_SYSTEM_PODS_ARGS (or the Environment=/ExecStart= line that holds kubelet flags), ensure this flag is present (or add it):

    --protect-kernel-defaults=true
  3. Reload systemd and restart kubelet on every worker node

    sudo systemctl daemon-reload
    sudo systemctl restart kubelet.service
  4. Verify kubelet is running with protect-kernel-defaults enabled on each worker node

    /bin/ps -fC kubelet | grep -- --protect-kernel-defaults

    Confirm that the output includes --protect-kernel-defaults=true.

Using kubectl

kubectl cannot modify kubelet process flags or the kubelet config file on worker nodes, so this setting cannot be fixed via Kubernetes API objects. To remediate, you must change /var/lib/kubelet/config.yaml or the kubelet systemd unit on every worker node as described in the Manual Steps section.

Automation
#!/usr/bin/env bash
#
# Enable protectKernelDefaults for kubelet on each worker node.
# Run this on every worker node as root.
# Safe to re-run; it will only adjust config if needed.
set -euo pipefail

KUBELET_CONFIG="/var/lib/kubelet/config.yaml"
SYSTEMD_DROPIN="/etc/systemd/system/kubelet.service.d/10-kubeadm.conf"

echo "[*] Ensuring kubelet protectKernelDefaults is enabled..."

fix_config_file() {
if [ ! -f "$KUBELET_CONFIG" ]; then
echo "[-] $KUBELET_CONFIG not found; skipping file-based configuration."
return
fi

if ! command -v python3 >/dev/null 2>&1; then
echo "[-] python3 is required for safe YAML editing; please install it."
return 1
fi

echo "[*] Updating $KUBELET_CONFIG (if needed)..."
python3 << 'PYEOF'
import sys
from pathlib import Path

cfg_path = Path("/var/lib/kubelet/config.yaml")
data = cfg_path.read_text()

# Minimal, structure-preserving update: ensure a top-level line
# 'protectKernelDefaults: true' exists and is set to true.
lines = data.splitlines()
out = []
found = False
for line in lines:
if line.lstrip().startswith("protectKernelDefaults:"):
# Normalize to 'protectKernelDefaults: true'
indent = line[:len(line) - len(line.lstrip())]
out.append(f"{indent}protectKernelDefaults: true")
found = True
else:
out.append(line)

if not found:
# Append at end as a top‑level key
if out and out[-1].strip() != "":
out.append("")
out.append("protectKernelDefaults: true")

new_data = "\n".join(out) + ("\n" if not out or not out[-1].endswith("\n") else "")
if new_data != data:
cfg_path.write_text(new_data)
PYEOF
}

fix_systemd_dropin() {
if [ ! -f "$SYSTEMD_DROPIN" ]; then
echo "[-] $SYSTEMD_DROPIN not found; skipping systemd flag-based configuration."
return
fi

echo "[*] Ensuring --protect-kernel-defaults=true is present in $SYSTEMD_DROPIN..."

# Ensure the KUBELET_SYSTEM_PODS_ARGS variable exists and contains the flag.
if ! grep -q '^Environment="KUBELET_SYSTEM_PODS_ARGS=' "$SYSTEMD_DROPIN"; then
# Add a new Environment line with the flag
echo 'Environment="KUBELET_SYSTEM_PODS_ARGS=--protect-kernel-defaults=true"' >> "$SYSTEMD_DROPIN"
else
# Update existing line to include the flag exactly once
tmp="$(mktemp)"
awk '
/^Environment="KUBELET_SYSTEM_PODS_ARGS=/ {
line=$0
sub(/^Environment="KUBELET_SYSTEM_PODS_ARGS=/,"",line)
sub(/"$/,"",line)
args=line
has_flag=0
n=split(args, a, " ")
out=""
for (i=1;i<=n;i++) {
if (a[i] == "--protect-kernel-defaults=true") has_flag=1
if (a[i] != "") {
if (out=="") out=a[i]; else out=out" "a[i]
}
}
if (!has_flag) {
if (out=="") out="--protect-kernel-defaults=true"
else out=out" --protect-kernel-defaults=true"
}
print "Environment=\"KUBELET_SYSTEM_PODS_ARGS=" out "\""
next
}
{ print }
' "$SYSTEMD_DROPIN" > "$tmp"
mv "$tmp" "$SYSTEMD_DROPIN"
fi
}

# Apply fixes
fix_config_file || true
fix_systemd_dropin || true

echo "[*] Reloading systemd and restarting kubelet..."
systemctl daemon-reload
systemctl restart kubelet.service

echo "[*] Verification: checking kubelet process arguments and config..."
/bin/ps -fC kubelet || { echo "[-] kubelet process not found"; exit 1; }

# Confirm the flag is set on the process OR in the config file
if /bin/ps -fC kubelet | grep -q -- '--protect-kernel-defaults=true'; then
echo "[+] kubelet is running with --protect-kernel-defaults=true"
else
echo "[*] --protect-kernel-defaults flag not visible in process args; checking config file..."
if [ -f "$KUBELET_CONFIG" ] && grep -q '^[[:space:]]*protectKernelDefaults:[[:space:]]*true' "$KUBELET_CONFIG"; then
echo "[+] protectKernelDefaults: true is set in $KUBELET_CONFIG"
else
echo "[-] protectKernelDefaults is not confirmed as enabled; manual review required."
exit 1
fi
fi

echo "[*] Done."

Additional Reading: