Skip to main content

API Server Should Set Etcd CA File

More Info:

Verifies that --etcd-cafile is set so the API server verifies the etcd server certificate against a trusted certificate authority.

Risk Level

High

Address

Security

Compliance Standards

  • CIS Kubernetes

Triage and Remediation

Remediation

Manual Steps
  1. Log in to each control plane node

    ssh root@<control-plane-node-ip>
  2. Confirm the current ownership of the API server manifest file

    stat -c '%n %U:%G' /etc/kubernetes/manifests/kube-apiserver.yaml
  3. Change the file owner and group to root:root (if not already)

    chown root:root /etc/kubernetes/manifests/kube-apiserver.yaml
  4. (Optional) Reconfirm file permissions are appropriate (readable only by root and system processes)

    chmod 600 /etc/kubernetes/manifests/kube-apiserver.yaml
    ls -l /etc/kubernetes/manifests/kube-apiserver.yaml
  5. Repeat steps 1–4 on every control plane node in the cluster.

  6. Verification (on each control plane node)

    /bin/sh -c 'if test -e /etc/kubernetes/manifests/kube-apiserver.yaml; then stat -c %U:%G /etc/kubernetes/manifests/kube-apiserver.yaml; fi'
Using kubectl

kubectl cannot modify file ownership or other host-level settings for /etc/kubernetes/manifests/kube-apiserver.yaml on control plane nodes. This finding must be fixed directly on each control plane node’s filesystem; see the Manual Steps section for the exact commands to run over SSH.

Automation
#!/usr/bin/env bash
#
# Automation: Fix ownership of kube-apiserver manifest on control plane nodes
# Target: run on every control plane node (as root)
#
# Usage: sudo /path/to/fix-kube-apiserver-owner.sh

set -euo pipefail

MANIFEST_PATH="/etc/kubernetes/manifests/kube-apiserver.yaml"
DESIRED_OWNER="root"
DESIRED_GROUP="root"
CHANGED=0

echo "Checking kube-apiserver manifest ownership on this control plane node..."

if [ ! -e "${MANIFEST_PATH}" ]; then
echo "WARNING: ${MANIFEST_PATH} does not exist on this node; nothing to do."
exit 0
fi

# Get current ownership
CURRENT_OWNER="$(stat -c %U "${MANIFEST_PATH}")"
CURRENT_GROUP="$(stat -c %G "${MANIFEST_PATH}")"

echo "Current ownership: ${CURRENT_OWNER}:${CURRENT_GROUP}"
echo "Desired ownership: ${DESIRED_OWNER}:${DESIRED_GROUP}"

# Apply fix only if needed
if [ "${CURRENT_OWNER}" != "${DESIRED_OWNER}" ] || [ "${CURRENT_GROUP}" != "${DESIRED_GROUP}" ]; then
echo "Updating ownership to ${DESIRED_OWNER}:${DESIRED_GROUP}..."
chown "${DESIRED_OWNER}:${DESIRED_GROUP}" "${MANIFEST_PATH}"
CHANGED=1
else
echo "Ownership already correct; no change needed."
fi

# Verification (same as audit command)
echo "Verifying ownership..."
VERIFY_OUTPUT="$(stat -c %U:%G "${MANIFEST_PATH}")"
echo "stat -c %U:%G ${MANIFEST_PATH} -> ${VERIFY_OUTPUT}"

if [ "${VERIFY_OUTPUT}" != "${DESIRED_OWNER}:${DESIRED_GROUP}" ]; then
echo "ERROR: Ownership verification failed; expected ${DESIRED_OWNER}:${DESIRED_GROUP}."
exit 1
fi

if [ "${CHANGED}" -eq 1 ]; then
echo "Ownership successfully updated and verified."
else
echo "No changes were required; ownership is correct and verified."
fi

exit 0