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
Remediation​
Manual Steps
-
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-portin the arguments, you are using executable arguments.
- If you see
-
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.yamlIf
readOnlyPortis 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' -
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 -
Reload systemd and restart kubelet (on every worker node):
sudo systemctl daemon-reloadsudo systemctl restart kubelet.service -
Confirm kubelet is healthy (on every worker node):
sudo systemctl status kubelet -l -
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-portflag appears. - For argument usage, ensure you see
--read-only-port=0and no non‑zero value.
- For config-file usage, ensure no conflicting
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