API Server Should Disable Profiling
More Info:
Verifies that the API server --profiling argument is set to false. Profiling exposes detailed system and program data that could aid an attacker.
Risk Level
Medium
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
On every control plane node, open the API server static pod manifest for editing:
sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml -
In the
command:orargs:list forkube-apiserver, locate any existing--profilingflag and change it to:- --profiling=falseIf no
--profilingflag is present, add this line under the other arguments, for example:spec:containers:- name: kube-apiservercommand:- kube-apiserver- --profiling=false... -
Save and exit the editor. The kubelet will automatically detect the manifest change and restart the
kube-apiserverstatic pod; expect a brief API server disruption during this restart. -
After 30–60 seconds, verify on the same control plane node that the
kube-apiserverprocess is now running with--profiling=false:ps -ef | grep kube-apiserver | grep -v grep -
In the command output, confirm that
--profiling=falseappears and that there is no--profiling=trueflag. Repeat steps 1–4 on every control plane node.
Using kubectl
kubectl cannot modify the kube-apiserver static pod manifest or its process flags, so this finding cannot be fixed through the Kubernetes API. The change must be made directly on every control plane node in /etc/kubernetes/manifests/kube-apiserver.yaml; see the Manual Steps section for the exact procedure.
Automation
#!/usr/bin/env bash
#
# Remediate CISKubernetes 1.2.15:
# Ensure that the kube-apiserver --profiling argument is set to false.
#
# Run this script on every control plane node as root.
# It is safe to re-run; it will only adjust the --profiling flag as needed.
#
# Operational impact:
# - Editing /etc/kubernetes/manifests/kube-apiserver.yaml will trigger
# the kube-apiserver static 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)"
if [[ $EUID -ne 0 ]]; then
echo "ERROR: This script must be run as root on each control plane node." >&2
exit 1
fi
if [[ ! -f "$APISERVER_MANIFEST" ]]; then
echo "ERROR: kube-apiserver manifest not found at ${APISERVER_MANIFEST}." >&2
exit 1
fi
echo "Creating backup of ${APISERVER_MANIFEST} in ${BACKUP_DIR}..."
mkdir -p "$BACKUP_DIR"
cp -p "$APISERVER_MANIFEST" "${BACKUP_DIR}/kube-apiserver.yaml"
echo "Ensuring --profiling=false is configured..."
# Normalize existing --profiling flags:
# 1) Convert any explicit --profiling=true to --profiling=false
# 2) Remove any duplicate occurrences after the first corrected one
TMP_FILE="$(mktemp)"
trap 'rm -f "${TMP_FILE}"' EXIT
# Step 1: Replace any explicit --profiling=true with --profiling=false
# and keep existing --profiling=false as-is.
# We do not add the flag yet; that happens in Step 2.
sed -E \
-e 's/(--profiling)=[Tt][Rr][Uu][Ee]/\1=false/g' \
"$APISERVER_MANIFEST" > "${TMP_FILE}.step1"
# Step 2: Ensure exactly one --profiling=false exists in the container args list.
# Approach:
# - Remove all existing --profiling=... entries
# - Add a single "--profiling=false" as the last item in the args: list
# (or create args: section with it if missing)
awk '
BEGIN {
in_container = 0
in_args = 0
}
# Detect containers: section and container start
/containers:/ { print; next }
/- name: kube-apiserver/ {
in_container = 1
print
next
}
in_container == 1 && /- name:/ && $0 !~ /kube-apiserver/ {
# another container; end of kube-apiserver container
if (in_args == 1) {
# If we were in args, ensure we have added profiling flag
if (profiling_added == 0) {
print " - \"--profiling=false\""
}
in_args = 0
}
in_container = 0
profiling_added = 0
print
next
}
in_container == 1 && /args:/ {
in_args = 1
profiling_added = 0
print
next
}
in_container == 1 && in_args == 1 {
# Within args of kube-apiserver
if ($0 ~ /--profiling=/) {
# Skip all existing profiling flags
next
}
# Detect end of args list (next non-indented key or end of container)
if ($1 !~ /^-/ && $1 !~ /^ *-/ && $1 !~ /^ *\"--/ && $1 !~ /^ *\'--/ && $1 !~ /^ *- /) {
# We reached a new section; add profiling flag before this line
if (profiling_added == 0) {
print " - \"--profiling=false\""
profiling_added = 1
}
in_args = 0
print
next
}
# Normal args line; just print
print
next
}
{
print
}
END {
# No special END handling; if args: existed it was handled above
}
' "${TMP_FILE}.step1" > "${TMP_FILE}.step2"
# Step 3: If kube-apiserver container has no args: section at all,
# add one with --profiling=false
awk '
BEGIN {
in_container = 0
has_args = 0
}
/- name: kube-apiserver/ {
in_container = 1
has_args = 0
print
next
}
in_container == 1 && /args:/ {
has_args = 1
print
next
}
in_container == 1 && /- name:/ && $0 !~ /kube-apiserver/ {
# another container; end of kube-apiserver container
if (has_args == 0) {
print " args:"
print " - \"--profiling=false\""
}
in_container = 0
has_args = 0
print
next
}
{
print
}
END {
# If file ended while still in kube-apiserver container with no args
if (in_container == 1 && has_args == 0) {
print " args:"
print " - \"--profiling=false\""
}
}
' "${TMP_FILE}.step2" > "${TMP_FILE}"
# Move final result into place
cp "${TMP_FILE}" "$APISERVER_MANIFEST"
echo "Updated ${APISERVER_MANIFEST} with --profiling=false."
echo "kubelet will restart the kube-apiserver static pod automatically."
# Wait for kube-apiserver process to restart and reflect new flags
echo "Waiting for kube-apiserver to be running with --profiling=false..."
RETRY=30
SLEEP_SECONDS=5
SUCCESS=0
for i in $(seq 1 "$RETRY"); do
if /bin/ps -ef | grep kube-apiserver | grep -v grep >/dev/null 2>&1; then
if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -- "--profiling=false" >/dev/null 2>&1; then
# Ensure no process still has --profiling=true
if ! /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -- "--profiling=true" >/dev/null 2>&1; then
SUCCESS=1
break
fi
fi
fi
sleep "$SLEEP_SECONDS"
done
echo
echo "Verification output (ps -ef | grep kube-apiserver | grep -v grep):"
# Final verification command as per audit guidance
/bin/ps -ef | grep kube-apiserver | grep -v grep || true
if [[ "$SUCCESS" -eq 1 ]]; then
echo
echo "Result: kube-apiserver is running with --profiling=false and no --profiling=true flags detected."
exit 0
else
echo
echo "WARNING: kube-apiserver process does not yet show --profiling=false as expected."
echo "Inspect the manifest and kubelet status on this control plane node."
exit 1
fi