Description of the content of the k8s certificate generated by Kubeadm
- Description of the content of the k8s certificate generated by Kubeadm:
-
- certificate grouping
- Kubernetes cluster root certificate
-
- The certificates issued by this root certificate are:
- kube-apiserver proxy root certificate (client certificate)
- etcd cluster root certificate
-
-
- The server certificate held by etcd server
- The client certificate used by the nodes in the peer cluster to communicate with each other
- Define the client certificate used by the Liveness probe in the pod
- Configure the client certificate used in kube-apiserver for mutual authentication with etcd server
-
- Extend k8s certificate time
-
- To extend the certificate expiration time:
Description of the content of the k8s certificate generated by Kubeadm:
Certificate grouping
Kubernetes puts the certificate in two folders
/etc/kubernetes/pki /etc/kubernetes/pki/etcd
Kubernetes cluster root certificate
Kubernetes cluster root certificate CA (certificate issuing authority for Kubernetes cluster components)
/etc/kubernetes/pki/ca.crt /etc/kubernetes/pki/ca.key
The above group of certificates is the root certificate used to issue other Kubernetes component certificates, which can be considered as one of the certificate issuing organizations in the Kubernetes cluster
The certificates issued by this root certificate are:
kube-apiserver apiserver certificate
/etc/kubernetes/pki/apiserver.crt /etc/kubernetes/pki/apiserver.key
Kubelet client certificate, used as client authentication when kube-apiserver actively initiates a request to kubelet
/etc/kubernetes/pki/apiserver-kubelet-client.crt /etc/kubernetes/pki/apiserver-kubelet-client.key
kube-apiserver proxy root certificate (client certificate)
Used in the requestheader-client-ca-file configuration option, kube-apiserver uses this certificate to verify whether the client certificate is issued by itself
/etc/kubernetes/pki/front-proxy-ca.crt /etc/kubernetes/pki/front-proxy-ca.key
There is only one set of certificates issued by this root certificate:
The proxy layer (such as the aggregation layer aggregator) uses this set of proxy certificates to request authentication from the kube-apiserver
The client certificate used by the agent, used to authenticate users on behalf of the kube-apiserver
/etc/kubernetes/pki/front-proxy-client.crt /etc/kubernetes/pki/front-proxy-client.key
etcd cluster root certificate
The certificates used by the etcd cluster are stored in the path /etc/kubernetes/pki/etcd. Obviously, this set of certificates is used exclusively for etcd cluster services. Design the following certificate files
etcd cluster root certificate CA (issuer of all certificates used by etcd)
/etc/kubernetes/pki/etcd/ca.crt /etc/kubernetes/pki/etcd/ca.key
The certificates issued by this root certificate issuing authority are:
- The server certificate held by etcd server
- The client certificate used by the nodes in the peer cluster to communicate with each other
- Define the client certificate used by the Liveness probe in the pod
- Configure the client certificate used in kube-apiserver for mutual authentication with etcd server
Server certificate held by etcd server
/etc/kubernetes/pki/etcd/server.crt /etc/kubernetes/pki/etcd/server.key
The client certificate used by the nodes in the peer cluster to communicate with each other
/etc/kubernetes/pki/etcd/peer.crt /etc/kubernetes/pki/etcd/peer.key
Note: Peer: the name of another Member in the same etcd cluster
Define the client certificate used by the Liveness probe in the pod
The Kubernetes cluster deployed by kubeadm runs the etcd service as a pod. In the definition of the pod, the Liveness detection probe is configured.
/etc/kubernetes/pki/etcd/healthcheck-client.crt /etc/kubernetes/pki/etcd/healthcheck-client.key
When you describe the pod of etcd, you will see the following line of configuration:
Liveness: exec [/bin/sh -ec ETCDCTL_API=3 etcdctl --endpoints=https://[127.0.0.1]:2379 --cacert=/etc/kubernetes/pki/etcd/ca.crt -- cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt --key=/etc/kubernetes/pki/etcd/healthcheck-client.key get foo] delay=15s timeout=15s period=10s #success=1 #failure=8
Configure the client certificate used in kube-apiserver for two-way authentication with etcd server
/etc/kubernetes/pki/apiserver-etcd-client.crt /etc/kubernetes/pki/apiserver-etcd-client.key
Extend k8s certificate time
Any server executes
Check the validity period of the certificate:
openssl x509 -in /etc/kubernetes/pki/ca.crt -noout -text |grep Not
The display is as follows. From the following, you can see that the ca certificate is valid for 10 years, from 2023 to 2033:
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text |grep Not
The display is as follows, through which you can see that the apiserver certificate is valid for 1 year
Extend certificate expiration time:
Upload the update-kubeadm-cert.sh file to the k8smaster1 and k8smaster2 nodes, and execute the following on k8smaster1 and k8smaster2:
#!/bin/bash #Script reproduced from https://github.com/yuyicai/update-kube-cert set -o errexit set -o pipefail # set -o xtrace log::err() {<!-- --> printf "[$(date + '%Y-%m-%dT%H:%M:%S.%N%z')]: \033[31mERROR: \033[0m$@\ " } log::info() {<!-- --> printf "[$(date + '%Y-%m-%dT%H:%M:%S.%N%z')]: \033[32mINFO: \033[0m$@\ " } log::warning() {<!-- --> printf "[$(date + '%Y-%m-%dT%H:%M:%S.%N%z')]: \033[33mWARNING: \033[0m$@\ " } check_file() {<!-- --> if [[ ! -r ${<!-- -->1} ]]; then log::err "can not find ${1}" exit 1 the fi } # get x509v3 subject alternative name from the old certificate cert::get_subject_alt_name() {<!-- --> local cert=${<!-- -->1}.crt check_file "${cert}" local alt_name=$(openssl x509 -text -noout -in ${<!-- -->cert} | grep -A1 'Alternative' | tail -n1 | sed 's/[[:space:]]*Address/ /g') printf "${alt_name}\ " } # get subject from the old certificate cert::get_subj() {<!-- --> local cert=${<!-- -->1}.crt check_file "${cert}" local subj=$(openssl x509 -text -noout -in ${<!-- -->cert} | grep "Subject:" | sed 's/Subject:/\//g;s/\,/\/ /;s/[[:space:]]//g') printf "${subj}\ " } cert::backup_file() {<!-- --> local file=${<!-- -->1} if [[ ! -e ${<!-- -->file}.old-$(date + %Y%m%d) ]]; then cp -rp ${<!-- -->file} ${<!-- -->file}.old-$(date + %Y%m%d) log::info "backup ${file} to ${file}.old-$(date + %Y%m%d)" else log::warning "does not backup, ${file}.old-$(date + %Y%m%d) already exists" the fi } # generate certificate whit client, server or peer # Args: # $1 (the name of certificate) # $2 (the type of certificate, must be one of client, server, peer) # $3 (the subject of certificates) # $4 (the validity of certificates) (days) # $5 (the x509v3 subject alternative name of certificate when the type of certificate is server or peer) cert::gen_cert() {<!-- --> local cert_name=${<!-- -->1} local cert_type=${<!-- -->2} local subj=${<!-- -->3} local cert_days=${<!-- -->4} local alt_name=${<!-- -->5} local cert=${<!-- -->cert_name}.crt local key=${<!-- -->cert_name}.key local csr=${<!-- -->cert_name}.csr local csr_conf="distinguished_name = dn\ [dn]\ [v3_ext]\ keyUsage = critical, digitalSignature, keyEncipherment\ " check_file "${key}" check_file "${cert}" # backup certificate when certificate not in ${kubeconf_arr[@]} # kubeconf_arr=("controller-manager.crt" "scheduler.crt" "admin.crt" "kubelet.crt") # if [[ ! "${kubeconf_arr[@]}" =~ "${cert##*/}" ]]; then # cert::backup_file "${cert}" #fi case "${cert_type}" in client) openssl req -new -key ${<!-- -->key} -subj "${subj}" -reqexts v3_ext \ -config <(printf "${csr_conf} extendedKeyUsage = clientAuth\ ") -out ${<!-- -->csr} openssl x509 -in ${<!-- -->csr} -req -CA ${<!-- -->CA_CERT} -CAkey ${<!-- -->CA_KEY} -CAcreateserial -extensions v3_ext \ -extfile <(printf "${csr_conf} extendedKeyUsage = clientAuth\ ") -days ${<!-- -->cert_days} -out ${<!-- -->cert} log::info "generated ${cert}" ;; server) openssl req -new -key ${<!-- -->key} -subj "${subj}" -reqexts v3_ext \ -config <(printf "${csr_conf} extendedKeyUsage = serverAuth\ subjectAltName = ${alt_name}\ ") -out ${<!-- -->csr} openssl x509 -in ${<!-- -->csr} -req -CA ${<!-- -->CA_CERT} -CAkey ${<!-- -->CA_KEY} -CAcreateserial -extensions v3_ext \ -extfile <(printf "${csr_conf} extendedKeyUsage = serverAuth\ subjectAltName = ${alt_name}\ ") -days ${<!-- -->cert_days} -out ${<!-- -->cert} log::info "generated ${cert}" ;; peer) openssl req -new -key ${<!-- -->key} -subj "${subj}" -reqexts v3_ext \ -config <(printf "${csr_conf} extendedKeyUsage = serverAuth, clientAuth\ subjectAltName = ${alt_name}\ ") -out ${<!-- -->csr} openssl x509 -in ${<!-- -->csr} -req -CA ${<!-- -->CA_CERT} -CAkey ${<!-- -->CA_KEY} -CAcreateserial -extensions v3_ext \ -extfile <(printf "${csr_conf} extendedKeyUsage = serverAuth, clientAuth\ subjectAltName = ${alt_name}\ ") -days ${<!-- -->cert_days} -out ${<!-- --> cert} log::info "generated ${cert}" ;; *) log::err "unknow, unsupported etcd certs type: ${cert_type}, supported type: client, server, peer" exit 1 esac rm -f ${<!-- -->csr} } cert::update_kubeconf() {<!-- --> local cert_name=${<!-- -->1} local kubeconf_file=${<!-- -->cert_name}.conf local cert=${<!-- -->cert_name}.crt local key=${<!-- -->cert_name}.key # generate certificate check_file ${<!-- -->kubeconf_file} # get the key from the old kubeconf grep "client-key-data" ${<!-- -->kubeconf_file} | awk {<!-- -->'print$2'} | base64 -d > ${<!-- -->key} # get the old certificate from the old kubeconf grep "client-certificate-data" ${<!-- -->kubeconf_file} | awk {<!-- -->'print$2'} | base64 -d > ${<!-- -->cert} # get subject from the old certificate local subj=$(cert::get_subj ${<!-- -->cert_name}) cert::gen_cert "${cert_name}" "client" "${subj}" "${CAER_DAYS}" # get certificate base64 code local cert_base64=$(base64 -w 0 ${<!-- -->cert}) # backup kubeconf # cert::backup_file "${kubeconf_file}" # set certificate base64 code to kubeconf sed -i 's/client-certificate-data:.*/client-certificate-data: '${<!-- -->cert_base64}'/g' ${<!-- -->kubeconf_file} log::info "generated new ${kubeconf_file}" rm -f ${<!-- -->cert} rm -f ${<!-- -->key} # set config for kubectl if [[ ${<!-- -->cert_name##*/} == "admin" ]]; then mkdir -p ~/.kube cp -fp ${<!-- -->kubeconf_file} ~/.kube/config log::info "copy the admin.conf to ~/.kube/config for kubectl" the fi } cert::update_etcd_cert() {<!-- --> PKI_PATH=${<!-- -->KUBE_PATH}/pki/etcd CA_CERT=${<!-- -->PKI_PATH}/ca.crt CA_KEY=${<!-- -->PKI_PATH}/ca.key check_file "${CA_CERT}" check_file "${CA_KEY}" # generate etcd server certificate # /etc/kubernetes/pki/etcd/server CART_NAME=${<!-- -->PKI_PATH}/server subject_alt_name=$(cert::get_subject_alt_name ${<!-- -->CART_NAME}) cert::gen_cert "${CART_NAME}" "peer" "/CN=etcd-server" "${CAER_DAYS}" "${subject_alt_name}" # generate etcd peer certificate # /etc/kubernetes/pki/etcd/peer CART_NAME=${<!-- -->PKI_PATH}/peer subject_alt_name=$(cert::get_subject_alt_name ${<!-- -->CART_NAME}) cert::gen_cert "${CART_NAME}" "peer" "/CN=etcd-peer" "${CAER_DAYS}" "${subject_alt_name}" # generate etcd healthcheck-client certificate # /etc/kubernetes/pki/etcd/healthcheck-client CART_NAME=${<!-- -->PKI_PATH}/healthcheck-client cert::gen_cert "${CART_NAME}" "client" "/O=system:masters/CN=kube-etcd-healthcheck-client" "${CAER_DAYS}" # generate apiserver-etcd-client certificate # /etc/kubernetes/pki/apiserver-etcd-client check_file "${CA_CERT}" check_file "${CA_KEY}" PKI_PATH=${<!-- -->KUBE_PATH}/pki CART_NAME=${<!-- -->PKI_PATH}/apiserver-etcd-client cert::gen_cert "${CART_NAME}" "client" "/O=system:masters/CN=kube-apiserver-etcd-client" "${CAER_DAYS}" # restart etcd docker ps | awk '/k8s_etcd/{print$1}' | xargs -r -I '{}' docker restart {<!-- -->} || true log::info "restarted etcd" } cert::update_master_cert() {<!-- --> PKI_PATH=${<!-- -->KUBE_PATH}/pki CA_CERT=${<!-- -->PKI_PATH}/ca.crt CA_KEY=${<!-- -->PKI_PATH}/ca.key check_file "${CA_CERT}" check_file "${CA_KEY}" # generate apiserver server certificate # /etc/kubernetes/pki/apiserver CART_NAME=${<!-- -->PKI_PATH}/apiserver subject_alt_name=$(cert::get_subject_alt_name ${<!-- -->CART_NAME}) cert::gen_cert "${CART_NAME}" "server" "/CN=kube-apiserver" "${CAER_DAYS}" "${subject_alt_name}" # generate apiserver-kubelet-client certificate # /etc/kubernetes/pki/apiserver-kubelet-client CART_NAME=${<!-- -->PKI_PATH}/apiserver-kubelet-client cert::gen_cert "${CART_NAME}" "client" "/O=system:masters/CN=kube-apiserver-kubelet-client" "${CAER_DAYS}" # generate kubeconf for controller-manager, scheduler, kubectl and kubelet # /etc/kubernetes/controller-manager,scheduler,admin,kubelet.conf cert::update_kubeconf "${KUBE_PATH}/controller-manager" cert::update_kubeconf "${KUBE_PATH}/scheduler" cert::update_kubeconf "${KUBE_PATH}/admin" # check kubelet.conf # https://github.com/kubernetes/kubeadm/issues/1753 set + e grep kubelet-client-current.pem /etc/kubernetes/kubelet.conf > /dev/null 2> &1 kubelet_cert_auto_update=$? set -e if [[ "$kubelet_cert_auto_update" == "0" ]]; then log::warning "does not need to update kubelet.conf" else cert::update_kubeconf "${KUBE_PATH}/kubelet" the fi # generate front-proxy-client certificate # use front-proxy-client ca CA_CERT=${<!-- -->PKI_PATH}/front-proxy-ca.crt CA_KEY=${<!-- -->PKI_PATH}/front-proxy-ca.key check_file "${CA_CERT}" check_file "${CA_KEY}" CART_NAME=${<!-- -->PKI_PATH}/front-proxy-client cert::gen_cert "${CART_NAME}" "client" "/CN=front-proxy-client" "${CAER_DAYS}" # restart apiserve, controller-manager, scheduler and kubelet docker ps | awk '/k8s_kube-apiserver/{print$1}' | xargs -r -I '{}' docker restart {<!-- -->} || true log::info "restarted kube-apiserver" docker ps | awk '/k8s_kube-controller-manager/{print$1}' | xargs -r -I '{}' docker restart {<!-- -->} || true log::info "restarted kube-controller-manager" docker ps | awk '/k8s_kube-scheduler/{print$1}' | xargs -r -I '{}' docker restart {<!-- -->} || true log::info "restarted kube-scheduler" systemctl restart kubelet log::info "restarted kubelet" } main() {<!-- --> local node_tpye=$1 KUBE_PATH=/etc/kubernetes CAER_DAYS=3650 # backup $KUBE_PATH to $KUBE_PATH.old-$(date + %Y%m%d) cert::backup_file "${KUBE_PATH}" case ${<!-- -->node_tpye} in etcd) # update etcd certificates cert::update_etcd_cert ;; master) # update master certificates and kubeconf cert::update_master_cert ;; all) # update etcd certificates cert::update_etcd_cert # update master certificates and kubeconf cert::update_master_cert ;; *) log::err "unknown, unsupported certs type: ${cert_type}, supported types: all, etcd, master" printf "Documentation: https://github.com/yuyicai/update-kube-cert example: '\033[32m./update-kubeadm-cert.sh all\033[0m' update all etcd certificates, master certificates and kubeconf /etc/kubernetes ├── admin.conf ├── controller-manager.conf ├── scheduler.conf ├── kubelet.conf └── pki ├── apiserver.crt ├── apiserver-etcd-client.crt ├── apiserver-kubelet-client.crt ├── front-proxy-client.crt └── etcd ├── healthcheck-client.crt ├── peer.crt └── server. crt '\033[32m./update-kubeadm-cert.sh etcd\033[0m' update only etcd certificates /etc/kubernetes └── pki ├── apiserver-etcd-client.crt └── etcd ├── healthcheck-client.crt ├── peer.crt └── server. crt '\033[32m./update-kubeadm-cert.sh master\033[0m' update only master certificates and kubeconf /etc/kubernetes ├── admin.conf ├── controller-manager.conf ├── scheduler.conf ├── kubelet.conf └── pki ├── apiserver.crt ├── apiserver-kubelet-client.crt └── front-proxy-client.crt " exit 1 esac } main "$@"
chmod +x update-kubeadm-cert.sh
Execute the following command to modify the certificate expiration time and extend it to 10 years
./update-kubeadm-cert.sh all
Query whether the Pod is normal on the k8smaster1 node, and the data can be queried to indicate that the certificate has been issued
kubectl get pods -n kube-system #The display is as follows, you can see the pod information, indicating that the certificate is issued normally:
openssl x509 -in /etc/kubernetes/pki/ca.crt -noout -text |grep Not
openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text |grep Not
The display is as follows. From the following, you can see that the apiserver certificate is valid for 10 years, from 2025 to 2035: