Ensure Admission Control Plugin ServiceAccount Is Set
More Info:
Automate service accounts management.
Risk Level
Medium
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
On every control plane node, review existing ServiceAccounts to understand what is already in use (run on any machine with kubectl access):
kubectl get serviceaccounts --all-namespaces -o wideIf needed, create or adjust ServiceAccounts for your workloads according to your environment’s requirements:
kubectl create serviceaccount <name> -n <namespace> -
On every control plane node, back up the existing kube-apiserver static pod manifest:
sudo cp -a /etc/kubernetes/manifests/kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml.backup -
On every control plane node, open the kube-apiserver manifest for editing:
sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml -
In the
spec.containers[0].commandsection, locate the--disable-admission-pluginsargument.- If it includes
ServiceAccount, removeServiceAccountfrom the comma-separated list, leaving the other plugins unchanged. - If
--disable-admission-pluginsis not present, no change is needed for this argument.
Save and exit the editor.
Note: Editing this file will cause the kubelet to restart the kube-apiserver static pod.
- If it includes
-
Wait for the kube-apiserver pod to restart and become Ready (run on any machine with kubectl access):
kubectl get pods -n kube-system -l component=kube-apiserver -o wide -
Verify on every control plane node that the kube-apiserver process is now running without
ServiceAccountin--disable-admission-plugins:/bin/ps -ef | grep kube-apiserver | grep -v grepInspect the output and confirm that either
--disable-admission-pluginsis absent or, if present, its value does not containServiceAccount.
Using kubectl
kubectl cannot modify the kube-apiserver static pod manifest or its process flags on the control plane node. To remediate this finding, you must edit /etc/kubernetes/manifests/kube-apiserver.yaml directly on every control plane node; see the Manual Steps section for detailed guidance.
Automation
#!/usr/bin/env bash
#
# Automation: Ensure ServiceAccount admission plugin is NOT disabled
# Scope: Run on every control plane node
# Effect: Edits /etc/kubernetes/manifests/kube-apiserver.yaml
# Note: Changing this static pod manifest will restart the kube-apiserver.
set -euo pipefail
KUBE_APISERVER_MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
BACKUP_SUFFIX="$(date +%Y%m%d%H%M%S)"
if [ ! -f "$KUBE_APISERVER_MANIFEST" ]; then
echo "ERROR: $KUBE_APISERVER_MANIFEST not found on this node. Are you on a control plane node?"
exit 1
fi
if ! command -v python3 >/dev/null 2>&1; then
echo "ERROR: python3 is required for safe YAML manipulation."
exit 1
fi
echo "Creating backup: ${KUBE_APISERVER_MANIFEST}.${BACKUP_SUFFIX}"
cp -p "$KUBE_APISERVER_MANIFEST" "${KUBE_APISERVER_MANIFEST}.${BACKUP_SUFFIX}"
python3 << 'PYEOF'
import sys, re, copy
from pathlib import Path
path = Path("/etc/kubernetes/manifests/kube-apiserver.yaml")
text = path.read_text()
# Very small YAML editor tailored for kube-apiserver command args line.
# Goal: ensure --disable-admission-plugins does NOT contain ServiceAccount.
lines = text.splitlines()
changed = False
def process_arg_list(arg_str: str) -> str:
"""
Given a comma-separated list (e.g. 'NamespaceLifecycle,ServiceAccount,NodeRestriction'),
remove 'ServiceAccount' token if present and deduplicate commas.
"""
parts = [p.strip() for p in arg_str.split(",") if p.strip()]
parts = [p for p in parts if p != "ServiceAccount"]
return ",".join(parts)
new_lines = []
for line in lines:
if "--disable-admission-plugins" in line:
orig_line = line
# Match patterns like:
# - --disable-admission-plugins=Something,ServiceAccount,Other
# - --disable-admission-plugins=ServiceAccount
# --disable-admission-plugins=ServiceAccount,Other
def repl(m):
pre = m.group(1)
val = m.group(2)
new_val = process_arg_list(val)
return f"{pre}{new_val}"
new_line = re.sub(
r"(--disable-admission-plugins=)([^ \"']+)",
repl,
line
)
if new_line != orig_line:
changed = True
line = new_line
new_lines.append(line)
if changed:
new_text = "\n".join(new_lines) + ("\n" if text.endswith("\n") else "")
path.write_text(new_text)
PYEOF
echo "Configuration updated. kube-apiserver static pod will be reloaded automatically."
# Verification: ensure kube-apiserver is running and ServiceAccount is NOT in --disable-admission-plugins
echo "Waiting briefly for kube-apiserver to stabilize..."
sleep 10
echo "Current kube-apiserver process flags:"
/bin/ps -ef | grep kube-apiserver | grep -v grep || {
echo "ERROR: kube-apiserver process not found. Check pod status."
exit 1
}
if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -q -- "--disable-admission-plugins"; then
if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -q -- "--disable-admission-plugins=.*ServiceAccount"; then
echo "FAIL: ServiceAccount still present in --disable-admission-plugins."
exit 1
fi
fi
echo "PASS: ServiceAccount admission plugin is not disabled on this control plane node."