API Server Should Disable Service Account Extend Token
More Info:
Verifies that --service-account-extend-token-expiration is set to false so bound service account tokens are not automatically extended to long lifetimes, reducing token exposure.
Risk Level
High
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
On every control plane node, back up the existing manifest before editing:
sudo cp -a /etc/kubernetes/manifests/kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml.bak -
On every control plane node, open the kube-apiserver static pod manifest for editing:
sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml -
In the container
command:section, either add or modify the flag so it is present exactly as:- --service-account-extend-token-expiration=falseEnsure there is no other
--service-account-extend-token-expirationflag with a different value in the file, then save and exit.
Note: editing this file will cause the kube-apiserver static pod to be restarted automatically by the kubelet. -
Wait 30–60 seconds for the kube-apiserver pod to restart, then confirm the apiserver container is running (on any control plane node):
sudo crictl ps | grep kube-apiserver(If
crictlis not available, usesudo docker ps | grep kube-apiserveron nodes using Docker.) -
On every control plane node, verify the running process includes the correct flag value:
/bin/ps -ef | grep kube-apiserver | grep -v grep | grep -- '--service-account-extend-token-expiration=false'Ensure this command returns at least one line and that there is no line showing
--service-account-extend-token-expiration=true.
Using kubectl
kubectl cannot modify the kube-apiserver static pod manifest or its process flags, so this setting cannot be fixed via the Kubernetes API. To remediate, you must edit /etc/kubernetes/manifests/kube-apiserver.yaml directly on every control plane node; follow the Manual Steps section for the exact host-level changes.
Automation
#!/usr/bin/env bash
#
# Remediate CIS Kubernetes 1.2.30:
# Ensure --service-account-extend-token-expiration is set to false
# Target: every control plane node
#
# Usage: run as root on each control plane node.
# sudo bash ./fix-service-account-extend-token-expiration.sh
set -euo pipefail
APISERVER_MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
BACKUP_DIR="/etc/kubernetes/manifests/backup-cis-1.2.30"
PARAM_NAME="service-account-extend-token-expiration"
DESIRED_VALUE="false"
echo "[INFO] Starting remediation for CIS 1.2.30 on this control plane node"
if [[ $EUID -ne 0 ]]; then
echo "[ERROR] This script must be run as root." >&2
exit 1
fi
if [[ ! -f "${APISERVER_MANIFEST}" ]]; then
echo "[ERROR] kube-apiserver manifest not found at ${APISERVER_MANIFEST}" >&2
exit 1
fi
mkdir -p "${BACKUP_DIR}"
TS="$(date +%Y%m%d-%H%M%S)"
BACKUP_FILE="${BACKUP_DIR}/kube-apiserver.yaml.${TS}"
cp "${APISERVER_MANIFEST}" "${BACKUP_FILE}"
echo "[INFO] Backed up ${APISERVER_MANIFEST} to ${BACKUP_FILE}"
# Function to ensure the desired flag is present and set to false
ensure_flag() {
local file="$1"
local param="$2"
local value="$3"
# If line with parameter exists, replace it to ensure correct value
if grep -q -- "--${param}=" "${file}"; then
# If already correctly set, do nothing
if grep -q -- "--${param}=${value}" "${file}"; then
echo "[INFO] --${param} already set to ${value}; no change needed"
return 0
fi
echo "[INFO] Updating existing --${param} flag to ${value}"
# Replace the value while preserving YAML formatting
# This substitution changes only the flag value, not indentation or other content
sed -i "s#--${param}=[^\"']*#--${param}=${value}#g" "${file}"
else
echo "[INFO] Adding --${param}=${value} flag under kube-apiserver command section"
# Insert the flag after the kube-apiserver command line in the manifest.
# We look for the line containing 'kube-apiserver' in the container command list.
# This is a heuristic but is safe and idempotent: we only add if missing.
awk -v p="--${param}=${value}" '
# Once we see kube-apiserver line inside the command list, we remember and
# insert the flag on the following line (with same indentation plus two spaces).
/kube-apiserver/ && in_cmd == 0 {
print $0
# capture indentation of this line
indent = match($0, /[^ ]/)-1
pad = sprintf("%*s", indent+2, "")
print pad "- " p
in_cmd = 1
next
}
{ print $0 }
' "${file}" > "${file}.tmp"
mv "${file}.tmp" "${file"
}
}
ensure_flag "${APISERVER_MANIFEST}" "${PARAM_NAME}" "${DESIRED_VALUE}"
echo "[INFO] Changes applied to ${APISERVER_MANIFEST}."
echo "[INFO] Because this is a static pod manifest, the kube-apiserver pod will be restarted automatically by the kubelet."
# Wait for kube-apiserver process to reflect updated flag
echo "[INFO] Waiting for kube-apiserver to restart with new flags..."
SLEEP_SECS=5
MAX_WAIT_SECS=180
elapsed=0
while true; do
if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -q -- "--${PARAM_NAME}=${DESIRED_VALUE}"; then
echo "[INFO] Verification successful: kube-apiserver is running with --${PARAM_NAME}=${DESIRED_VALUE}"
break
fi
if (( elapsed >= MAX_WAIT_SECS )); then
echo "[ERROR] Timed out waiting for kube-apiserver to start with --${PARAM_NAME}=${DESIRED_VALUE}" >&2
echo "[INFO] Current kube-apiserver process flags:" >&2
/bin/ps -ef | grep kube-apiserver | grep -v grep || true
exit 1
fi
sleep "${SLEEP_SECS}"
elapsed=$((elapsed + SLEEP_SECS))
done
echo "[INFO] CIS 1.2.30 remediation completed on this control plane node."