🔒

Kubernetesクラスターでkubectlが通らなくなった【証明書期限切れ】

2024/06/20に公開

自宅サーバー(Proxmox)でHA構成のKubernetesクラスターを構築してから早一年が経ちました。 詳しくはこちらの記事でまとめています。
しかし、久しぶりに様子を見てみるとkubectlなどのコマンドが全く通らなくなってしまいました。今回はそのトラブルシューティングをまとめようと思います。

エラー内容

最初はk9sが落ちることに気づき、kubectlコマンドを実行してみてもtimeoutが生じていることが確認できました。

$ kubectl get nodes
E0613 09:31:17.589658 26729 memcache.go:265] couldn't get current server API group list: Get "https://192.168.1.90:6443/api?timeout=32s": net/http: TLS handshake timeout
E0613 09:31:32.139369 26729 memcache.go:265] couldn't get current server API group list: Get "https://192.168.1.90:6443/api?timeout=32s": read tcp 192.168.1.85:40754->192.168.1.90:6443: read: connection reset by peer - error from a previous attempt: EOF

再起動しても変わらず、control planeの前段にリバースプロキシを設置していたためそちらの問題かとも思いましたが、リバースプロキシ自体は問題なさそうでした。
また、今まで動いていたのが急に動かなくなったのも気になりました。 以前はcontrol planeのストレージ容量が無くなり落ちたことがありましたが、容量も問題なさそうでした。

原因

タイトルでお察しの通りだと思いますが、結局、原因はkubernetesクラスターの証明書が切れていたことが問題でした。
control planeに入って、証明書の期限を確認してみるととっくに期限が切れていることがわかりました。

$ sudo kubeadm certs check-expiration
[check-expiration] Reading configuration from the cluster...
[check-expiration] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[check-expiration] Error reading configuration from the Cluster. Falling back to default configuration

CERTIFICATE                EXPIRES                  RESIDUAL TIME   CERTIFICATE AUTHORITY   EXTERNALLY MANAGED
admin.conf                 Apr 06, 2024 16:36 UTC   <invalid>       ca                      no
apiserver                  Apr 06, 2024 16:36 UTC   <invalid>       ca                      no
apiserver-etcd-client      Apr 06, 2024 16:36 UTC   <invalid>       etcd-ca                 no
apiserver-kubelet-client   Apr 06, 2024 16:36 UTC   <invalid>       ca                      no
controller-manager.conf    Apr 06, 2024 16:36 UTC   <invalid>       ca                      no
etcd-healthcheck-client    Apr 06, 2024 16:36 UTC   <invalid>       etcd-ca                 no
etcd-peer                  Apr 06, 2024 16:36 UTC   <invalid>       etcd-ca                 no
etcd-server                Apr 06, 2024 16:36 UTC   <invalid>       etcd-ca                 no
front-proxy-client         Apr 06, 2024 16:36 UTC   <invalid>       front-proxy-ca          no
scheduler.conf             Apr 06, 2024 16:36 UTC   <invalid>       ca                      no

CERTIFICATE AUTHORITY   EXPIRES                  RESIDUAL TIME   EXTERNALLY MANAGED
ca                      Mar 18, 2033 05:46 UTC   8y              no
etcd-ca                 Mar 18, 2033 05:46 UTC   8y              no
front-proxy-ca          Mar 18, 2033 05:46 UTC   8y              no

証明書が切れていことで、クラスター内の通信がtimeoutしていたようです。
これは推測ですが、Kubernetesに載せているアプリケーション自体がずっと動いていたのは、既にnodeでstartしたpodは、他nodeとの通信がなくとも動き続けることができるからではないかと思います。
もしかしたらpodが落ちてしまったらrestartできないかもしれません。

対処法

対処法として、証明書を更新する必要があります。
まず、control planeに入って、以下を実行します。

$ sudo kubeadm certs renew all
[renew] Reading configuration from the cluster...
[renew] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[renew] Error reading configuration from the Cluster. Falling back to default configuration

certificate embedded in the kubeconfig file for the admin to use and for kubeadm itself renewed
certificate for serving the Kubernetes API renewed
certificate the apiserver uses to access etcd renewed
certificate for the API server to connect to kubelet renewed
certificate embedded in the kubeconfig file for the controller manager to use renewed
certificate for liveness probes to healthcheck etcd renewed
certificate for etcd nodes to communicate with each other renewed
certificate for serving etcd renewed
certificate for the front proxy client renewed
certificate embedded in the kubeconfig file for the scheduler manager to use renewed

Done renewing certificates. You must restart the kube-apiserver, kube-controller-manager, kube-scheduler and etcd, so that they can use the new certificates.

証明書の期限を確認してみると、確かに更新されていることがわかります。

$ sudo kubeadm certs check-expiration
[check-expiration] Reading configuration from the cluster...
[check-expiration] FYI: You can look at this config file with 'kubectl -n kube-system get cm kubeadm-config -o yaml'
[check-expiration] Error reading configuration from the Cluster. Falling back to default configuration

CERTIFICATE                EXPIRES                  RESIDUAL TIME   CERTIFICATE AUTHORITY   EXTERNALLY MANAGED
admin.conf                 Jun 14, 2025 14:26 UTC   364d            ca                      no
apiserver                  Jun 14, 2025 14:26 UTC   364d            ca                      no
apiserver-etcd-client      Jun 14, 2025 14:26 UTC   364d            etcd-ca                 no
apiserver-kubelet-client   Jun 14, 2025 14:26 UTC   364d            ca                      no
controller-manager.conf    Jun 14, 2025 14:26 UTC   364d            ca                      no
etcd-healthcheck-client    Jun 14, 2025 14:26 UTC   364d            etcd-ca                 no
etcd-peer                  Jun 14, 2025 14:26 UTC   364d            etcd-ca                 no
etcd-server                Jun 14, 2025 14:26 UTC   364d            etcd-ca                 no
front-proxy-client         Jun 14, 2025 14:26 UTC   364d            front-proxy-ca          no
scheduler.conf             Jun 14, 2025 14:26 UTC   364d            ca                      no

CERTIFICATE AUTHORITY   EXPIRES                  RESIDUAL TIME   EXTERNALLY MANAGED
ca                      Mar 18, 2033 05:46 UTC   8y              no
etcd-ca                 Mar 18, 2033 05:46 UTC   8y              no
front-proxy-ca          Mar 18, 2033 05:46 UTC   8y              no

しかし、kubectlで使用する証明書の期限を確認してみると、期限切れのままです(場合によってはyqコマンドのインストールが必要)。

$ yq -r '.users[0].user."client-certificate-data"' <.kube/config | base64 -d | openssl x509 -text
Certificate:
    Data:
        Version: 3 (0x2)
...
        Validity
            Not Before: Mar 21 05:46:30 2023 GMT
            Not After : Mar 20 06:08:52 2024 GMT

どうやらこちらは手動で更新する必要があるようです。

sudo cp /etc/kubernetes/admin.conf ~/.kube/config

もう一度確認してみると正しく更新されていることがわかります。

$ yq -r '.users[0].user."client-certificate-data"' <.kube/config | base64 -d | openssl x509 -text
Certificate:
    Data:
        Version: 3 (0x2)
...
        Validity
            Not Before: Mar 21 05:46:30 2023 GMT
            Not After : Jun 14 14:26:14 2025 GMT

これらを全てのcontrol planeで実行します。 場合によっては再起動が必要そうです。

また、手元からKubernetesクラスターにkubectlなどのコマンドを実行するためには、手元の証明書の更新も必要です。
次にControl Planeで以下を実行します。

$ kubectl config view --raw

出力内容を手元のMac上のこのファイルに書きます。

$ sudo vi $HOME/.kube/config

終わりに

なんで自動更新してくれないんだろうと思ったんですが、Kubernetesをupdateしたら自動で証明書も更新されるみたいです。
Kubernetesのupdateは頻繁なので、きっちりupdateしていれば問題ないよう…
今後はきちんとupdateしていきます。

Discussion