Skip to main content

API Server Should Not Enable The AlwaysAdmit Admission

More Info:

Verifies that the AlwaysAdmit admission plugin is not enabled. AlwaysAdmit accepts every request and bypasses all other admission controls.

Risk Level

High

Address

Security

Compliance Standards

  • CIS Kubernetes

Triage and Remediation

Remediation

Manual Steps
  1. On every control plane node, open the API server static pod manifest in an editor:

    sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
  2. In the command: (or args:) list of the kube-apiserver container, locate any entry that starts with --enable-admission-plugins= and remove AlwaysAdmit from the comma-separated list. For example, change:

    - --enable-admission-plugins=NamespaceLifecycle,AlwaysAdmit,NodeRestriction

    to:

    - --enable-admission-plugins=NamespaceLifecycle,NodeRestriction

    If AlwaysAdmit is the only value, you may delete the whole --enable-admission-plugins=... line.

  3. Still in the same file, check for any explicit use of the deprecated --admission-control= flag and remove AlwaysAdmit from that list as well, or remove the flag line entirely if appropriate.

  4. Save the file and exit the editor. The kubelet will detect the manifest change and automatically restart the kube-apiserver static pod; expect a brief API server interruption.

  5. After the pod restarts, verify that AlwaysAdmit is no longer configured in the running process on that control plane node:

    /bin/ps -ef | grep kube-apiserver | grep -v grep | grep AlwaysAdmit || echo "AlwaysAdmit not found"
  6. Repeat steps 1–5 on every control plane node in the cluster.

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 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
#
# Disable the AlwaysAdmit admission plugin in kube-apiserver static pod manifest.
# Target: every control plane node
# Safe to re-run; backs up the manifest once per change and only edits when needed.

set -euo pipefail

MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
BACKUP_DIR="/etc/kubernetes/manifests/backup-$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"

if [[ ! -f "$MANIFEST" ]]; then
echo "ERROR: $MANIFEST not found. Run this script on a control plane node."
exit 1
fi

# Function: check if AlwaysAdmit is currently enabled in the manifest
has_always_admit() {
grep -E -- '--enable-admission-plugins=.*AlwaysAdmit' "$MANIFEST" >/dev/null 2>&1
}

# Function: check if AlwaysAdmit is explicitly disabled
has_always_admit_in_disable() {
grep -E -- '--disable-admission-plugins=.*AlwaysAdmit' "$MANIFEST" >/dev/null 2>&1
}

echo "Inspecting $MANIFEST for AlwaysAdmit..."

if ! has_always_admit; then
echo "AlwaysAdmit is not enabled in --enable-admission-plugins. No change needed."
else
echo "AlwaysAdmit found in --enable-admission-plugins. Patching manifest..."

cp -n "$MANIFEST" "$BACKUP_DIR/kube-apiserver.yaml.$(date +%H%M%S)"

TMP="$(mktemp)"
cp "$MANIFEST" "$TMP"

# 1. Remove AlwaysAdmit from any existing --enable-admission-plugins list
# Handles both comma-separated and single-value cases.
python3 - "$TMP" <<'PYCODE'
import re, sys, shutil, tempfile

path = sys.argv[1]
with open(path, 'r', encoding='utf-8') as f:
data = f.read()

pattern = re.compile(r'(--enable-admission-plugins=)(\S+)')
def repl(m):
prefix, val = m.groups()
plugins = val.split(',')
plugins = [p for p in plugins if p != 'AlwaysAdmit']
if not plugins:
# remove the flag entirely by returning just a comment marker
return '# ' + prefix + val
return prefix + ','.join(plugins)

new_data = pattern.sub(repl, data)

fd, tmp_out = tempfile.mkstemp()
with open(tmp_out, 'w', encoding='utf-8') as f:
f.write(new_data)
shutil.move(tmp_out, path)
PYCODE

# 2. Optionally ensure AlwaysAdmit is explicitly disabled (defensive),
# but only if it's not already present in --disable-admission-plugins.
if ! has_always_admit_in_disable; then
echo "Adding AlwaysAdmit to --disable-admission-plugins for defense-in-depth..."

# If --disable-admission-plugins exists, append; else, add a new arg line.
if grep -q -- '--disable-admission-plugins=' "$TMP"; then
python3 - "$TMP" <<'PYCODE'
import re, sys, shutil, tempfile
path = sys.argv[1]
with open(path, 'r', encoding='utf-8') as f:
data = f.read()

pattern = re.compile(r'(--disable-admission-plugins=)(\S+)')
def repl(m):
prefix, val = m.groups()
plugins = val.split(',')
if 'AlwaysAdmit' not in plugins:
plugins.append('AlwaysAdmit')
return prefix + ','.join(plugins)

new_data = pattern.sub(repl, data)
fd, tmp_out = tempfile.mkstemp()
with open(tmp_out, 'w', encoding='utf-8') as f:
f.write(new_data)
shutil.move(tmp_out, path)
PYCODE
else
# Insert a new argument line under the kube-apiserver container args
python3 - "$TMP" <<'PYCODE'
import sys, shutil, tempfile

path = sys.argv[1]
with open(path, 'r', encoding='utf-8') as f:
lines = f.readlines()

out = []
inserted = False
for i, line in enumerate(lines):
out.append(line)
if not inserted and line.lstrip().startswith('args:'):
indent = ' ' * (len(line) - len(line.lstrip()))
out.append(f"{indent}- --disable-admission-plugins=AlwaysAdmit\n")
inserted = True

if not inserted:
# Fallback: just append at end
out.append(" - --disable-admission-plugins=AlwaysAdmit\n")

fd, tmp_out = tempfile.mkstemp()
with open(tmp_out, 'w', encoding='utf-8') as f:
f.writelines(out)
shutil.move(tmp_out, path)
PYCODE
fi
fi

# Move patched temp file back into place
mv "$TMP" "$MANIFEST"
echo "Patched $MANIFEST. kube-apiserver static pod will be restarted by kubelet."
fi

echo
echo "Verification (this may take up to a minute while kube-apiserver restarts)..."

# Wait until kube-apiserver process is present and does not reference AlwaysAdmit in enable flag
for i in {1..30}; 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 -E -- '--enable-admission-plugins=.*AlwaysAdmit' >/dev/null 2>&1; then
echo "PASS: kube-apiserver is running and AlwaysAdmit is not enabled."
exit 0
fi
fi
sleep 2
done

echo "WARNING: kube-apiserver process still shows AlwaysAdmit in --enable-admission-plugins."
echo "Inspect current flags with:"
echo "/bin/ps -ef | grep kube-apiserver | grep -v grep"
exit 1