Skip to main content

API Server Should Enable The EventRateLimit Admission Plugin

More Info:

Verifies that the EventRateLimit admission plugin is enabled to limit the rate of API requests and protect the API server from denial-of-service.

Risk Level

High

Address

Security

Compliance Standards

  • CIS Kubernetes

Triage and Remediation

Remediation

Manual Steps
  1. Create the EventRateLimit configuration file (every control plane node)

    sudo mkdir -p /etc/kubernetes/admission
    sudo tee /etc/kubernetes/admission/event-rate-limit.yaml >/dev/null << 'EOF'
    apiVersion: apiserver.k8s.io/v1alpha1
    kind: AdmissionConfiguration
    plugins:
    - name: EventRateLimit
    path: /etc/kubernetes/admission/event-rate-limit-config.yaml
    EOF

    sudo tee /etc/kubernetes/admission/event-rate-limit-config.yaml >/dev/null << 'EOF'
    apiVersion: eventratelimit.admission.k8s.io/v1alpha1
    kind: Configuration
    limits:
    - type: Namespace
    qps: 50
    burst: 100
    - type: User
    qps: 10
    burst: 20
    EOF
  2. Back up the existing API server static pod manifest (every control plane node)

    sudo cp -a /etc/kubernetes/manifests/kube-apiserver.yaml \
    /etc/kubernetes/manifests/kube-apiserver.yaml.backup.$(date +%F-%H%M%S)
  3. Edit the API server manifest to enable EventRateLimit (every control plane node)
    Open the file:

    sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml

    In the spec.containers[0].command list:

    • Ensure --enable-admission-plugins includes EventRateLimit (add it to the comma‑separated list, do not remove existing plugins), for example:
      - --enable-admission-plugins=NodeRestriction,EventRateLimit
    • Add or update the admission config flag to point to the file you created:
      - --admission-control-config-file=/etc/kubernetes/admission/event-rate-limit.yaml
  4. Ensure the admission config files are mounted into the API server pod (every control plane node)
    In the same manifest, under the container volumeMounts, add if not present:

    - mountPath: /etc/kubernetes/admission
    name: admission-config
    readOnly: true

    Under volumes, add if not present:

    - name: admission-config
    hostPath:
    path: /etc/kubernetes/admission
    type: DirectoryOrCreate
  5. Allow the API server to restart and stabilize (every control plane node)
    Saving /etc/kubernetes/manifests/kube-apiserver.yaml causes the kubelet to restart the kube-apiserver static pod automatically. Wait and confirm the pod is running:

    sudo crictl ps | grep kube-apiserver || sudo docker ps | grep kube-apiserver
  6. Verify EventRateLimit is enabled and configured (every control plane node)

    /bin/ps -ef | grep kube-apiserver | grep -v grep \
    | grep -- '--enable-admission-plugins' \
    | grep 'EventRateLimit' && \
    /bin/ps -ef | grep kube-apiserver | grep -v grep \
    | grep -- '--admission-control-config-file=/etc/kubernetes/admission/event-rate-limit.yaml'

    Optionally, confirm the flag values inside the container:

    kubectl -n kube-system get pod -l component=kube-apiserver -o wide
Using kubectl

kubectl cannot be used to enable the EventRateLimit admission plugin because this setting is defined in the API server’s static pod manifest on each control plane node at /etc/kubernetes/manifests/kube-apiserver.yaml. To remediate this finding, follow the guidance in the Manual Steps section and update the host-level configuration directly on the control plane nodes.

Automation
#!/usr/bin/env bash
#
# Automates enabling the EventRateLimit admission plugin on all control plane nodes.
# - Creates an EventRateLimit config file at /etc/kubernetes/admission-control-eventratelimit.yaml
# - Ensures kube-apiserver manifest has:
# --enable-admission-plugins=...,EventRateLimit,...
# --admission-control-config-file=/etc/kubernetes/admission-control-eventratelimit.yaml
# - Safe to re-run.
#
# RUN ON: each control plane node (with root privileges)

set -euo pipefail

APISERVER_MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
EVENT_RL_CFG="/etc/kubernetes/admission-control-eventratelimit.yaml"

backup_file() {
local f="$1"
if [ -f "$f" ] && [ ! -f "${f}.pre-eventratelimit.bak" ]; then
cp -p "$f" "${f}.pre-eventratelimit.bak"
fi
}

ensure_eventratelimit_config() {
mkdir -p "$(dirname "$EVENT_RL_CFG")"
backup_file "$EVENT_RL_CFG" || true

cat > "$EVENT_RL_CFG.tmp" <<'EOF'
apiVersion: apiserver.k8s.io/v1alpha1
kind: AdmissionConfiguration
plugins:
- name: EventRateLimit
path: /etc/kubernetes/eventconfig.yaml
---
apiVersion: eventratelimit.admission.k8s.io/v1alpha1
kind: Configuration
limits:
- type: Namespace
qps: 50
burst: 100
- type: User
qps: 20
burst: 50
EOF

# Optional: eventconfig referenced above
cat > /etc/kubernetes/eventconfig.yaml.tmp <<'EOF'
apiVersion: eventratelimit.admission.k8s.io/v1alpha1
kind: Configuration
limits:
- type: Namespace
qps: 50
burst: 100
- type: User
qps: 20
burst: 50
EOF

mv "$EVENT_RL_CFG.tmp" "$EVENT_RL_CFG"
chmod 600 "$EVENT_RL_CFG"

mv /etc/kubernetes/eventconfig.yaml.tmp /etc/kubernetes/eventconfig.yaml
chmod 600 /etc/kubernetes/eventconfig.yaml
}

patch_apiserver_manifest() {
if [ ! -f "$APISERVER_MANIFEST" ]; then
echo "ERROR: $APISERVER_MANIFEST not found; this script is for static pod control planes." >&2
exit 1
fi

backup_file "$APISERVER_MANIFEST"

# 1) Ensure --enable-admission-plugins has EventRateLimit
if grep -q -- '--enable-admission-plugins=' "$APISERVER_MANIFEST"; then
# If EventRateLimit is missing, add it
if ! grep -q -- '--enable-admission-plugins=.*EventRateLimit' "$APISERVER_MANIFEST"; then
sed -i -E \
's/(--enable-admission-plugins=)([^" ]*)/\1\2,EventRateLimit/' \
"$APISERVER_MANIFEST"
fi
else
# Add a new flag line under the kube-apiserver container args
# This assumes a standard kubeadm manifest with "- kube-apiserver" line.
if grep -q '^\s*- kube-apiserver' "$APISERVER_MANIFEST"; then
sed -i \
'/^\s*- kube-apiserver/a\ - --enable-admission-plugins=EventRateLimit' \
"$APISERVER_MANIFEST"
else
echo "WARNING: Could not find '- kube-apiserver' to attach --enable-admission-plugins; please edit $APISERVER_MANIFEST manually." >&2
fi
fi

# 2) Ensure --admission-control-config-file points to our config
if grep -q -- '--admission-control-config-file=' "$APISERVER_MANIFEST"; then
sed -i -E \
"s#--admission-control-config-file=[^\" ]*#--admission-control-config-file=${EVENT_RL_CFG}#g" \
"$APISERVER_MANIFEST"
else
if grep -q '^\s*- kube-apiserver' "$APISERVER_MANIFEST"; then
sed -i \
"/^\s*- kube-apiserver/a\ - --admission-control-config-file=${EVENT_RL_CFG}" \
"$APISERVER_MANIFEST"
else
echo "WARNING: Could not find '- kube-apiserver' to attach --admission-control-config-file; please edit $APISERVER_MANIFEST manually." >&2
fi
fi

echo "NOTE: Editing $APISERVER_MANIFEST will cause the kube-apiserver static pod to restart on this node."
}

verify() {
echo "Waiting 30s for kube-apiserver static pod restart..."
sleep 30

echo "Verifying kube-apiserver process flags..."
if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -q -- '--enable-admission-plugins=.*EventRateLimit'; then
echo "OK: EventRateLimit is present in --enable-admission-plugins."
else
echo "FAIL: EventRateLimit not found in --enable-admission-plugins." >&2
/bin/ps -ef | grep kube-apiserver | grep -v grep || true
exit 1
fi

if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -q -- "--admission-control-config-file=${EVENT_RL_CFG}"; then
echo "OK: --admission-control-config-file points to ${EVENT_RL_CFG}."
else
echo "FAIL: --admission-control-config-file not correctly set to ${EVENT_RL_CFG}." >&2
/bin/ps -ef | grep kube-apiserver | grep -v grep || true
exit 1
fi
}

main() {
ensure_eventratelimit_config
patch_apiserver_manifest
verify
}

main "$@"