Ensure DenyServiceExternalIPs Is Not Set
More Info:
This admission controller rejects all net-new usage of the Service field externalIPs
Risk Level
Low
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
-
On every control plane node, back up the existing manifest before editing:
sudo cp -a /etc/kubernetes/manifests/kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml.bak -
On every control plane node, open the API server static pod manifest for editing:
sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml -
In the
spec.containers[0].commandsection, locate the--enable-admission-pluginsflag. RemoveDenyServiceExternalIPsfrom the comma-separated list (leave the rest of the plugins unchanged), then save and exit.
Example before:- --enable-admission-plugins=NamespaceLifecycle,LimitRanger,DenyServiceExternalIPs,ServiceAccountExample after:
- --enable-admission-plugins=NamespaceLifecycle,LimitRanger,ServiceAccountNote: Saving this file will cause the kubelet to restart the
kube-apiserverstatic pod. -
If
DenyServiceExternalIPsis present as its own flag (older/custom configurations), remove that line entirely:# Remove a line such as:- --DenyServiceExternalIPs -
Wait for the kube-apiserver pod to be recreated and become Ready (run on any machine with kubectl access):
kubectl get pods -n kube-system -l component=kube-apiserver -o wide -
Verify on every control plane node that the
kube-apiserverprocess is now running withoutDenyServiceExternalIPs:/bin/ps -ef | grep kube-apiserver | grep -v grep | grep -i DenyServiceExternalIPs || echo "OK: DenyServiceExternalIPs not set"
Using kubectl
kubectl cannot change the DenyServiceExternalIPs admission plugin because it is configured via the kube-apiserver static pod manifest on each control plane node (/etc/kubernetes/manifests/kube-apiserver.yaml). To remediate this finding, make the change directly on the host as described in the Manual Steps section.
Automation
#!/usr/bin/env bash
#
# Automation: Remove DenyServiceExternalIPs admission plugin from kube-apiserver
# Scope: Run on every control plane node (with access to /etc/kubernetes/manifests)
# Usage: sudo ./fix_deny_service_external_ips.sh
set -euo pipefail
MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
BACKUP_DIR="/etc/kubernetes/manifests/backup-$(date +%Y%m%d-%H%M%S)"
echo "[INFO] Checking for kube-apiserver manifest at ${MANIFEST}"
if [[ ! -f "${MANIFEST}" ]]; then
echo "[ERROR] kube-apiserver manifest not found at ${MANIFEST}"
exit 1
fi
echo "[INFO] Creating backup directory ${BACKUP_DIR}"
mkdir -p "${BACKUP_DIR}"
cp -p "${MANIFEST}" "${BACKUP_DIR}/"
# Function to normalize and remove DenyServiceExternalIPs from a comma-separated list
remove_plugin_from_csv() {
local csv="$1"
local plugin="DenyServiceExternalIPs"
# Split, trim, and rebuild without the target plugin
awk -v csv="${csv}" -v plugin="${plugin}" '
BEGIN {
n = split(csv, arr, ",");
out = "";
for (i = 1; i <= n; i++) {
gsub(/^[[:space:]]+|[[:space:]]+$/, "", arr[i]);
if (arr[i] == "" || arr[i] == plugin) continue;
if (out != "") out = out "," arr[i];
else out = arr[i];
}
print out;
}'
}
TMP_MANIFEST="$(mktemp)"
cp "${MANIFEST}" "${TMP_MANIFEST}"
echo "[INFO] Processing admission plugin flags in ${MANIFEST}"
# Handle --enable-admission-plugins (legacy flag)
if grep -q -- "--enable-admission-plugins=" "${TMP_MANIFEST}"; then
echo "[INFO] Found --enable-admission-plugins flag; updating if necessary"
current_csv=$(sed -n 's/.*--enable-admission-plugins=\([^" ]*\).*/\1/p' "${TMP_MANIFEST}" | head -n1 || true)
if [[ -n "${current_csv}" ]]; then
new_csv=$(remove_plugin_from_csv "${current_csv}")
if [[ "${new_csv}" != "${current_csv}" ]]; then
sed -i "s#--enable-admission-plugins=${current_csv}#--enable-admission-plugins=${new_csv}#g" "${TMP_MANIFEST}"
echo "[INFO] Removed DenyServiceExternalIPs from --enable-admission-plugins"
else
echo "[INFO] DenyServiceExternalIPs not present in --enable-admission-plugins"
fi
fi
else
echo "[INFO] --enable-admission-plugins flag not present (nothing to change there)"
fi
# Handle --admission-control-config-file (if used), which may include DenyServiceExternalIPs by name
# NOTE: This script DOES NOT edit that file, only warns if present.
if grep -q -- "--admission-control-config-file=" "${TMP_MANIFEST}"; then
echo "[WARN] --admission-control-config-file is in use."
echo "[WARN] If DenyServiceExternalIPs is configured inside that file, review and remove it manually."
fi
# Detect any direct use of DenyServiceExternalIPs in args (defensive)
if grep -q "DenyServiceExternalIPs" "${TMP_MANIFEST}"; then
echo "[INFO] DenyServiceExternalIPs still referenced directly; ensuring it is not part of any simple CSV flags"
# Generic clean-up attempt for any argument like --something=...,DenyServiceExternalIPs,...
# This remains idempotent and only removes the named plugin where it is a list member.
perl -pi -e '
my $plugin = "DenyServiceExternalIPs";
s{
(--[a-zA-Z0-9\-]+=) # flag start
([^" \n]+) # CSV value
}{
my ($flag, $csv) = ($1, $2);
my @parts = split /,/, $csv;
@parts = grep { $_ ne $plugin } map { s/^\s+|\s+$//gr } @parts;
my $newcsv = join(",", @parts);
$flag . $newcsv;
}egx;
' "${TMP_MANIFEST}"
# Re-check if any literal remains (might be in complex YAML/config sections)
if grep -q "DenyServiceExternalIPs" "${TMP_MANIFEST}"; then
echo "[WARN] DenyServiceExternalIPs still present after automated CSV cleanup."
echo "[WARN] Inspect ${TMP_MANIFEST} manually and remove DenyServiceExternalIPs from enabled admission plugins."
else
echo "[INFO] All CSV references to DenyServiceExternalIPs removed."
fi
else
echo "[INFO] DenyServiceExternalIPs not referenced directly in manifest (nothing more to do)."
fi
echo "[INFO] Installing updated manifest"
cp "${TMP_MANIFEST}" "${MANIFEST}"
rm -f "${TMP_MANIFEST}"
echo "[INFO] kube-apiserver static pod manifest updated."
echo "[INFO] NOTE: The kube-apiserver static pod will be restarted automatically by kubelet."
echo "[INFO] Waiting for kube-apiserver process to reflect updated configuration..."
sleep 20
echo "[INFO] Verifying that DenyServiceExternalIPs is not set in kube-apiserver process"
if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -q "DenyServiceExternalIPs"; then
echo "[ERROR] Verification failed: DenyServiceExternalIPs still appears in kube-apiserver process arguments."
echo "[INFO] Current kube-apiserver command line:"
/bin/ps -ef | grep kube-apiserver | grep -v grep
exit 2
else
echo "[INFO] Verification succeeded: DenyServiceExternalIPs is not set in kube-apiserver process."
fi