[Kubernetes] Update Kubernetes APIServer certSANs

Morpheus Huang
6 min readJul 21, 2022

--

0x01 Overview

Kubernetes安裝時,如果沒在kubeadm init時額外設定 --apiserver-cert-extra-sans,或者kubeadm配置檔中設定certSANs,則 APIServer 所使用的 TLS憑證中的SAN清單,僅會有一些預設值,可以透過openssl指令查看當前的SAN包含哪些DNS與IP。

~$ openssl x509 -in apiserver.crt -text
....
X509v3 Subject Alternative Name:
DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, DNS:master-node, IP Address:10.96.0.1, IP Address:10.2.0.11

當一些原因需要額外增加DNS或IP時,就必須先更新APIServer的TLS憑證,否則嘗試連線時就會出現類似以下的錯誤訊息:

Unable to connect to the server: x509: certificate is valid for kubernetes, kubernetes.default, kubernetes.default.svc, kubernetes.default.svc.cluster.local, master-node, not 10–2–0–11.nip.io

底下主要針對如何更新APIServer certSANs流程做說明,操作的Kubernetes版本為 v1.24.1

0x02 更新流程

1.修改kubeadm-config

首先將kube-system/kubeadm-config cm給dump出來。

~$ kubectl -n kube-system get configmap kubeadm-config -o jsonpath='{.data.ClusterConfiguration}' > kubeadm.yaml

內容大概如下:

接著,將要新增的DNS或IP加上certSANs清單中。

apiServer:  
certSANs:
- 10-2-0-11.nip.io
- 10.2.0.11
- 10.96.0.1

2. 產生新的tls憑證

要產生新的tls憑證前,必須先刪除或將舊有的tls憑證移到他處。

~$ mkdir cert_backup
~$ sudo mv /etc/kubernetes/pki/apiserver.{crt,key} cert_backup

接著執行以下指令,產生新的tls憑證。

~$ sudo kubeadm init phase certs apiserver --config kubeadm.yaml
[certs] Generating "apiserver" certificate and key
[certs] apiserver serving cert is signed for DNS names [10-2-0-11.nip.io kubernetes kubernetes.default kubernetes.default.svc kubernetes.default.svc.cluster.local master-node] and IPs [10.96.0.1 10.2.0.11]

如果沒先刪除舊的tls憑證,就執行以上指令的話,會直接使用舊有的憑證,而不會產生新的。

[certs] Using existing apiserver certificate and key on disk

新的tls憑證產生後,可以用文章開頭的openssl指令確認Subject Alternative Name欄位中是否正確。

PS:其實如果單純要產生新的tls憑證,也可以透過以下指令直接產生,不需要產生一個kubeadm.yaml

~$ sudo kubeadm init phase certs apiserver --apiserver-cert-extra-sans=10–2–0–11.nip.io

不過,因為後續還需要將設定寫回kubeadm-config,因此還是得修改kubeadm-config配置檔。

3. 重啟Kubernetes API Server

Kubernetes 1.24後,已經不在支援dockershim,因此這裡使用的是cri-o runtime,可以透過crictl指令查詢apiserver的id,然後刪掉container等待kubelet自動將apiserver重啟。

~$ sudo crictl pods | grep kube-apiserver | cut -d' ' -f1
~$ sudo crictl stopp <pod-id>
~$ sudo crictl rmp <pod-id>

其實直接delete API Server的Pod,好像也是一樣的意思….

4. 更新kubeadm-config

API Server重啟後,可以直接修改 ~/.kube/config中的server address,然後透過kubectl指令測試是否正常。

如果操作都正常,需將先前第一步修改好的kubeadm-config更新到configmap中。

~$ sudo kubeadm init phase upload-config kubeadm --config kubeadm.yaml
[upload-config] Storing the configuration used in ConfigMap "kubeadm-config" in the "kube-system" Namespace

更新後,可以也可以透過以下指令確認是否真的更新到configmap上。

~$ kubectl -n kube-system get configmap kubeadm-config -o jsonpath='{.data.ClusterConfiguration}'

0x03 結論

本文主要紀錄一下之前更新Kubernetes certSANs的過程,省的每次有需要時都要額外去找資料。

0x04 參考資料

https://blog.scottlowe.org/2019/07/30/adding-a-name-to-kubernetes-api-server-certificate/

--

--