Skip to main content

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

Manual Steps
  1. On every worker node, check the current permissions of the kubelet kubeconfig file:

    stat -c permissions=%a /etc/kubernetes/kubelet.conf
  2. On every worker node, set the kubelet kubeconfig file permissions to 600:

    chmod 600 /etc/kubernetes/kubelet.conf
  3. (Optional, recommended) On every worker node, ensure the file is owned by root:

    chown root:root /etc/kubernetes/kubelet.conf
  4. 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."