Kubelet TLS Cert File And Private Key File Arguments Set As
More Info:
Setting tlsCertFile and tlsPrivateKeyFile provides the kubelet with a proper serving certificate and key for its API. This ensures kubelet connections are secured with trusted TLS material.
Risk Level
Medium
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
On every control plane node, identify the current API server manifest and TLS files:
sudo ls -l /etc/kubernetes/manifests/kube-apiserver.yamlsudo grep -n "tls-cert-file" /etc/kubernetes/manifests/kube-apiserver.yaml || echo "no tls-cert-file set"sudo grep -n "tls-private-key-file" /etc/kubernetes/manifests/kube-apiserver.yaml || echo "no tls-private-key-file set"sudo ls -l /etc/kubernetes/pkiDecide which existing certificate/key pair you will use (for example,
/etc/kubernetes/pki/apiserver.crtand/etc/kubernetes/pki/apiserver.key), or provision new ones according to your PKI policy. -
If you need to generate a new serving certificate and key for the API server on this control plane node, create them (example using openssl; adjust CN/SANs to match your cluster and certificate policy):
cd /etc/kubernetes/pkisudo openssl req -newkey rsa:4096 -nodes -keyout apiserver.key \-out apiserver.csr \-subj "/CN=kube-apiserver" \-addext "subjectAltName=DNS:kubernetes,DNS:kubernetes.default,DNS:kubernetes.default.svc,DNS:kubernetes.default.svc.cluster.local,IP:10.96.0.1"# Sign with your cluster CA (example: /etc/kubernetes/pki/ca.crt and ca.key)sudo openssl x509 -req -in apiserver.csr -CA ca.crt -CAkey ca.key -CAcreateserial \-out apiserver.crt -days 365 -sha256sudo chmod 600 apiserver.keysudo chmod 644 apiserver.crt -
On every control plane node, edit the API server static pod manifest to set the TLS certificate and key flags (this edit will automatically restart the kube-apiserver pod when you save the file):
sudo cp /etc/kubernetes/manifests/kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml.bak.$(date +%s)sudo vi /etc/kubernetes/manifests/kube-apiserver.yamlIn the
command:section of the kube-apiserver container, ensure the following lines exist and point to the chosen files (adjust paths if different):- --tls-cert-file=/etc/kubernetes/pki/apiserver.crt- --tls-private-key-file=/etc/kubernetes/pki/apiserver.keySave and exit; kubelet will detect the manifest change and restart the API server pod with the new flags.
-
If the certificate and key are not yet mounted into the API server container path, ensure the manifest has appropriate volume and volumeMount entries (still on every control plane node editing
/etc/kubernetes/manifests/kube-apiserver.yaml):volumeMounts:- mountPath: /etc/kubernetes/pkiname: k8s-certsreadOnly: true...volumes:- name: k8s-certshostPath:path: /etc/kubernetes/pkitype: DirectoryOrCreateSave the file; kubelet will restart the API server pod again if you changed volumes.
-
After waiting 30–60 seconds for the static pod to restart, verify on each control plane node that the kube-apiserver process is running with the required flags:
/bin/ps -ef | grep kube-apiserver | grep -v grepConfirm the output includes both
--tls-cert-file=/etc/kubernetes/pki/apiserver.crtand--tls-private-key-file=/etc/kubernetes/pki/apiserver.key(or your chosen paths) for the running kube-apiserver process.
Using kubectl
kubectl cannot modify kube-apiserver process flags or the static pod manifest on the node. This finding must be fixed by editing /etc/kubernetes/manifests/kube-apiserver.yaml and related TLS files directly on every control plane node; see the Manual Steps section for exact host-level instructions.
Automation
#!/usr/bin/env bash
#
# Automation: Configure kube-apiserver --tls-cert-file and --tls-private-key-file
# Scope: run on every control plane node (with sudo)
#
# This script:
# - Backs up /etc/kubernetes/manifests/kube-apiserver.yaml
# - Ensures --tls-cert-file and --tls-private-key-file arguments are present
# - Uses placeholder paths you must replace with correct certificate/key paths
# - Verifies via the audit command
#
# NOTE: Editing a static pod manifest under /etc/kubernetes/manifests will cause
# the kube-apiserver pod to restart on this node.
set -euo pipefail
APISERVER_MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
BACKUP_DIR="/etc/kubernetes/manifests/backup-$(date +%Y%m%d-%H%M%S)"
# TODO: set these to the correct, existing cert and key paths for your environment
TLS_CERT_PATH="/etc/kubernetes/pki/apiserver.crt"
TLS_KEY_PATH="/etc/kubernetes/pki/apiserver.key"
run_on_control_plane_only() {
if [ ! -f "$APISERVER_MANIFEST" ]; then
echo "This node does not appear to be a control plane node (no $APISERVER_MANIFEST). Skipping."
exit 0
fi
}
require_root() {
if [ "$(id -u)" -ne 0 ]; then
echo "Run this script as root (sudo)."
exit 1
fi
}
validate_paths() {
if [ ! -f "$TLS_CERT_PATH" ]; then
echo "TLS certificate not found at $TLS_CERT_PATH"
echo "Update TLS_CERT_PATH in this script to a valid certificate file before re-running."
exit 1
fi
if [ ! -f "$TLS_KEY_PATH" ]; then
echo "TLS private key not found at $TLS_KEY_PATH"
echo "Update TLS_KEY_PATH in this script to a valid key file before re-running."
exit 1
fi
}
backup_manifest() {
mkdir -p "$BACKUP_DIR"
cp -a "$APISERVER_MANIFEST" "$BACKUP_DIR/kube-apiserver.yaml"
echo "Backed up $APISERVER_MANIFEST to $BACKUP_DIR/kube-apiserver.yaml"
}
ensure_arg() {
local arg_name="$1"
local arg_value="$2"
local file="$3"
# If argument already present, replace its value; if absent, append to command args.
if grep -q -- "$arg_name=" "$file"; then
# Replace existing value (handles both '--arg=val' forms)
sed -i "s#${arg_name}=[^\"'[:space:]]*#${arg_name}=${arg_value}#g" "$file"
else
# Append argument in the container command args. This assumes standard kubeadm-style manifest.
# Insert before the first occurrence of '--advertise-address' if present,
# otherwise just append as an extra - --arg line.
if grep -q -- "--advertise-address" "$file"; then
# Insert line before '--advertise-address'
# Works on typical YAML:
# - --some-arg
# - --advertise-address=...
sed -i "/--advertise-address/ i\ - ${arg_name}=${arg_value}" "$file"
else
# Append near the end of the args list: insert before the closing 'volumeMounts' or 'volumes'
if grep -q "volumeMounts:" "$file"; then
sed -i "/volumeMounts:/ i\ - ${arg_name}=${arg_value}" "$file"
else
# Fallback: append at end of file (still valid for static pod)
printf " - %s=%s\n" "$arg_name" "$arg_value" >> "$file"
fi
fi
fi
}
apply_fix() {
echo "Ensuring --tls-cert-file and --tls-private-key-file are configured in $APISERVER_MANIFEST"
ensure_arg "--tls-cert-file" "$TLS_CERT_PATH" "$APISERVER_MANIFEST"
ensure_arg "--tls-private-key-file" "$TLS_KEY_PATH" "$APISERVER_MANIFEST"
echo "Changes applied. kubelet will restart the kube-apiserver static pod automatically."
}
verify() {
echo "Waiting for kube-apiserver process to reflect new arguments..."
# Give kubelet some time to restart the static pod if it just changed
sleep 10
if /bin/ps -ef | grep kube-apiserver | grep -v grep >/dev/null 2>&1; then
echo "kube-apiserver process detected. Verifying TLS arguments..."
else
echo "kube-apiserver process not found yet. Current processes:"
/bin/ps -ef | grep kube-apiserver || true
exit 1
fi
# Show the relevant arguments for manual confirmation
/bin/ps -ef | grep kube-apiserver | grep -v grep | tr -s ' ' | sed 's/ /\n/g' | \
grep -E -- '--tls-cert-file|--tls-private-key-file' || true
# Automated check for both flags and correct values
if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -q -- "--tls-cert-file=${TLS_CERT_PATH}" \
&& /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -q -- "--tls-private-key-file=${TLS_KEY_PATH}"; then
echo "Verification successful: kube-apiserver is running with the desired --tls-cert-file and --tls-private-key-file."
else
echo "Verification FAILED: kube-apiserver does not show the expected TLS arguments."
echo "Inspect the kube-apiserver manifest and process output above to troubleshoot."
exit 1
fi
}
main() {
require_root
run_on_control_plane_only
validate_paths
backup_manifest
apply_fix
verify
}
main "$@"