Skip to main content

Ensure API Server Only Uses Strong Cryptographic Ciphers

More Info:

Ensure that the API server is configured to only use strong cryptographic ciphers.

Risk Level

Medium

Address

Security

Compliance Standards

  • CIS Kubernetes

Triage and Remediation

Remediation

Manual Steps
  1. On every control plane node, back up the API server manifest before editing:

    sudo cp -a /etc/kubernetes/manifests/kube-apiserver.yaml /etc/kubernetes/manifests/kube-apiserver.yaml.bak
  2. Edit the manifest on every control plane node:

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

    Locate the command: or - kube-apiserver args list and either add or replace the existing --tls-cipher-suites argument with a single, comma-separated value line like this (each item exactly as shown, no spaces):

    - --tls-cipher-suites=TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
  3. 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.

  4. Wait for the kube-apiserver pod to become Ready again (on any machine with kubectl access):

    kubectl get pods -n kube-system -l component=kube-apiserver -o wide
  5. On every control plane node, verify the running process has the correct cipher suites configured:

    /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -- '--tls-cipher-suites=TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256'
Using kubectl

kubectl cannot modify the kube-apiserver static pod manifest or its process flags, so this finding cannot be remediated through the Kubernetes API. To fix it, you must edit /etc/kubernetes/manifests/kube-apiserver.yaml directly on every control plane node as described in the Manual Steps section.

Automation
#!/usr/bin/env bash
#
# Harden kube-apiserver TLS cipher suites on all control plane nodes.
#
# USAGE:
# 1) Put this script on each control plane node.
# 2) Run as root: ./harden-apiserver-ciphers.sh
#
# This edits /etc/kubernetes/manifests/kube-apiserver.yaml.
# Changing this file will cause the kube-apiserver static pod to restart.

set -euo pipefail

APISERVER_MANIFEST="/etc/kubernetes/manifests/kube-apiserver.yaml"

REQUIRED_CIPHERS="TLS_AES_128_GCM_SHA256,TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256"

backup_manifest() {
local src="$1"
local ts
ts="$(date +%Y%m%d-%H%M%S)"
cp -p "$src" "${src}.bak-${ts}"
echo "Backup created: ${src}.bak-${ts}"
}

ensure_manifest_exists() {
if [ ! -f "$APISERVER_MANIFEST" ]; then
echo "ERROR: $APISERVER_MANIFEST not found on this node. Run this only on control plane nodes."
exit 1
fi
}

configure_tls_cipher_suites() {
local file="$APISERVER_MANIFEST"

# If flag already present with the required value, do nothing (idempotent).
if grep -q -- "--tls-cipher-suites=${REQUIRED_CIPHERS}" "$file"; then
echo "Flag --tls-cipher-suites already set to required value; no changes needed."
return 0
fi

backup_manifest "$file"

if grep -q -- "--tls-cipher-suites=" "$file"; then
# Replace any existing tls-cipher-suites line with the required value.
sed -i 's#^\(\s*-\s*--tls-cipher-suites=\).*#\1'"${REQUIRED_CIPHERS}"'#' "$file"
echo "Updated existing --tls-cipher-suites flag."
else
# Insert the flag under the kube-apiserver command list.
# This assumes a typical kubeadm-style manifest with a 'command:' list.
# Append as a new '- --tls-cipher-suites=...' line after the last existing flag line.
# Safer approach: add near other --tls-* options if present.
if grep -q "command:" "$file"; then
# Add the flag after the 'command:' block start.
awk -v ciphers="$REQUIRED_CIPHERS" '
/command:/ && in_cmd==0 {
print $0
in_cmd=1
next
}
in_cmd==1 && $1 ~ /^-/ {
print $0
last_flag_line=NR
next
}
in_cmd==1 && $1 !~ /^-/ {
if (inserted==0) {
print " - --tls-cipher-suites=" ciphers
inserted=1
}
in_cmd=0
print $0
next
}
{
print $0
}
END {
if (in_cmd==1 && inserted==0) {
print " - --tls-cipher-suites=" ciphers
}
}
' "$file" > "${file}.tmp"
mv "${file}.tmp" "$file"
echo "Inserted new --tls-cipher-suites flag under command section."
else
echo "ERROR: Could not locate 'command:' section in $file to insert --tls-cipher-suites flag."
echo "Please edit the manifest manually to add:"
echo " - --tls-cipher-suites=${REQUIRED_CIPHERS}"
exit 1
fi
fi

echo "NOTE: kubelet will automatically restart the kube-apiserver static pod due to manifest change."
}

verify_apiserver_process() {
echo "Waiting for kube-apiserver to restart with new flags (up to 120 seconds)..."

# Wait loop for process containing the desired flag.
for i in $(seq 1 24); do
if /bin/ps -ef | grep kube-apiserver | grep -v grep | grep -q -- "--tls-cipher-suites=${REQUIRED_CIPHERS}"; then
echo "Verification succeeded: kube-apiserver is running with the required --tls-cipher-suites flag."
/bin/ps -ef | grep kube-apiserver | grep -v grep
return 0
fi
sleep 5
done

echo "WARNING: kube-apiserver process not yet showing the required --tls-cipher-suites flag."
echo "Current kube-apiserver processes:"
/bin/ps -ef | grep kube-apiserver | grep -v grep || true
exit 1
}

main() {
ensure_manifest_exists
configure_tls_cipher_suites
verify_apiserver_process
}

main "$@"

Additional Reading: