Ensure Root CA File Argument Is Appropriate
More Info:
Allow pods to verify the API servers serving certificate before establishing connections.
Risk Level
Low
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
On every control plane node, back up the existing manifest:
sudo cp -a /etc/kubernetes/manifests/kube-controller-manager.yaml /etc/kubernetes/manifests/kube-controller-manager.yaml.bak -
On the same node, identify the appropriate root CA bundle file present on the host (coordinate with your PKI/security team if unsure). Common examples include:
ls -l /etc/kubernetes/pki/ca.crtls -l /etc/ssl/certs/ca-bundle.crtls -l /etc/ssl/certs/ca-certificates.crt -
Edit the controller manager manifest on the control plane node to configure the root CA file (replace the example path with the correct bundle you identified in step 2):
sudo vi /etc/kubernetes/manifests/kube-controller-manager.yamlUnder the
command:orargs:list forkube-controller-manager, add (or update) the flag, for example:- --root-ca-file=/etc/kubernetes/pki/ca.crtSave and exit. Because this is a static pod manifest, the kube-controller-manager pod will be automatically restarted by the kubelet when the file changes.
-
(If needed) Ensure the configured file is readable by the kube-controller-manager container on the control plane node:
sudo ls -l /etc/kubernetes/pki/ca.crtIf the file is not already accessible in the pod via a volume mount, add an appropriate
hostPathvolume andvolumeMountinkube-controller-manager.yamlpointing to the directory that contains the CA file, then save the manifest again to trigger a restart. -
Wait for the kube-controller-manager pod to restart and become Running on the control plane node:
sudo crictl pods | grep kube-controller-manager || sudo docker ps | grep kube-controller-manager -
Verification on every control plane node (derived from the audit command): confirm the running process includes the
--root-ca-fileflag with the correct path:/bin/ps -ef | grep kube-controller-manager | grep -v grepCheck that the output shows
--root-ca-file=/etc/kubernetes/pki/ca.crt(or the exact path you configured).
Using kubectl
kubectl cannot modify the kube-controller-manager static pod manifest or its process flags, so this finding cannot be fixed via the Kubernetes API. To remediate, you must edit /etc/kubernetes/manifests/kube-controller-manager.yaml directly on every control plane node as described in the Manual Steps section.
Automation
#!/usr/bin/env bash
#
# Automation: Ensure kube-controller-manager has --root-ca-file set
# Scope: Run on every control plane node (with root privileges)
#
# This script:
# - Backs up /etc/kubernetes/manifests/kube-controller-manager.yaml
# - Ensures --root-ca-file=/etc/kubernetes/pki/ca.crt is present
# - Is idempotent and safe to re-run
# - Verifies the running process flags
#
# NOTE:
# - Editing a static pod manifest under /etc/kubernetes/manifests will
# cause the kube-controller-manager pod to be restarted by the kubelet.
set -euo pipefail
MANIFEST="/etc/kubernetes/manifests/kube-controller-manager.yaml"
BACKUP_DIR="/etc/kubernetes/manifests/backup-$(date +%Y%m%d)"
ROOT_CA_PATH="/etc/kubernetes/pki/ca.crt"
FLAG_NAME="--root-ca-file"
FLAG_VALUE="${FLAG_NAME}=${ROOT_CA_PATH}"
require_root() {
if [ "$(id -u)" -ne 0 ]; then
echo "ERROR: This script must be run as root on each control plane node." >&2
exit 1
fi
}
check_files() {
if [ ! -f "${MANIFEST}" ]; then
echo "ERROR: Manifest not found: ${MANIFEST}" >&2
exit 1
fi
if [ ! -f "${ROOT_CA_PATH}" ]; then
echo "ERROR: Root CA file not found: ${ROOT_CA_PATH}" >&2
echo " Adjust ROOT_CA_PATH in this script if your CA bundle is elsewhere." >&2
exit 1
fi
}
backup_manifest() {
mkdir -p "${BACKUP_DIR}"
local base
base="$(basename "${MANIFEST}")"
if [ ! -f "${BACKUP_DIR}/${base}" ]; then
cp -p "${MANIFEST}" "${BACKUP_DIR}/${base}"
echo "Backup created at ${BACKUP_DIR}/${base}"
else
echo "Backup already exists at ${BACKUP_DIR}/${base}, not overwriting."
fi
}
ensure_flag_in_manifest() {
# If flag already set with correct value, do nothing
if grep -qE "[[:space:]]${FLAG_NAME}=${ROOT_CA_PATH}([[:space:]]|$|\"|')" "${MANIFEST}"; then
echo "Manifest already contains ${FLAG_VALUE}, no change needed."
return
fi
# If flag present with wrong value, replace it
if grep -q "${FLAG_NAME}=" "${MANIFEST}"; then
echo "Updating existing ${FLAG_NAME} value in manifest to ${ROOT_CA_PATH}."
# Replace any existing --root-ca-file=<something> token with the desired one
# Handles lines in args: [ "...", "--root-ca-file=/old", ... ]
sed -i -E "s#${FLAG_NAME}=[^\"'[:space:]]*#${FLAG_VALUE}#g" "${MANIFEST}"
return
fi
# Otherwise, add the flag under the command/args section.
# Try to append to an existing args: list if present.
if grep -q '^\s*args:\s*$' "${MANIFEST}"; then
echo "Adding ${FLAG_VALUE} to existing args list in manifest."
# Insert a new "- --root-ca-file=..." line after the 'args:' line
awk -v flag="${FLAG_VALUE}" '
/^\s*args:\s*$/ && !added {
print $0
print " - " flag
added=1
next
}
{ print $0 }
' "${MANIFEST}" > "${MANIFEST}.tmp"
mv "${MANIFEST}.tmp" "${MANIFEST}"
else
# Fallback: append a minimal args section with the flag under the container spec.
echo "No args list found; appending args section with ${FLAG_VALUE}."
awk -v flag="${FLAG_VALUE}" '
/- name: kube-controller-manager/ && !added {
print $0
getline
print $0
print " args:"
print " - " flag
added=1
next
}
{ print $0 }
' "${MANIFEST}" > "${MANIFEST}.tmp"
mv "${MANIFEST}.tmp" "${MANIFEST}"
fi
}
wait_for_pod_restart() {
echo "Waiting up to 120 seconds for kube-controller-manager static pod to restart..."
local timeout=120
local waited=0
while [ "${waited}" -lt "${timeout}" ]; do
if /bin/ps -ef | grep '[k]ube-controller-manager' >/dev/null 2>&1; then
# Extra small delay to allow full startup
sleep 5
return
fi
sleep 5
waited=$((waited + 5))
done
echo "WARNING: kube-controller-manager process not detected after ${timeout} seconds." >&2
}
verify_process_flag() {
echo "Verifying that kube-controller-manager is running with ${FLAG_VALUE} ..."
if /bin/ps -ef | grep '[k]ube-controller-manager' | grep -q "${FLAG_VALUE}"; then
echo "PASS: kube-controller-manager process includes ${FLAG_VALUE}"
/bin/ps -ef | grep '[k]ube-controller-manager'
return 0
else
echo "FAIL: kube-controller-manager process does not include ${FLAG_VALUE}" >&2
/bin/ps -ef | grep '[k]ube-controller-manager' || true
return 1
fi
}
main() {
require_root
check_files
backup_manifest
ensure_flag_in_manifest
echo "Manifest updated (or already compliant). kubelet will restart the static pod automatically."
# Give kubelet some time to notice and restart; then verify.
wait_for_pod_restart
verify_process_flag
}
main "$@"