Skip to main content

Verify Read Only Port Argument Is Set 0

More Info:​

Disable the read-only port.

Risk Level​

Medium

Address​

Security

Compliance Standards​

  • CIS Kubernetes

Triage and Remediation​

Remediation​

Manual Steps
  1. On every worker node, check how kubelet is configured (file vs flags):

    ps -fC kubelet

    Inspect the command line: if you see --config=/var/lib/kubelet/config.yaml it is using the config file; if you see --read-only-port= it is using flags.

  2. If using the kubelet config file, edit it to disable the read-only port:

    sudo sed -i 's/^[[:space:]]*readOnlyPort:.*/readOnlyPort: 0/' /var/lib/kubelet/config.yaml

    If there is no readOnlyPort line, add it under the top-level kubeletConfiguration block, for example:

    sudo sh -c 'printf "\nreadOnlyPort: 0\n" >> /var/lib/kubelet/config.yaml'
  3. If using command-line arguments, edit the kubelet systemd drop-in on each worker node:

    sudo sed -i 's/--read-only-port=[0-9]\+/--read-only-port=0/' /etc/systemd/system/kubelet.service.d/10-kubeadm.conf

    If --read-only-port is missing, add it to the KUBELET_SYSTEM_PODS_ARGS (or the line with other -- flags), for example:

    sudo sed -i 's#^\(.*KUBELET_SYSTEM_PODS_ARGS=.*\)"#\1 --read-only-port=0"#' /etc/systemd/system/kubelet.service.d/10-kubeadm.conf
  4. On every worker node, reload systemd and restart kubelet (this will restart the kubelet and may briefly impact pod scheduling/health reporting on that node):

    sudo systemctl daemon-reload
    sudo systemctl restart kubelet.service
  5. Verify on every worker node that kubelet is running with the read-only port disabled:

    ps -fC kubelet

    Confirm either that:

    • the kubelet command line contains --read-only-port=0, or
    • kubelet is using /var/lib/kubelet/config.yaml and that file contains readOnlyPort: 0.
Using kubectl

kubectl cannot modify kubelet process flags or its config file on worker nodes; this setting must be changed directly on each node’s /var/lib/kubelet/config.yaml or in the kubelet systemd unit. Refer to the Manual Steps section for the exact on-node configuration and restart instructions.

Automation
#!/usr/bin/env bash
#
# Fix: Ensure kubelet read-only port is disabled (readOnlyPort: 0)
# Scope: every worker node
#
# Usage:
# Run as root on each worker node:
# bash ./fix-kubelet-readonlyport.sh
#
# Idempotent: safe to re-run.

set -euo pipefail

KUBELET_CONFIG="/var/lib/kubelet/config.yaml"
SYSTEMD_DROPIN="/etc/systemd/system/kubelet.service.d/10-kubeadm.conf"
BACKUP_SUFFIX=".$(date +%Y%m%d%H%M%S).bak"

log() { printf '[%s] %s\n' "$(date -u +%Y-%m-%dT%H:%M:%SZ)" "$*"; }

require_root() {
if [ "$(id -u)" -ne 0 ]; then
log "ERROR: This script must be run as root."
exit 1
fi
}

backup_file() {
local f="$1"
if [ -f "$f" ]; then
cp -p "$f" "$f$BACKUP_SUFFIX"
log "Backup created: $f$BACKUP_SUFFIX"
fi
}

ensure_readonlyport_in_config() {
if [ ! -f "$KUBELET_CONFIG" ]; then
log "Kubelet config file not found at $KUBELET_CONFIG, skipping file-based config."
return 1
fi

backup_file "$KUBELET_CONFIG"

if grep -qE '^\s*readOnlyPort:' "$KUBELET_CONFIG"; then
# Replace existing key
sed -i 's/^\(\s*readOnlyPort:\).*/\1 0/' "$KUBELET_CONFIG"
log "Updated existing readOnlyPort entry to 0 in $KUBELET_CONFIG"
else
# Append key at top-level (2 space indent is acceptable for this scalar)
printf '\nreadOnlyPort: 0\n' >> "$KUBELET_CONFIG"
log "Appended readOnlyPort: 0 to $KUBELET_CONFIG"
fi

return 0
}

ensure_readonlyport_in_systemd() {
if [ ! -f "$SYSTEMD_DROPIN" ]; then
log "Systemd drop-in not found at $SYSTEMD_DROPIN, skipping CLI-arg config."
return 1
fi

backup_file "$SYSTEMD_DROPIN"

# Ensure KUBELET_SYSTEM_PODS_ARGS exists in Environment line
if grep -q 'KUBELET_SYSTEM_PODS_ARGS' "$SYSTEMD_DROPIN"; then
:
else
# Add an Environment line if missing
echo 'Environment="KUBELET_SYSTEM_PODS_ARGS="' >> "$SYSTEMD_DROPIN"
log "Added KUBELET_SYSTEM_PODS_ARGS environment definition to $SYSTEMD_DROPIN"
fi

# Remove any existing --read-only-port flag
sed -i 's/--read-only-port=[^" ]*//g' "$SYSTEMD_DROPIN"

# Add --read-only-port=0 into KUBELET_SYSTEM_PODS_ARGS
# If the var is empty, just set this flag; otherwise append.
perl -0777 -pi -e '
s/(Environment="[^"]*KUBELET_SYSTEM_PODS_ARGS=)([^"]*)"/
my $prefix = $1; my $val = $2;
$val =~ s/\s+$//;
if ($val =~ /--read-only-port=0\b/) { $prefix.$val."\"" }
elsif ($val eq "") { $prefix."--read-only-port=0\"" }
else { $prefix.$val." --read-only-port=0\"" }
/eg
' "$SYSTEMD_DROPIN"

log "Ensured --read-only-port=0 is present in KUBELET_SYSTEM_PODS_ARGS in $SYSTEMD_DROPIN"
return 0
}

restart_kubelet() {
log "Reloading systemd and restarting kubelet (this will restart the kubelet process)..."
systemctl daemon-reload
systemctl restart kubelet.service
log "kubelet restarted."
}

verify() {
log "Verifying kubelet read-only port is disabled..."

# Check via ps flags
if /bin/ps -fC kubelet 2>/dev/null | grep -q -- '--read-only-port=0'; then
log "Verification: kubelet process has --read-only-port=0 flag."
else
log "WARNING: kubelet process does not show --read-only-port=0 flag in ps output."
fi

# If config file exists, also verify its content
if [ -f "$KUBELET_CONFIG" ]; then
if grep -qE '^\s*readOnlyPort:\s*0\b' "$KUBELET_CONFIG"; then
log "Verification: $KUBELET_CONFIG contains readOnlyPort: 0"
else
log "WARNING: $KUBELET_CONFIG does not contain readOnlyPort: 0"
fi
fi

# Final display of kubelet command line for manual confirmation
log "Current kubelet command line:"
/bin/ps -fC kubelet || true
}

main() {
require_root

local cfg_ok=1
local sysd_ok=1

if ensure_readonlyport_in_config; then
cfg_ok=0
fi

if ensure_readonlyport_in_systemd; then
sysd_ok=0
fi

if [ "$cfg_ok" -ne 0 ] && [ "$sysd_ok" -ne 0 ]; then
log "ERROR: Neither $KUBELET_CONFIG nor $SYSTEMD_DROPIN could be updated. Please review manually."
exit 1
fi

restart_kubelet
verify
}

main "$@"

Additional Reading:​