Ensure Read Only Port Is Secured
More Info:
Disable the read-only port.
Risk Level
Medium
Address
Security
Compliance Standards
- APRA CPS 234 (Australia)
- BSI C5 (Germany)
- Brazil LGPD
- CCPA / CPRA (California)
- CIS AKS
- CIS Critical Security Controls v8
- 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)
- NIS2 Directive
- 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
Remediation
Manual Steps
-
Edit the Kubelet config file on every worker node
sudo sed -i 's/^[[:space:]]*readOnlyPort:.*/readOnlyPort: 0/' /var/lib/kubelet/config.yaml || \echo 'readOnlyPort: 0' | sudo tee -a /var/lib/kubelet/config.yaml -
If the Kubelet uses command-line flags instead of config.yaml, edit the systemd drop-in on every worker node
sudo sed -i 's/--read-only-port=[0-9]\+/--read-only-port=0/g' /etc/systemd/system/kubelet.service.d/10-kubeadm.confIf the flag is missing, add
--read-only-port=0to the kubelet arguments in that file (typically in theKUBELET_KUBEADM_ARGSor related variable). -
Reload systemd configuration on every worker node
sudo systemctl daemon-reload -
Restart kubelet on every worker node
sudo systemctl restart kubelet.service -
Verify kubelet is running with read-only port disabled on every worker node
/bin/ps -fC kubelet | grep -- '--read-only-port=0' || echo "Using config file; check for readOnlyPort: 0 in /var/lib/kubelet/config.yaml"
Using kubectl
kubectl cannot modify kubelet process flags or its config file on worker nodes, so this finding cannot be fixed through the Kubernetes API. The required change must be made on each worker node’s host configuration (for example /var/lib/kubelet/config.yaml or the kubelet systemd unit); see the Manual Steps section for the exact remediation.
Automation
#!/usr/bin/env bash
#
# Harden kubelet read-only port on all worker nodes (run via SSH or automation tool).
# Idempotent: safe to re-run.
#
# Usage (on a machine with SSH access to workers):
# WORKER_NODES="worker1 worker2" ./secure-kubelet-readonly-port.sh
#
set -euo pipefail
WORKER_NODES="${WORKER_NODES:-}"
if [ -z "${WORKER_NODES}" ]; then
echo "ERROR: Set WORKER_NODES to a space-separated list of worker node hostnames/IPs."
exit 1
fi
SSH_OPTS="-o StrictHostKeyChecking=no -o BatchMode=yes"
remote_script='
set -euo pipefail
echo "=== Host: $(hostname) ==="
# 1) If kubelet config file exists, ensure readOnlyPort: 0 is set
CFG="/var/lib/kubelet/config.yaml"
if [ -f "$CFG" ]; then
echo "[INFO] Found $CFG, updating readOnlyPort..."
# Create a timestamped backup once
if [ ! -f "${CFG}.bak" ]; then
cp "$CFG" "${CFG}.bak"
echo "[INFO] Backup created at ${CFG}.bak"
fi
# If readOnlyPort key exists, set it to 0; otherwise append at end (YAML root)
if grep -qE "^[[:space:]]*readOnlyPort:" "$CFG"; then
sed -i -E "s/^([[:space:]]*readOnlyPort:).*/\1 0/" "$CFG"
else
printf "\nreadOnlyPort: 0\n" >> "$CFG"
fi
fi
# 2) If kubelet is configured via systemd flags, ensure --read-only-port=0 is present
UNIT_DROPIN="/etc/systemd/system/kubelet.service.d/10-kubeadm.conf"
UPDATED_SYSTEMD=0
if [ -f "$UNIT_DROPIN" ]; then
echo "[INFO] Found $UNIT_DROPIN, ensuring --read-only-port=0 in KUBELET_SYSTEM_PODS_ARGS or ExecStart..."
if ! grep -q -- "--read-only-port=0" "$UNIT_DROPIN"; then
# Prefer editing KUBELET_SYSTEM_PODS_ARGS if present
if grep -q "KUBELET_SYSTEM_PODS_ARGS" "$UNIT_DROPIN"; then
sed -i -E "s@(KUBELET_SYSTEM_PODS_ARGS=.*)@\1 --read-only-port=0@" "$UNIT_DROPIN"
else
# Fallback: append to ExecStart line
sed -i -E "s@^(ExecStart=/usr/bin/kubelet.*)@\1 --read-only-port=0@" "$UNIT_DROPIN"
fi
UPDATED_SYSTEMD=1
else
echo "[INFO] --read-only-port=0 already present in $UNIT_DROPIN"
fi
fi
# 3) Reload and restart kubelet if needed
if [ -f "$CFG" ] || [ "$UPDATED_SYSTEMD" -eq 1 ]; then
echo "[INFO] Reloading systemd and restarting kubelet (this will restart kubelet)..."
systemctl daemon-reload
systemctl restart kubelet.service
fi
# 4) Verification: ensure kubelet is not listening on a read-only port
echo "[INFO] Verifying kubelet process arguments..."
/bin/ps -fC kubelet || true
if /bin/ps -fC kubelet | grep -q -- "--read-only-port"; then
echo "[WARN] kubelet still has a --read-only-port flag. Investigate additional unit files or configs."
else
echo "[OK] kubelet has no --read-only-port flag in process args."
fi
echo "[INFO] Additional check: kubelet should not listen on 10255 (default read-only port) ..."
if command -v ss >/dev/null 2>&1; then
ss -ltnp | grep ":10255" || echo "[OK] No listener on TCP 10255 detected."
elif command -v netstat >/dev/null 2>&1; then
netstat -ltnp | grep ":10255" || echo "[OK] No listener on TCP 10255 detected."
else
echo "[WARN] Neither ss nor netstat available to confirm port 10255."
fi
echo
'
for node in $WORKER_NODES; do
echo "===== Processing worker node: $node ====="
ssh $SSH_OPTS "$node" "$remote_script"
done
echo "All done."