Skip to main content

Controller Manager Should Disable Profiling

More Info:

Verifies that the controller manager --profiling argument is set to false so detailed profiling data is not exposed to potential attackers.

Risk Level

Medium

Address

Security

Compliance Standards

  • CIS Kubernetes

Triage and Remediation

Remediation

Manual Steps
  1. On every control plane node, open the kube-controller-manager static pod manifest for editing:

    sudo vi /etc/kubernetes/manifests/kube-controller-manager.yaml
  2. In the spec.containers[0].command (or args) list, add or update the profiling flag so it is explicitly disabled:

    - --profiling=false

    Ensure there is no other --profiling= entry with a different value.

  3. Save the file and exit the editor. The kube-controller-manager static pod will be automatically restarted by the kubelet because the manifest under /etc/kubernetes/manifests changed. Be aware this briefly restarts the controller manager on this control plane node.

  4. Repeat steps 1–3 on every control plane node that has a /etc/kubernetes/manifests/kube-controller-manager.yaml file.

  5. After the controller manager has restarted on a node, verify that profiling is disabled by inspecting the running process on that node:

    ps -ef | grep kube-controller-manager | grep -v grep

    Confirm the output includes --profiling=false and does not include --profiling=true or a bare --profiling flag.

Using kubectl

kubectl cannot change the --profiling flag for the controller manager because it is configured via the static pod manifest on each control plane node at /etc/kubernetes/manifests/kube-controller-manager.yaml. To remediate this finding, follow the guidance in the Manual Steps section on each control plane node.

Automation
#!/usr/bin/env bash
#
# Automation: Disable profiling in kube-controller-manager static pod manifest
#
# Target: every control plane node
# Preconditions: run as root on each control plane node

set -euo pipefail

MANIFEST="/etc/kubernetes/manifests/kube-controller-manager.yaml"
ARG_NAME="--profiling"
DESIRED="${ARG_NAME}=false"

echo ">>> Ensuring ${DESIRED} in ${MANIFEST}"

if [[ ! -f "${MANIFEST}" ]]; then
echo "ERROR: Manifest not found at ${MANIFEST}. This script is only for static pod deployments."
exit 1
fi

# Backup once (idempotent)
BACKUP="${MANIFEST}.pre-profiling-fix.bak"
if [[ ! -f "${BACKUP}" ]]; then
cp -p "${MANIFEST}" "${BACKUP}"
echo "Created backup ${BACKUP}"
fi

# Function to test if manifest already has desired arg
has_desired_arg() {
grep -E '^\s*-\s*'"${DESIRED}"'\s*$' "${MANIFEST}" >/dev/null 2>&1
}

# Function to test if any --profiling arg exists
has_any_profiling_arg() {
grep -E '^\s*-\s*'"${ARG_NAME}="' "${MANIFEST}" >/dev/null 2>&1
}

# Ensure a --profiling=false argument exists, replacing any existing --profiling=...
if has_desired_arg; then
echo ">>> ${DESIRED} already present in ${MANIFEST}"
else
if has_any_profiling_arg; then
echo ">>> Updating existing ${ARG_NAME} argument to false"
# Replace any existing --profiling=<value> with --profiling=false on the arg lines
# This keeps indentation and surrounding structure intact.
sed -i -E 's|^(\s*-\s*'"${ARG_NAME}"'=).*|\1false|' "${MANIFEST}"
else
echo ">>> Adding ${DESIRED} to kube-controller-manager container args"

# Insert the argument under the kube-controller-manager container args list.
# This uses a conservative awk approach that:
# - Detects the kube-controller-manager container block
# - Inserts the arg under its args: list if present
# - If no args: list exists, creates one.
tmpfile="$(mktemp)"

awk -v arg="${DESIRED}" '
$0 ~ "name:[[:space:]]*kube-controller-manager" { in_kcm=1 }
in_kcm && $0 ~ "name:" && $0 !~ "kube-controller-manager" { in_kcm=0 }
in_kcm && $0 ~ "args:[[:space:]]*$" {
in_args=1
print
getline nextline
# Insert arg as first item under args if not already there
if (nextline ~ /^[ \t]*-[ \t]/) {
print " - " arg
}
print nextline
while ((getline l) > 0) {
if (l ~ /^[^ \t-]/ || l ~ /^[ \t]*[A-Za-z0-9_-]+:/) {
print l
in_args=0
break
}
print l
}
next
}
in_kcm && !in_args && $0 ~ "image:" && !seen_args_block {
# No args: block seen yet; create one before image line
print " args:"
print " - " arg
seen_args_block=1
}
{ print }
' "${MANIFEST}" > "${tmpfile}"

mv "${tmpfile}" "${MANIFEST}"
fi
fi

echo ">>> Waiting for kube-controller-manager static pod restart (triggered by manifest change)..."
sleep 10

echo ">>> Verification: checking running kube-controller-manager process flags"
/bin/ps -ef | grep kube-controller-manager | grep -v grep || {
echo "WARNING: kube-controller-manager process not found. Static pod may still be starting."
}

if /bin/ps -ef | grep kube-controller-manager | grep -v grep | grep -q -- "${DESIRED}"; then
echo "SUCCESS: kube-controller-manager is running with ${DESIRED}"
else
echo "WARNING: ${DESIRED} not detected in running kube-controller-manager process."
echo "Current process line(s):"
/bin/ps -ef | grep kube-controller-manager | grep -v grep || true
exit 1
fi