Skip to main content

Ensure That The --read-only-port Is Disabled

More Info:​

The kubelet read-only port serves cluster and workload data without authentication or authorization. Setting it to 0 disables this unauthenticated endpoint.

Risk Level​

High

Address​

Security

Compliance Standards​

  • CIS EKS

Triage and Remediation​

Remediation​

Manual Steps
  1. On every worker node, check how the kubelet is configured:

    ps -fC kubelet
    • If you see --config=/var/lib/kubelet/config.yaml (or similar), you are using a config file.
    • If you see --read-only-port in the arguments, you are using executable arguments.
  2. If using the kubelet config file, edit it to disable the read-only port (on every worker node):

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

    If readOnlyPort is not present, add this line under the top-level config (YAML aligned appropriately):

    sudo sh -c 'printf "\nreadOnlyPort: 0\n" >> /var/lib/kubelet/config.yaml'
  3. If using executable arguments instead, edit the kubelet systemd drop-in to set the flag (on every worker node):

    sudo sed -i 's/\(--read-only-port=\)[0-9]\+/\10/' /etc/systemd/system/kubelet.service.d/10-kubelet-args.conf || \
    sudo sed -i 's#\(KUBELET_ARGS=".*\)"#\1 --read-only-port=0"#' /etc/systemd/system/kubelet.service.d/10-kubelet-args.conf
  4. Reload systemd and restart kubelet (on every worker node):

    sudo systemctl daemon-reload
    sudo systemctl restart kubelet.service
  5. Confirm kubelet is healthy (on every worker node):

    sudo systemctl status kubelet -l
  6. Verify that the kubelet is running with the read-only port disabled (on every worker node):

    ps -fC kubelet
    • For config-file usage, ensure no conflicting --read-only-port flag appears.
    • For argument usage, ensure you see --read-only-port=0 and no non‑zero value.
Using kubectl

kubectl cannot modify kubelet host-level configuration or process flags, so this finding cannot be remediated via the Kubernetes API. The change must be made directly on each worker node’s kubelet configuration and systemd unit as described in the Manual Steps section.

Automation
#!/usr/bin/env bash
#
# Disable kubelet read-only port on every worker node.
# Usage: run on each worker node as root (or with sudo).
#
# This script:
# - Sets readOnlyPort: 0 in kubelet config if present
# - Ensures --read-only-port=0 is set in kubelet systemd args if used
# - Restarts kubelet if changes were made
# - Verifies kubelet is running with read-only port disabled
#

set -euo pipefail

changed=0

backup_file() {
local f="$1"
if [ -f "$f" ] && [ ! -f "${f}.bak" ]; then
cp -p "$f" "${f}.bak"
fi
}

############################################
# 1) Handle kubelet config file (if present)
############################################

# Common kubelet config locations to check
CONFIG_CANDIDATES=(
"/etc/kubernetes/kubelet/kubelet-config.json"
"/var/lib/kubelet/config.yaml"
)

for cfg in "${CONFIG_CANDIDATES[@]}"; do
if [ -f "$cfg" ]; then
backup_file "$cfg"

# Detect format: JSON vs YAML (simple heuristic)
if grep -q 'readOnlyPort' "$cfg"; then
before="$(grep -n 'readOnlyPort' "$cfg" || true)"
else
before=""
fi

# If JSON (kubelet-config.json style)
if echo "$cfg" | grep -q '\.json$'; then
# If key exists, set to 0; if not, add it near top-level (simple jq-less edit)
if grep -q '"readOnlyPort"' "$cfg"; then
sed -i 's/"readOnlyPort"[[:space:]]*:[[:space:]]*[0-9]\+/"readOnlyPort": 0/' "$cfg"
else
# Insert after opening brace of top-level object
sed -i '0,/{/{s//{\
"readOnlyPort": 0,/' "$cfg"
fi
else
# Assume YAML
# If key exists, set to 0; otherwise append to end
if grep -q '^[[:space:]]*readOnlyPort:' "$cfg"; then
sed -i 's/^[[:space:]]*readOnlyPort:[[:space:]]*[0-9]\+/readOnlyPort: 0/' "$cfg"
else
printf '\nreadOnlyPort: 0\n' >> "$cfg"
fi
fi

after="$(grep -n 'readOnlyPort' "$cfg" || true)"
if [ "$before" != "$after" ]; then
echo "Updated readOnlyPort in $cfg:"
echo " before: ${before:-<none>}"
echo " after : ${after:-<none>}"
changed=1
fi
fi
done

##################################################
# 2) Handle kubelet systemd args (if used on node)
##################################################

UNIT_DROPIN="/etc/systemd/system/kubelet.service.d/10-kubelet-args.conf"

if [ -f "$UNIT_DROPIN" ]; then
backup_file "$UNIT_DROPIN"

# Ensure file has an Environment line with KUBELET_ARGS
if ! grep -q 'KUBELET_ARGS' "$UNIT_DROPIN"; then
# Append a basic KUBELET_ARGS definition if missing
cat <<'EOF' >> "$UNIT_DROPIN"

[Service]
Environment="KUBELET_ARGS="
EOF
fi

before_line="$(grep 'KUBELET_ARGS' "$UNIT_DROPIN" || true)"

# Normalize: if --read-only-port is present, replace its value with 0.
if grep -q -- '--read-only-port=' "$UNIT_DROPIN"; then
sed -i 's/--read-only-port=[0-9]\+/--read-only-port=0/g' "$UNIT_DROPIN"
else
# Append --read-only-port=0 inside the KUBELET_ARGS env var
# Works for lines like: Environment="KUBELET_ARGS=...existing..."
sed -i 's/\(Environment="[^"]*KUBELET_ARGS[^"]*=\)\([^"]*"\)/\1\2 --read-only-port=0"/' "$UNIT_DROPIN"
fi

after_line="$(grep 'KUBELET_ARGS' "$UNIT_DROPIN" || true)"

if [ "$before_line" != "$after_line" ]; then
echo "Updated KUBELET_ARGS in $UNIT_DROPIN:"
echo " before: ${before_line:-<none>}"
echo " after : ${after_line:-<none>}"
changed=1
fi
fi

########################################
# 3) Restart kubelet if any change made
########################################

if [ "$changed" -eq 1 ]; then
echo "Changes detected; reloading systemd and restarting kubelet..."
systemctl daemon-reload
systemctl restart kubelet.service
else
echo "No changes required; kubelet config already compliant."
fi

echo "kubelet status:"
systemctl status kubelet -l --no-pager || true

########################################
# 4) Verification: ensure flag is absent
# or set to 0 in kubelet process args
########################################

echo
echo "Verifying kubelet does not expose read-only port > 0:"
/bin/ps -fC kubelet || true

# Fail if we see an explicit non-zero read-only port
if /bin/ps -fC kubelet 2>/dev/null | grep -q -- '--read-only-port='; then
if /bin/ps -fC kubelet 2>/dev/null | grep -q -- '--read-only-port=0'; then
echo "Verification: kubelet is running with --read-only-port=0 in arguments."
else
echo "WARNING: kubelet still has a non-zero --read-only-port in its arguments."
exit 1
fi
else
echo "Verification: kubelet has no --read-only-port flag (defaults should be disabled by config)."
fi