Service Account Private Key File Argument Is Appropriate
More Info:
Explicitly set a service account private key file for service accounts on the controller manager.
Risk Level
Low
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
On every control plane node, back up the controller manager static pod manifest:
sudo cp -a /etc/kubernetes/manifests/kube-controller-manager.yaml \/etc/kubernetes/manifests/kube-controller-manager.yaml.bak -
Identify (or create if needed) the service account private key file on the control plane node (example path below); ensure it is readable by the controller-manager:
sudo ls -l /etc/kubernetes/pki/sa.key || sudo openssl genrsa -out /etc/kubernetes/pki/sa.key 2048sudo chmod 600 /etc/kubernetes/pki/sa.key -
Edit the controller manager manifest to add or update the
--service-account-private-key-fileflag to point to that key file:sudo sed -i \'s#^\(\s*-\s*--service-account-private-key-file=\).*#\1/etc/kubernetes/pki/sa.key#' \/etc/kubernetes/manifests/kube-controller-manager.yaml || \sudo sed -i \'/^\s*- kube-controller-manager$/a\ - --service-account-private-key-file=/etc/kubernetes/pki/sa.key' \/etc/kubernetes/manifests/kube-controller-manager.yaml -
If the key file path (
/etc/kubernetes/pki/sa.keyin this example) is not already mounted into the container, edit the manifest to add a hostPath volume and mount (this restart is automatic when you save the file):sudo sed -i '/volumes:/,/^ *[^- ]/s//volumes:\n - name: sa-key\n hostPath:\n path: \/etc\/kubernetes\/pki\/sa.key\n type: FileOrCreate\n&/' /etc/kubernetes/manifests/kube-controller-manager.yamlsudo sed -i '/volumeMounts:/,/^ *[^- ]/s//volumeMounts:\n - name: sa-key\n mountPath: \/etc\/kubernetes\/pki\/sa.key\n readOnly: true\n&/' /etc/kubernetes/manifests/kube-controller-manager.yaml(Adjust if your manifest structure differs; saving the file will cause the kube-controller-manager static pod to restart.)
-
Wait 30–60 seconds for the kubelet to restart the static pod, then verify on each control plane node that the controller manager process is using the correct flag and path:
/bin/ps -ef | grep kube-controller-manager | grep -v grep | \grep -- '--service-account-private-key-file=/etc/kubernetes/pki/sa.key'
Using kubectl
kubectl cannot modify the kube-controller-manager static pod manifest or its process flags. This setting must be changed directly on each control plane node by editing /etc/kubernetes/manifests/kube-controller-manager.yaml; see the Manual Steps section for detailed host-level instructions.
Automation
#!/usr/bin/env bash
#
# Automation: Configure --service-account-private-key-file for kube-controller-manager
#
# Run on: every control plane node (with root privileges)
#
# This script:
# - Ensures a service account private key exists at /etc/kubernetes/pki/sa.key
# - Adds/updates --service-account-private-key-file in
# /etc/kubernetes/manifests/kube-controller-manager.yaml
# - Relies on the kubelet to restart the static pod automatically
# - Verifies the flag is active in the running process
#
# Idempotent: safe to re-run.
set -euo pipefail
KCM_MANIFEST="/etc/kubernetes/manifests/kube-controller-manager.yaml"
SA_KEY="/etc/kubernetes/pki/sa.key"
SA_CERT="/etc/kubernetes/pki/sa.pub"
BACKUP_SUFFIX="$(date +%Y%m%d%H%M%S)"
if [[ $EUID -ne 0 ]]; then
echo "ERROR: Run this script as root." >&2
exit 1
fi
if [[ ! -f "$KCM_MANIFEST" ]]; then
echo "ERROR: Manifest $KCM_MANIFEST not found on this node." >&2
exit 1
fi
echo "==> Ensuring service account private key exists at $SA_KEY"
if [[ ! -f "$SA_KEY" ]]; then
mkdir -p "$(dirname "$SA_KEY")"
chmod 700 "$(dirname "$SA_KEY")"
echo " Generating new RSA private key for service accounts..."
openssl genrsa -out "$SA_KEY" 2048
chmod 600 "$SA_KEY"
chown root:root "$SA_KEY"
echo " Generating corresponding public key at $SA_CERT..."
openssl rsa -in "$SA_KEY" -pubout -out "$SA_CERT"
else
echo " Existing key found at $SA_KEY (leaving as-is)."
fi
echo "==> Updating $KCM_MANIFEST with --service-account-private-key-file flag"
cp "$KCM_MANIFEST" "${KCM_MANIFEST}.bak.${BACKUP_SUFFIX}"
if ! grep -q -- "--service-account-private-key-file=" "$KCM_MANIFEST"; then
echo " Flag not present; adding to manifest."
# Insert the flag into the args list of the kube-controller-manager container
# This sed adds the line right after the first occurrence of 'kube-controller-manager'
# in the args section, which is typical for kubeadm-style manifests.
sed -i '
/- kube-controller-manager/ {
:loop
n
/args:/!b loop
n
s/^/ - --service-account-private-key-file='"$SA_KEY"'\n/
}
' "$KCM_MANIFEST"
else
echo " Flag already present; normalizing its value to $SA_KEY."
# Replace any existing value with the desired path
sed -i "s#--service-account-private-key-file=\S*#--service-account-private-key-file=${SA_KEY}#g" "$KCM_MANIFEST"
fi
echo "==> Waiting for kube-controller-manager static pod to be restarted by kubelet..."
sleep 20
echo "==> Verification: checking running kube-controller-manager process"
if /bin/ps -ef | grep kube-controller-manager | grep -v grep | grep -q -- "--service-account-private-key-file=${SA_KEY}"; then
echo "SUCCESS: kube-controller-manager is running with --service-account-private-key-file=${SA_KEY}"
exit 0
else
echo "WARNING: kube-controller-manager process does not yet show the expected flag."
echo "Run the following manually to inspect the process:"
echo " /bin/ps -ef | grep kube-controller-manager | grep -v grep"
exit 1
fi