Skip to main content

5.2.4.4. CA upload

This section covers uploading root certificates to the Kubernetes cluster. The kubeadm-certs secret is created manually and contains the keys and certificates required when adding new control plane nodes (kubeadm join). This approach allows sensitive data to be securely transferred between control plane nodes.

Uploading root certificates to Kubernetes

● Required

Note

This section provides instructions for uploading root certificates to the Kubernetes control plane. The certificates are uploaded in encrypted form as a Secret resource, which allows them to be securely transferred and decrypted on another node for managing the control plane node lifecycle.

Environment variables for configuration file template

export AUTH_EXTRA_GROUPS="system:bootstrappers:kubeadm:default-node-token"

Role model preparation

This block prepares the role model for granting access to the kubeadm-certs secret. This is necessary so that control plane nodes can securely obtain root certificates through the Kubernetes API when joining the cluster. The role is bound to the ${AUTH_EXTRA_GROUPS} group, which kubeadm typically falls under during join.

kubectl \
--kubeconfig=/etc/kubernetes/super-admin.conf apply -f - <<EOF
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: kubeadm:kubeadm-certs
namespace: kube-system
rules:
- apiGroups:
- ""
resourceNames:
- kubeadm-certs
resources:
- secrets
verbs:
- get
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: kubeadm:kubeadm-certs
namespace: kube-system
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: kubeadm:kubeadm-certs
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: ${AUTH_EXTRA_GROUPS}
EOF

Working directory

mkdir -p /etc/kubernetes/openssl

Environment variables

export CERTIFICATE_UPLOAD_KEY=0c00c2fd5c67c37656c00d78a9d7e1f2eb794ef8e4fc3e2a4b532eb14323cd59
cat <<EOF > /etc/kubernetes/openssl/encrypt.py
#!/usr/bin/env python3
import sys, base64, os
from cryptography.hazmat.primitives.ciphers.aead import AESGCM

key = bytes.fromhex(sys.argv[1])
path = sys.argv[2]

with open(path, "rb") as f:
data = f.read()

nonce = os.urandom(12)
aesgcm = AESGCM(key)
ct = aesgcm.encrypt(nonce, data, None)

# kubeadm expects: nonce + ciphertext (including auth tag)
payload = nonce + ct
print(base64.b64encode(payload).decode())
EOF
cat <<'EOF' > /etc/kubernetes/openssl/upload-certs.sh
#!/bin/bash
set -euo pipefail

CERT_PATH="/etc/kubernetes/pki"
PY_SCRIPT="$(dirname "$0")/encrypt.py"

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"
)

KEY="${CERTIFICATE_UPLOAD_KEY:-}"
if [[ -z "$KEY" ]]; then
echo "[ERROR] CERTIFICATE_UPLOAD_KEY is not set"
exit 1
fi

echo "[INFO] Using certificate key: $KEY"

TMP_DIR=$(mktemp -d)
SECRET_FILE="$TMP_DIR/secret.yaml"

cat <<EOF_SECRET > "$SECRET_FILE"
apiVersion: v1
kind: Secret
metadata:
name: kubeadm-certs
namespace: kube-system
type: Opaque
data:
EOF_SECRET

for name in "${!files[@]}"; do
path="${files[$name]}"
if [[ ! -f "$path" ]]; then
echo "[WARN] Skipping missing file: $path"
continue
fi
echo "[INFO] Encrypting $name..."
b64=$(python3 "$PY_SCRIPT" "$KEY" "$path")
echo " $name: $b64" >> "$SECRET_FILE"
done

echo "[INFO] Applying secret to cluster..."
kubectl apply -f "$SECRET_FILE"

echo "[INFO] Secret successfully uploaded."
EOF

Setting permissions

chmod +x /etc/kubernetes/openssl/upload-certs.sh

Running the script

/etc/kubernetes/openssl/upload-certs.sh
Command output
[INFO] Using certificate key: 0c00c2fd5c67c37656c00d78a9d7e1f2eb794ef8e4fc3e2a4b532eb14323cd59
[INFO] Encrypting front-proxy-ca.key...
[INFO] Encrypting sa.key...
[INFO] Encrypting front-proxy-ca.crt...
[INFO] Encrypting etcd-ca.crt...
[INFO] Encrypting sa.pub...
[INFO] Encrypting ca.key...
[INFO] Encrypting ca.crt...
[INFO] Encrypting etcd-ca.key...
[INFO] Applying secret to cluster...
secret/kubeadm-certs configured
[INFO] Secret successfully uploaded.