Ensure Secure Port Argument Is Not Set 0
More Info:
Do not disable the secure port.
Risk Level
Critical
Address
Security
Compliance Standards
- CIS Kubernetes
Triage and Remediation
- Remediation
Remediation
Manual Steps
- On every control plane node, back up the current manifest before editing:
sudo cp /etc/kubernetes/manifests/kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml.bak
- On every control plane node, edit the API server manifest to remove or change the
--secure-portflag. For example, to set it to 6443:
sudo sed -i 's/--secure-port=0/--secure-port=6443/' /etc/kubernetes/manifests/kube-apiserver.yaml
If the flag appears in another form, open the file and edit manually:
sudo vi /etc/kubernetes/manifests/kube-apiserver.yaml
and either delete the --secure-port=0 line or change 0 to your desired non‑zero port.
-
Wait for the kubelet on each control plane node to automatically restart the
kube-apiserverstatic pod due to the manifest change (typically within ~1 minute). Be aware this restarts the API server and may briefly impact API availability. -
On any machine with SSH access to each control plane node, verify the new
kube-apiserverprocess is running with a non‑zero secure port:
ssh <control-plane-node> "/bin/ps -ef | grep kube-apiserver | grep -v grep"
Confirm there is no --secure-port=0 argument in the output; if --secure-port appears, it must be set to a non‑zero port (for example --secure-port=6443).
Using kubectl
kubectl cannot modify the kube-apiserver static pod manifest or its process flags. This finding must be fixed directly on every control plane node by editing /etc/kubernetes/manifests/kube-apiserver.yaml; see the Manual Steps section for the exact procedure.
Automation
#!/usr/bin/env bash
#
# Fix CISKubernetes 1.2.17: Ensure --secure-port is not set to 0 for kube-apiserver
#
# Run on: every control plane node (as root)
#
# Behavior:
# - Backs up /etc/kubernetes/manifests/kube-apiserver.yaml once
# - Ensures --secure-port is either absent or set to a non-zero port (default: 6443)
# - Idempotent: safe to re-run
# - Verifies by inspecting running kube-apiserver process
set -euo pipefail
API_SERVER_MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"
BACKUP_SUFFIX=".pre_cis_1_2_17_backup"
DESIRED_SECURE_PORT="6443" # change this if you use a non-default secure port
echo "[INFO] Starting remediation for kube-apiserver --secure-port on control plane node: $(hostname)"
if [[ $EUID -ne 0 ]]; then
echo "[ERROR] This script must be run as root."
exit 1
fi
if [[ ! -f "${API_SERVER_MANIFEST}" ]]; then
echo "[ERROR] Manifest ${API_SERVER_MANIFEST} not found. Nothing to do on this node."
exit 1
fi
# Backup manifest once
if [[ ! -f "${API_SERVER_MANIFEST}${BACKUP_SUFFIX}" ]]; then
echo "[INFO] Creating backup: ${API_SERVER_MANIFEST}${BACKUP_SUFFIX}"
cp -p "${API_SERVER_MANIFEST}" "${API_SERVER_MANIFEST}${BACKUP_SUFFIX}"
else
echo "[INFO] Backup already exists: ${API_SERVER_MANIFEST}${BACKUP_SUFFIX}"
fi
# Determine current --secure-port settings in manifest
CURRENT_SECURE_PORT_LINES=$(grep -E -- '--secure-port(=|[[:space:]]+)' "${API_SERVER_MANIFEST}" || true)
if [[ -z "${CURRENT_SECURE_PORT_LINES}" ]]; then
echo "[INFO] No --secure-port found in manifest; nothing to change in file."
else
echo "[INFO] Existing --secure-port entries in manifest:"
echo "${CURRENT_SECURE_PORT_LINES}"
fi
TMP_FILE="$(mktemp)"
trap 'rm -f "${TMP_FILE}"' EXIT
# Normalize --secure-port:
# - Remove any occurrences with value 0
# - Ensure at most one occurrence with DESIRED_SECURE_PORT
#
# Handles both:
# - --secure-port=0 / --secure-port=6443
# - ["--secure-port","0"] (rare but seen in some generator tools)
cp "${API_SERVER_MANIFEST}" "${TMP_FILE}"
# Remove any --secure-port explicitly set to 0 (various formatting styles)
sed -i -E \
-e 's/--secure-port=0[[:space:]]*//g' \
-e 's/--secure-port[[:space:]]+0[[:space:]]*//g' \
-e 's/"--secure-port","0"[[:space:]]*//g' \
-e 's/"--secure-port", "0"[[:space:]]*//g' \
"${TMP_FILE}"
# If there is still a non-zero --secure-port defined, leave it as is (admin-chosen port)
if grep -qE -- '--secure-port(=|[[:space:]]+)[1-9][0-9]*' "${TMP_FILE}"; then
echo "[INFO] Non-zero --secure-port already configured in manifest; not overriding."
else
# No non-zero secure-port found; we ensure one is present with DESIRED_SECURE_PORT
echo "[INFO] No non-zero --secure-port found; ensuring --secure-port=${DESIRED_SECURE_PORT} is set."
# Try to append to an existing --secure-port line if one exists (without value),
# else add a new argument entry under kube-apiserver container args.
if grep -q -- '--secure-port' "${TMP_FILE}"; then
# There is a bare --secure-port; normalize to desired value
sed -i -E \
-e "s/--secure-port([[:space:]]+|=)[^[:space:]\"]*/--secure-port=${DESIRED_SECURE_PORT}/g" \
"${TMP_FILE}"
else
# Need to inject a new arg; attempt to place it alongside other args.
# We look for a line under spec.containers[*].command or .args that has other flags.
if grep -q 'kube-apiserver' "${TMP_FILE}" && grep -q '\-\-advertise-address' "${TMP_FILE}"; then
# Common case: flags listed one-per-line; add a new line after --advertise-address
sed -i -E \
'/--advertise-address/ a\ - --secure-port='"${DESIRED_SECURE_PORT}" \
"${TMP_FILE}" || true
else
# Fallback: append at end of args list if we can find one
if grep -q 'args:' "${TMP_FILE}"; then
# Add as a new element to args
sed -i -E \
'/args:/,/image:/ {
/args:/!{
/-/!{
s/(args:[[:space:]]*)/\1\n - --secure-port='"${DESIRED_SECURE_PORT}"'/
}
}
}' "${TMP_FILE}" || true
fi
fi
# If still not present, append at end of file as a last resort (admin may refine manually)
if ! grep -qE -- '--secure-port(=|[[:space:]]+)'"${DESIRED_SECURE_PORT}" "${TMP_FILE}"; then
echo "[WARN] Could not safely inject --secure-port into existing args; appending at end of manifest."
{
echo " # Added by CIS 1.2.17 remediation script"
echo " - --secure-port=${DESIRED_SECURE_PORT}"
} >> "${TMP_FILE}"
fi
fi
fi
# If no change, avoid unnecessary restart
if cmp -s "${API_SERVER_MANIFEST}" "${TMP_FILE}"; then
echo "[INFO] Manifest already compliant; no changes applied."
else
echo "[INFO] Updating ${API_SERVER_MANIFEST} (this will restart kube-apiserver static pod)."
cp "${TMP_FILE}" "${API_SERVER_MANIFEST}"
fi
# Allow static pod controller time to restart kube-apiserver if needed
echo "[INFO] Waiting up to 60 seconds for kube-apiserver to restart (if changed)..."
sleep 60 || true
# Verification: ensure kube-apiserver process is not using --secure-port=0
echo "[INFO] Verifying running kube-apiserver process arguments..."
PS_OUT="$(/bin/ps -ef | grep kube-apiserver | grep -v grep || true)"
if [[ -z "${PS_OUT}" ]]; then
echo "[ERROR] kube-apiserver process not found after change. Check kubelet and pod logs."
exit 2
fi
echo "${PS_OUT}"
if echo "${PS_OUT}" | grep -q -- '--secure-port=0'; then
echo "[ERROR] kube-apiserver is still running with --secure-port=0."
exit 3
fi
if echo "${PS_OUT}" | grep -q -- '--secure-port'; then
CURRENT_RUNNING_PORT="$(echo "${PS_OUT}" | sed -nE 's/.*--secure-port=([0-9]+).*/\1/p' | head -n1 || true)"
if [[ -n "${CURRENT_RUNNING_PORT}" ]]; then
echo "[INFO] kube-apiserver is running with secure port: ${CURRENT_RUNNING_PORT}"
else
echo "[INFO] kube-apiserver uses --secure-port (non-zero) but port parsing failed; review args above."
fi
else
echo "[INFO] kube-apiserver is running with default secure port (argument not set explicitly)."
fi
echo "[INFO] Remediation for CISKubernetes 1.2.17 completed on node: $(hostname)"