Skip to main content

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​

Manual Steps
  1. 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
  2. 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 2048
    sudo chmod 600 /etc/kubernetes/pki/sa.key
  3. Edit the controller manager manifest to add or update the --service-account-private-key-file flag 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
  4. If the key file path (/etc/kubernetes/pki/sa.key in 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.yaml

    sudo 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.)

  5. 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

Additional Reading:​