Skip to main content

Ensure Admission Control Plugin AlwaysAdmit Is Not Set

More Info:​

Do not allow all requests.

Risk Level​

Low

Address​

Security

Compliance Standards​

  • CIS Kubernetes

Triage and Remediation​

Remediation​

Manual Steps
  1. On every control plane node, open the kube-apiserver static pod manifest in an editor:

    sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
  2. In the spec.containers[0].command list, locate any line containing --enable-admission-plugins=.

    • If the value contains AlwaysAdmit, remove only AlwaysAdmit from the comma‑separated list (and any now-superfluous comma).
    • If AlwaysAdmit is the only value, remove the entire --enable-admission-plugins=AlwaysAdmit argument line.
  3. Still in the same manifest, if there is a separate --admission-control= argument and it contains AlwaysAdmit, remove only AlwaysAdmit from that comma‑separated list, or remove the whole argument if it only contains AlwaysAdmit.

  4. Save the file and exit the editor. The kubelet will automatically detect the manifest change and restart the kube-apiserver static pod; expect a brief control-plane disruption while it restarts.

  5. Wait for the new kube-apiserver process to be running:

    sudo crictl ps | grep kube-apiserver

    (If crictl is not available, use sudo docker ps | grep kube-apiserver depending on your container runtime.)

  6. Verify that AlwaysAdmit is no longer configured in the API server arguments on each control plane node:

    /bin/ps -ef | grep kube-apiserver | grep -v grep | grep AlwaysAdmit || echo "AlwaysAdmit not present"
Using kubectl

kubectl cannot modify the kube-apiserver static pod manifest or its process flags, so this finding cannot be fixed via the Kubernetes API. The configuration must be changed directly on each control plane node at /etc/kubernetes/manifests/kube-apiserver.yaml; see the Manual Steps section for how to do this.

Automation
#!/usr/bin/env bash
#
# Automation: Remove AlwaysAdmit admission plugin from kube-apiserver
#
# Run on: every control plane node (as root)
# Safe to re-run: yes (idempotent)

set -euo pipefail

APISERVER_MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
BACKUP_DIR="/etc/kubernetes/manifests/backup-$(date +%Y%m%d-%H%M%S)"

echo "==> Checking for kube-apiserver manifest at ${APISERVER_MANIFEST}"
if [[ ! -f "${APISERVER_MANIFEST}" ]]; then
echo "ERROR: ${APISERVER_MANIFEST} not found on this node. Is this a control plane node?"
exit 1
fi

echo "==> Creating backup in ${BACKUP_DIR}"
mkdir -p "${BACKUP_DIR}"
cp -p "${APISERVER_MANIFEST}" "${BACKUP_DIR}/"

# Function: remove AlwaysAdmit from an --enable-admission-plugins flag value
sanitize_plugins_line() {
local line="$1"
# Extract the value after '='
local prefix value newvalue
prefix="${line%%--enable-admission-plugins=*}"
value="${line#*--enable-admission-plugins=}"

# If there are spaces after the value, keep only up to first space
value="${value%% *}"

# Convert comma-separated list to array, remove AlwaysAdmit, and rejoin
IFS=',' read -r -a plugins <<< "${value}"
newplugins=()
for p in "${plugins[@]}"; do
[[ "${p}" == "AlwaysAdmit" ]] && continue
[[ -z "${p}" ]] && continue
newplugins+=("${p}")
done

if [[ ${#newplugins[@]} -eq 0 ]]; then
# No plugins left; remove the flag entirely by returning the prefix only
printf '%s\n' "${prefix}"
else
local joined="${newplugins[*]}"
joined="${joined// /,}"
printf '%s--enable-admission-plugins=%s\n' "${prefix}" "${joined}"
fi
}

TMP_FILE="$(mktemp)"
trap 'rm -f "${TMP_FILE}"' EXIT

echo "==> Updating kube-apiserver manifest to ensure AlwaysAdmit is not configured"
changed=false
while IFS= read -r line; do
if [[ "${line}" == *"--enable-admission-plugins="* ]]; then
if [[ "${line}" == *"AlwaysAdmit"* ]]; then
new_line="$(sanitize_plugins_line "${line}")"
# Preserve original indentation by prefixing spaces from original line
indent="${line%%${line##+([[:space:]])}}"
# shellcheck disable=SC2254
new_line="${indent}${new_line#"${new_line%%[![:space:]]*}"}"
echo "${new_line}" >> "${TMP_FILE}"
changed=true
else
echo "${line}" >> "${TMP_FILE}"
fi
else
echo "${line}" >> "${TMP_FILE}"
fi
done < "${APISERVER_MANIFEST}"

if [[ "${changed}" == true ]]; then
echo "==> Applying changes to ${APISERVER_MANIFEST}"
cp "${TMP_FILE}" "${APISERVER_MANIFEST}"
else
echo "==> No occurrences of AlwaysAdmit in --enable-admission-plugins found; no change needed"
fi

# kubelet will automatically restart the kube-apiserver static pod
echo "==> Waiting for kube-apiserver process to reload..."
sleep 30

echo "==> Verification: ensuring kube-apiserver is not started with AlwaysAdmit"
if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -q "AlwaysAdmit"; then
echo "VERIFICATION FAILED: kube-apiserver process still has AlwaysAdmit configured:"
/bin/ps -ef | grep kube-apiserver | grep -v grep
exit 1
fi

echo "VERIFICATION PASSED: kube-apiserver process does not include AlwaysAdmit in its arguments."

Additional Reading:​