Skip to main content

Client Certificate Authorities File Ownership Set To

More Info:

The kubelet client certificate authorities file should be owned by root:root so only privileged users can modify the trust store. Incorrect ownership could allow tampering with client authentication.

Risk Level

Medium

Address

Security

Compliance Standards

  • CIS Kubernetes

Triage and Remediation

Remediation

Manual Steps
  1. On every worker node, identify the kubelet client CA file path (if set explicitly):

    ps -ef | grep kubelet | grep -v apiserver | grep -- --client-ca-file=

    If no --client-ca-file flag is present, use the default path /etc/kubernetes/pki/ca.crt.

  2. On every worker node, set the ownership of the client CA file to root:root (replace the path if you found a different one in step 1):

    sudo chown root:root /etc/kubernetes/pki/ca.crt
  3. On every worker node, confirm the ownership is now correct:

    stat -c %U:%G /etc/kubernetes/pki/ca.crt

    The output must be:

    root:root
Using kubectl

kubectl cannot change file ownership on worker node filesystems, including /etc/kubernetes/pki/ca.crt, because this is a host-level configuration. To remediate this finding, you must run the appropriate chown command directly on every worker node; see the Manual Steps section for the exact commands.

Automation
#!/usr/bin/env bash
#
# Fix ownership of kubelet client CA file (CIS Kubernetes 4.1.8)
# Scope: run on every worker node (can be run on control planes as well; it is safe)
# Idempotent: yes

set -euo pipefail

echo "[INFO] Detecting kubelet --client-ca-file path (if specified)..."

# Try to detect the client CA file from kubelet process args
CAFILE="$(ps -ef \
| grep kubelet \
| grep -v apiserver \
| grep -- '--client-ca-file=' \
| awk -F '--client-ca-file=' '{print $2}' \
| awk '{print $1}' \
| uniq || true)"

# Fall back to default if not set
if [ -z "${CAFILE}" ]; then
CAFILE="/etc/kubernetes/pki/ca.crt"
echo "[INFO] --client-ca-file flag not found, using default: ${CAFILE}"
else
echo "[INFO] Detected --client-ca-file: ${CAFILE}"
fi

# Ensure the file exists
if [ ! -e "${CAFILE}" ]; then
echo "[WARN] Client CA file does not exist: ${CAFILE}"
echo "[WARN] Nothing to change on this node."
exit 0
fi

echo "[INFO] Current ownership of ${CAFILE}:"
stat -c '%n %U:%G %a' "${CAFILE}"

# Apply required ownership (idempotent)
echo "[INFO] Setting ownership of ${CAFILE} to root:root ..."
chown root:root "${CAFILE}"

echo "[INFO] Ownership updated. Verifying..."

OWNER_GROUP="$(stat -c '%U:%G' "${CAFILE}")"
echo "[INFO] Post-change ownership of ${CAFILE}: ${OWNER_GROUP}"

if [ "${OWNER_GROUP}" != "root:root" ]; then
echo "[ERROR] Failed to set ownership of ${CAFILE} to root:root"
exit 1
fi

echo "[INFO] Verification passed: ${CAFILE} is owned by root:root"

# Re-run the benchmark audit logic for explicit confirmation
echo "[INFO] Running audit-style verification..."

CAFILE_AUDIT="$(ps -ef \
| grep kubelet \
| grep -v apiserver \
| grep -- '--client-ca-file=' \
| awk -F '--client-ca-file=' '{print $2}' \
| awk '{print $1}' \
| uniq || true)"

if [ -z "${CAFILE_AUDIT}" ]; then
CAFILE_AUDIT="/etc/kubernetes/pki/ca.crt"
fi

if [ -e "${CAFILE_AUDIT}" ]; then
echo -n "[INFO] Audit ownership for ${CAFILE_AUDIT}: "
stat -c '%U:%G' "${CAFILE_AUDIT}"
else
echo "[WARN] Audit path ${CAFILE_AUDIT} does not exist."
fi

echo "[INFO] Completed ownership remediation on this node."

Usage (run on every worker node over SSH):

ssh <worker-node> 'bash -s' < fix_client_ca_ownership.sh