Kubelet Kubeconfig File Permissions Set To 600 Or More
More Info:
The kubelet.conf kubeconfig file holds credentials the kubelet uses to authenticate to the API server. Permissions of 600 or more restrictive prevent non-privileged users from reading those credentials.
Risk Level
Medium
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
On every worker node, check the current permissions of the kubelet kubeconfig file:
stat -c permissions=%a /etc/kubernetes/kubelet.conf -
On every worker node, set the kubelet kubeconfig file permissions to 600:
chmod 600 /etc/kubernetes/kubelet.conf -
(Optional, recommended) On every worker node, ensure the file is owned by root:
chown root:root /etc/kubernetes/kubelet.conf -
On every worker node, verify the new permissions match the benchmark requirement:
stat -c permissions=%a /etc/kubernetes/kubelet.conf
Using kubectl
kubectl cannot modify file permissions on node-local paths like /etc/kubernetes/kubelet.conf; this must be fixed directly on every worker node’s host filesystem. Use the guidance in the Manual Steps section to adjust the permissions and verify the change.
Automation
#!/usr/bin/env bash
#
# Harden kubelet.conf permissions on all worker nodes.
# Usage:
# 1) Create an inventory file with one worker node (IP or hostname) per line, e.g.:
# /etc/kubernetes/worker-nodes.txt
# 2) Run:
# bash secure-kubelet-kubeconfig.sh /etc/kubernetes/worker-nodes.txt
#
# Requirements:
# - Run from any machine with SSH access to every worker node.
# - SSH key-based auth to each node as a user with sudo privileges.
# - 'stat', 'chmod', and 'sudo' available on the worker nodes.
set -euo pipefail
INVENTORY_FILE="${1:-}"
if [[ -z "${INVENTORY_FILE}" || ! -f "${INVENTORY_FILE}" ]]; then
echo "Usage: $0 /path/to/worker-nodes.txt" >&2
exit 1
fi
SSH_USER="${SSH_USER:-$(whoami)}"
SSH_OPTS="${SSH_OPTS:--o BatchMode=yes -o StrictHostKeyChecking=accept-new}"
REMOTE_FILE="/etc/kubernetes/kubelet.conf"
TARGET_PERMS="600"
echo "Using SSH user: ${SSH_USER}"
echo "Worker node inventory: ${INVENTORY_FILE}"
echo "Target permissions for ${REMOTE_FILE}: ${TARGET_PERMS}"
echo
while IFS= read -r NODE || [[ -n "$NODE" ]]; do
# Skip empty lines and comments
[[ -z "$NODE" || "$NODE" =~ ^# ]] && continue
echo "==== Processing worker node: ${NODE} ===="
# Check if file exists
if ! ssh ${SSH_OPTS} "${SSH_USER}@${NODE}" "test -e '${REMOTE_FILE}'"; then
echo " [SKIP] ${REMOTE_FILE} not found on ${NODE}"
continue
fi
# Ensure permissions are 600 (idempotent: running chmod 600 repeatedly is safe)
ssh ${SSH_OPTS} "${SSH_USER}@${NODE}" "sudo chmod ${TARGET_PERMS} '${REMOTE_FILE}'"
# Verification (adapted from audit command)
PERMS=$(ssh ${SSH_OPTS} "${SSH_USER}@${NODE}" "/bin/sh -c 'if test -e \"${REMOTE_FILE}\"; then stat -c permissions=%a \"${REMOTE_FILE}\"; fi'")
if [[ "${PERMS}" == "permissions=${TARGET_PERMS}" ]]; then
echo " [OK] ${REMOTE_FILE} permissions on ${NODE} are ${PERMS}"
else
echo " [WARN] ${REMOTE_FILE} permissions on ${NODE} are ${PERMS}, expected permissions=${TARGET_PERMS}" >&2
fi
echo
done < "${INVENTORY_FILE}"
echo "Completed kubelet.conf permission hardening on all listed worker nodes."