Kubelet Read Only Port Secured
More Info:
The kubelet read-only port exposes cluster data without authentication and should be disabled by setting readOnlyPort to 0.
Risk Level
High
Address
Security
Compliance Standards
- CIS AKS
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
On every worker node, check how kubelet is started:
/bin/ps -fC kubeletInspect the output to see whether
--config=/var/lib/kubelet/config.yamlis used and whether a--read-only-portflag is present. -
If using the kubelet config file
/var/lib/kubelet/config.yaml(common with kubeadm), edit it on every worker node and setreadOnlyPortto0:sudo sed -i 's/^[[:space:]]*readOnlyPort:.*/readOnlyPort: 0/' /var/lib/kubelet/config.yamlIf
readOnlyPortis not present, add it under the top-level fields (align indentation with other keys):sudo sed -i '1ireadOnlyPort: 0' /var/lib/kubelet/config.yaml -
If kubelet is using a systemd unit flag instead of (or in addition to) the config file, edit
/etc/systemd/system/kubelet.service.d/10-kubeadm.confon every worker node and ensure--read-only-port=0is set in the kubelet arguments (either inKUBELET_SYSTEM_PODS_ARGSor the relevantKUBELET_*variable):sudo sed -i 's/--read-only-port=[0-9]\+/--read-only-port=0/g' /etc/systemd/system/kubelet.service.d/10-kubeadm.confIf no
--read-only-portis present, append it to the kubelet options line, for example:sudo sed -i 's#\(KUBELET_CONFIG_ARGS=".*\)"#\1 --read-only-port=0"#' /etc/systemd/system/kubelet.service.d/10-kubeadm.conf -
Reload systemd and restart kubelet on every worker node (this will temporarily disrupt workloads on that node while kubelet restarts):
sudo systemctl daemon-reloadsudo systemctl restart kubelet.service -
Verify on every worker node that kubelet no longer exposes a nonzero read-only port:
/bin/ps -fC kubeletConfirm that:
- There is no
--read-only-portflag with a value other than0, and - If present as a flag, it is
--read-only-port=0.
If relying solely on the config file, you may additionally confirm the setting:
grep -i 'readOnlyPort' /var/lib/kubelet/config.yaml - There is no
Using kubectl
kubectl cannot change the kubelet’s readOnlyPort setting because it is controlled by host-level configuration on each worker node (/var/lib/kubelet/config.yaml and/or the systemd unit kubelet.service). To remediate this finding, make the changes directly on every worker node as described in the Manual Steps section.
Automation
#!/usr/bin/env bash
#
# Harden kubelet read-only port on this worker node.
# - Sets readOnlyPort: 0 in /var/lib/kubelet/config.yaml (YAML-aware)
# - Ensures any --read-only-port flag is set to 0
# - Restarts kubelet and verifies
#
# Run on: every worker node (as root)
# Safe to re-run (idempotent).
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"
backup_file() {
local f="$1"
if [ -f "$f" ] && [ ! -f "$f$BACKUP_SUFFIX" ]; then
cp -p "$f" "$f$BACKUP_SUFFIX"
fi
}
ensure_readonlyport_in_config() {
if [ ! -f "$KUBELET_CONFIG" ]; then
echo "WARN: $KUBELET_CONFIG not found, skipping config.yaml edit"
return
fi
backup_file "$KUBELET_CONFIG"
# If key exists at top level, replace its value; otherwise append it.
if grep -Eq '^[[:space:]]*readOnlyPort:' "$KUBELET_CONFIG"; then
sed -i 's/^[[:space:]]*readOnlyPort:.*/readOnlyPort: 0/' "$KUBELET_CONFIG"
else
# Ensure file ends with a newline
sed -i -e '$a\' "$KUBELET_CONFIG"
printf '\nreadOnlyPort: 0\n' >> "$KUBELET_CONFIG"
fi
}
ensure_readonlyport_flag() {
if [ ! -f "$SYSTEMD_DROPIN" ]; then
echo "WARN: $SYSTEMD_DROPIN not found, skipping systemd drop-in edit"
return
fi
backup_file "$SYSTEMD_DROPIN"
# Ensure Environment line exists
if ! grep -q '^Environment=' "$SYSTEMD_DROPIN"; then
echo 'Environment="KUBELET_SYSTEM_PODS_ARGS="' >> "$SYSTEMD_DROPIN"
fi
# Normalize to one Environment line (no-op if already single)
# Then ensure it contains --read-only-port=0 exactly once.
# 1) Remove any existing --read-only-port flag
sed -i 's/--read-only-port=[^" ]*//g' "$SYSTEMD_DROPIN"
# 2) Trim double spaces left behind
sed -i 's/ / /g' "$SYSTEMD_DROPIN"
# 3) Append --read-only-port=0 inside the Environment value
perl -pi -e '
if (/^Environment="KUBELET_SYSTEM_PODS_ARGS="(.*)"\s*$/) {
my $v = $1;
$v =~ s/\s+$//;
$_ = "Environment=\"KUBELET_SYSTEM_PODS_ARGS=$v --read-only-port=0\"\n";
}
' "$SYSTEMD_DROPIN"
}
restart_kubelet() {
systemctl daemon-reload
systemctl restart kubelet.service
}
verify() {
echo "Verification: checking kubelet process flags and config..."
/bin/ps -fC kubelet || {
echo "FAIL: kubelet process not found after restart"
return 1
}
# Check no non-zero read-only-port flag
if /bin/ps -fC kubelet | grep -q -- '--read-only-port='; then
if /bin/ps -fC kubelet | grep -q -- '--read-only-port=0'; then
echo "OK: kubelet started with --read-only-port=0"
else
echo "FAIL: kubelet running with non-zero --read-only-port"
/bin/ps -fC kubelet
return 1
fi
else
echo "OK: kubelet has no --read-only-port flag (uses config.yaml)"
fi
if [ -f "$KUBELET_CONFIG" ]; then
if grep -Eq '^[[:space:]]*readOnlyPort:[[:space:]]*0[[:space:]]*$' "$KUBELET_CONFIG"; then
echo "OK: $KUBELET_CONFIG has readOnlyPort: 0"
else
echo "WARN: $KUBELET_CONFIG does not show readOnlyPort: 0"
grep -n 'readOnlyPort' "$KUBELET_CONFIG" || true
fi
fi
echo "Current kubelet command line:"
/bin/ps -fC kubelet
}
main() {
ensure_readonlyport_in_config
ensure_readonlyport_flag
restart_kubelet
verify
}
main "$@"