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
Remediation
Manual Steps
-
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 -
Edit the manifest on every control plane node:
sudo vi /etc/kubernetes/manifests/kube-apiserver.yamlLocate the
command:or- kube-apiserverargs list and either add or replace the existing--tls-cipher-suitesargument 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 -
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.
-
Wait for the kube-apiserver pod to become Ready again (on any machine with
kubectlaccess):kubectl get pods -n kube-system -l component=kube-apiserver -o wide -
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 "$@"