5.2.2.1. Root certificates
Certificate Authority (CA) is a trusted source that issues root certificates used to sign all other certificates within the Kubernetes cluster.
CA certificates play a key role in establishing trust between components, ensuring authentication, encryption, and integrity of communications.
This section describes the process of obtaining root certificates that are used to sign the remaining certificates in the Kubernetes cluster.
- Init
- Join
Creating root certificates
● Required
Creating root certificates
● Required
- Kubernetes CA
- FrontProxy CA
- ETCD CA
Kubernetes CA
Purpose: Kubernetes root Certificate Authority (CA). Signs the server and client certificates for kube-apiserver, kubelet, kube-controller-manager, and kube-scheduler. All cluster components trust this CA for TLS connection verification.
Note: this block describes only the process of creating Kubernetes CA root certificates.
- HardWay
- Kubeadm
Working directory
mkdir -p /etc/kubernetes/openssl
mkdir -p /etc/kubernetes/pki
Configuration
cat <<EOF > /etc/kubernetes/openssl/ca.conf
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
prompt = no
[req_distinguished_name]
CN = kubernetes
[v3_ca]
keyUsage = critical, keyCertSign, keyEncipherment, digitalSignature
basicConstraints = critical,CA:TRUE
EOF
Private key generation
openssl genrsa \
-out /etc/kubernetes/pki/ca.key 2048
Public key generation
openssl req \
-x509 \
-new \
-nodes \
-key /etc/kubernetes/pki/ca.key \
-sha256 \
-days 3650 \
-out /etc/kubernetes/pki/ca.crt \
-config /etc/kubernetes/openssl/ca.conf
Certificate readiness verification
This section depends on the following sections:
/etc/kubernetes/openssl/cert-report.sh /etc/kubernetes/pki/ca.crt
CERTIFICATE AUTHORITY EXPIRES RESIDUAL TIME EXTERNALLY MANAGED
ca Oct 20, 2034 22:04 UTC 9y no
Certificate generation
kubeadm init phase certs ca \
--config=/var/run/kubeadm/kubeadm.yaml
After executing the commands, we get the following output.
#### Create Kubernetes CA
[certs] Generating "ca" certificate and key
FrontProxy CA
Purpose: CA for the API aggregation mechanism (extension API servers). Signs the
front-proxy-clientcertificate, which kube-apiserver uses when proxying requests to extended API servers (e.g., metrics-server, custom API servers).
Note: this block describes only the process of creating Front Proxy CA root certificates.
- HardWay
- Kubeadm
Working directory
mkdir -p /etc/kubernetes/openssl
mkdir -p /etc/kubernetes/pki
Configuration
cat <<EOF > /etc/kubernetes/openssl/front-proxy-ca.conf
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
prompt = no
[req_distinguished_name]
CN = front-proxy-ca
[v3_ca]
keyUsage = critical, keyCertSign, keyEncipherment, digitalSignature
basicConstraints = critical,CA:TRUE
EOF
Private key generation
openssl genrsa \
-out /etc/kubernetes/pki/front-proxy-ca.key 2048
Public key generation
openssl req \
-x509 \
-new \
-nodes \
-key /etc/kubernetes/pki/front-proxy-ca.key \
-sha256 \
-days 3650 \
-out /etc/kubernetes/pki/front-proxy-ca.crt \
-config /etc/kubernetes/openssl/front-proxy-ca.conf
Certificate readiness verification
This section depends on the following sections:
/etc/kubernetes/openssl/cert-report.sh /etc/kubernetes/pki/front-proxy-ca.crt
CERTIFICATE AUTHORITY EXPIRES RESIDUAL TIME EXTERNALLY MANAGED
front-proxy-ca Oct 20, 2034 22:04 UTC 9y no
Certificate generation
kubeadm init phase certs front-proxy-ca \
--config=/var/run/kubeadm/kubeadm.yaml
After executing the commands, we get the following output.
#### Create Front Proxy CA
[certs] Generating "front-proxy-ca" certificate and key
ETCD CA
Purpose: CA for all etcd cluster certificates. Signs server, client, and peer certificates for etcd:
etcd-server(client connections, port 2379),etcd-peer(inter-node replication, port 2380), andetcd-healthcheck-client(health checks). Also used by kube-apiserver to verify the connection to etcd via theapiserver-etcd-clientcertificate.
Note: this section only describes the process of creating ETCD CA root certificates.
- HardWay
- Kubeadm
Working directory
mkdir -p /etc/kubernetes/openssl
mkdir -p /etc/kubernetes/pki/etcd
Configuration
cat <<EOF > /etc/kubernetes/openssl/etcd-ca.conf
[req]
distinguished_name = req_distinguished_name
x509_extensions = v3_ca
prompt = no
[req_distinguished_name]
CN = "etcd-ca"
[v3_ca]
keyUsage = critical, keyCertSign, keyEncipherment, digitalSignature
basicConstraints = critical,CA:TRUE
EOF
Private key generation
openssl genrsa \
-out /etc/kubernetes/pki/etcd/ca.key 2048
Public key generation
openssl req \
-x509 \
-new \
-nodes \
-key /etc/kubernetes/pki/etcd/ca.key \
-sha256 \
-days 3650 \
-out /etc/kubernetes/pki/etcd/ca.crt \
-config /etc/kubernetes/openssl/etcd-ca.conf
Certificate readiness check
This section depends on the following sections:
/etc/kubernetes/openssl/cert-report.sh /etc/kubernetes/pki/etcd/ca.crt
CERTIFICATE AUTHORITY EXPIRES RESIDUAL TIME EXTERNALLY MANAGED
etcd-ca Oct 20, 2034 22:04 UTC 9y no
Certificate generation
kubeadm init phase certs etcd-ca \
--config=/var/run/kubeadm/kubeadm.yaml
After running the command, we get the following output.
#### Create ETCD CA
[certs] Generating "etcd/ca" certificate and key
Downloading existing CAs
● Required
Downloading existing CAs
● Required
- HardWay
- Kubeadm
This section provides instructions for downloading root certificates from the Kubernetes control plane. The certificates are downloaded in encrypted form from the Secret resource, which allows them to be securely transferred and decrypted on the node for managing the control plane node lifecycle.
Working directory
mkdir -p /etc/kubernetes/openssl
mkdir -p /etc/kubernetes/pki
mkdir -p /etc/kubernetes/pki/etcd
Environment variables
In production environments, it is recommended to create a separate bootstrap token for each node. However, for demonstration purposes (and within this documentation), we have simplified the process and use a single shared token for all control plane nodes.
export CERTIFICATE_UPLOAD_KEY=0c00c2fd5c67c37656c00d78a9d7e1f2eb794ef8e4fc3e2a4b532eb14323cd59
export KUBE_API_BOOTSTRAP_TOKEN=fjt9ex.lwzqgdlvoxtqk4yw
export KUBE_API_SERVER=https://api.my-first-cluster.example.com:6443
cat <<EOF > /etc/kubernetes/openssl/decrypt.py
#!/usr/bin/env python3
import sys, base64
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
key = bytes.fromhex(sys.argv[1])
payload = base64.b64decode(sys.argv[2])
nonce, ct = payload[:12], payload[12:]
aesgcm = AESGCM(key)
plain = aesgcm.decrypt(nonce, ct, None)
sys.stdout.buffer.write(plain)
EOF
cat <<'EOF' > /etc/kubernetes/openssl/download-certs.sh
#!/bin/bash
set -euo pipefail
CERT_PATH="/etc/kubernetes/pki"
KEY="${CERTIFICATE_UPLOAD_KEY:-}"
PY_SCRIPT="$(dirname "$0")/decrypt.py"
KUBE_API_SERVER="${KUBE_API_SERVER:-https://127.0.0.1:6443}"
TOKEN="${KUBE_API_BOOTSTRAP_TOKEN:?KUBE_API_BOOTSTRAP_TOKEN is required}"
declare -A files=(
["ca.crt"]="$CERT_PATH/ca.crt"
["ca.key"]="$CERT_PATH/ca.key"
["etcd-ca.crt"]="$CERT_PATH/etcd/ca.crt"
["etcd-ca.key"]="$CERT_PATH/etcd/ca.key"
["front-proxy-ca.crt"]="$CERT_PATH/front-proxy-ca.crt"
["front-proxy-ca.key"]="$CERT_PATH/front-proxy-ca.key"
["sa.key"]="$CERT_PATH/sa.key"
["sa.pub"]="$CERT_PATH/sa.pub"
)
mkdir -p "$CERT_PATH"
echo "[INFO] Using certificate key: $KEY"
echo "[WARN] TLS verification is DISABLED (insecure mode)"
echo "[INFO] Fetching Secret kubeadm-certs from API..."
RESPONSE=$(curl -sSL -k \
-H "Authorization: Bearer $TOKEN" \
"$KUBE_API_SERVER/api/v1/namespaces/kube-system/secrets/kubeadm-certs")
echo "$RESPONSE" | jq -r '.data | to_entries[] | @base64' | while read -r item; do
name=$(echo "$item" | base64 -d | jq -r '.key')
b64=$(echo "$item" | base64 -d | jq -r '.value' | tr -d '\n')
out_path="${files[$name]:-}"
if [[ -z "$out_path" ]]; then
echo "[WARN] Unknown certificate: $name — skipping"
continue
fi
mkdir -p "$(dirname "$out_path")"
echo "[INFO] Decrypting $name → $out_path"
python3 "$PY_SCRIPT" "$KEY" "$b64" > "$out_path"
done
echo "[INFO] Certificates unpacked."
EOF
Setting permissions
chmod +x /etc/kubernetes/openssl/download-certs.sh
Running the script
/etc/kubernetes/openssl/download-certs.sh
[INFO] Using certificate key: 0c00c2fd5c67c37656c00d78a9d7e1f2eb794ef8e4fc3e2a4b532eb14323cd59
[WARN] TLS verification is DISABLED (insecure mode)
[INFO] Fetching Secret kubeadm-certs from API...
[INFO] Decrypting ca.crt → /etc/kubernetes/pki/ca.crt
[INFO] Decrypting ca.key → /etc/kubernetes/pki/ca.key
[INFO] Decrypting etcd-ca.crt → /etc/kubernetes/pki/etcd/ca.crt
[INFO] Decrypting etcd-ca.key → /etc/kubernetes/pki/etcd/ca.key
[INFO] Decrypting front-proxy-ca.crt → /etc/kubernetes/pki/front-proxy-ca.crt
[INFO] Decrypting front-proxy-ca.key → /etc/kubernetes/pki/front-proxy-ca.key
[INFO] Decrypting sa.key → /etc/kubernetes/pki/sa.key
[INFO] Decrypting sa.pub → /etc/kubernetes/pki/sa.pub
[INFO] Certificates unpacked.
This section depends on the following sections:
Manifest generation
kubeadm join phase control-plane-prepare download-certs \
--config=/var/run/kubeadm/kubeadm.yaml
[preflight] Reading configuration from the cluster...
[preflight] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[download-certs] Downloading the certificates in Secret "kubeadm-certs" in the "kube-system" Namespace
[download-certs] Saving the certificates to the folder: "/etc/kubernetes/pki"