TLS証明書のエラーでkubectlが使用できなくなった

概要

こんにちは。

ある日、kubectlコマンドを叩いたとこと、 「 Unable to connect to the server: x509: certificate has expired or is not yet valid: current time 2022-03-06T05:32:47+09:00 is after 2022-02-26T20:40:29Z 」 のエラーが出るようになり、操作が出来なくなってしまいました。

発生原因

これは、kubeadmで生成されたクライアント証明書は1年で失効するものによるものです。

対処

証明書の更新をおこなえば解決するので、実際に更新作業をおこなっていきたいと思います。

手順

エラーがでることを確認

kubectlコマンドを使用するとTLS証明書の期限が切れている旨のエラーがでます。

kubectl get po

Unable to connect to the server: x509: certificate has expired or is not yet valid: current time 2022-03-06T05:32:47+09:00 is after 2022-02-26T20:40:29Z

証明書の有効期限を確認

「2022年2月27日 日曜日 05時40分00秒」でクライアント証明書の有効期限が切れてしまっていることが確認できます。

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                 Feb 26, 2022 20:40 UTC   <invalid>                               no
apiserver                  Feb 26, 2022 20:40 UTC   <invalid>       ca                      no
apiserver-etcd-client      Feb 26, 2022 20:40 UTC   <invalid>       etcd-ca                 no
apiserver-kubelet-client   Feb 26, 2022 20:40 UTC   <invalid>       ca                      no
controller-manager.conf    Feb 26, 2022 20:40 UTC   <invalid>                               no
etcd-healthcheck-client    Feb 26, 2022 20:40 UTC   <invalid>       etcd-ca                 no
etcd-peer                  Feb 26, 2022 20:40 UTC   <invalid>       etcd-ca                 no
etcd-server                Feb 26, 2022 20:40 UTC   <invalid>       etcd-ca                 no
front-proxy-client         Feb 26, 2022 20:40 UTC   <invalid>       front-proxy-ca          no
scheduler.conf             Feb 26, 2022 20:40 UTC   <invalid>                               no

CERTIFICATE AUTHORITY   EXPIRES                  RESIDUAL TIME   EXTERNALLY MANAGED
ca                      Feb 24, 2031 20:40 UTC   8y              no
etcd-ca                 Feb 24, 2031 20:40 UTC   8y              no
front-proxy-ca          Feb 24, 2031 20:40 UTC   8y              no

kubectlコマンドを使用する際に使う、 .kube/config を確認

cat /root/.kube/config | grep "client-certificate-data:" | awk '{ print $2 }' | base64 --decode

証明書データは、base64でデコードする必要があるので注意。
実行すると、「—–BEGIN CERTIFICATE—–」~「—–END CERTIFICATE—–」までの証明書データが確認可能なので「SSL証明書(crt) 内容確認ツール」等で確認しましょう。

筆者の場合、「有効開始日が2021-02-27 05:40:29」で「有効期限日が2022-02-27 05:40:37」となっていました。

証明書の更新

更新自体は簡単で、 kubeadm certs renew all コマンドを使用すれば全ての証明書を新しいものに更新してくれます。

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.

更新後確認

再度、 kubeadm certs check-expiration コマンドを実行すると無事に1年間期限が増えたことが確認できます。

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                 Mar 05, 2023 21:02 UTC   364d                                    no
apiserver                  Mar 05, 2023 21:02 UTC   364d            ca                      no
apiserver-etcd-client      Mar 05, 2023 21:02 UTC   364d            etcd-ca                 no
apiserver-kubelet-client   Mar 05, 2023 21:02 UTC   364d            ca                      no
controller-manager.conf    Mar 05, 2023 21:02 UTC   364d                                    no
etcd-healthcheck-client    Mar 05, 2023 21:02 UTC   364d            etcd-ca                 no
etcd-peer                  Mar 05, 2023 21:02 UTC   364d            etcd-ca                 no
etcd-server                Mar 05, 2023 21:02 UTC   364d            etcd-ca                 no
front-proxy-client         Mar 05, 2023 21:02 UTC   364d            front-proxy-ca          no
scheduler.conf             Mar 05, 2023 21:02 UTC   364d                                    no

CERTIFICATE AUTHORITY   EXPIRES                  RESIDUAL TIME   EXTERNALLY MANAGED
ca                      Feb 24, 2031 20:40 UTC   8y              no
etcd-ca                 Feb 24, 2031 20:40 UTC   8y              no
front-proxy-ca          Feb 24, 2031 20:40 UTC   8y              no

kubeconfigのコピー

今ログインしているユーザでkubectlコマンド等を使用できるようにするため、configファイルコピーします。

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

コピーしたconfigの証明書を再度確認し、「有効期限日」が1年間伸ばされていれば問題ありません。

暫くまち、 kubectl get po コマンドを実行し、エラーがでなければ問題ありません。

ワーカーノードで適用

証明書の更新後、master側で、 kubectl get nodes を実行すると、ワーカーノードで NotReady 状態になることが分かりました。

解決の糸口が見つかりませんでしたので、ワーカーノードで、 kubeadm reset をおこない、 master 側で、 joinコマンドを発行後、ワーカーノードを master に参加させるようにします。

まず、 master 側で kubeadm token create --print-join-command を実行し、 join コマンドを発行します、発行されたものはどこかにメモしておくようにします。

ワーカーノードで、 kubeadm reset コマンドを実行します。

リセットが完了すると以下メッセージでることを確認します。

The reset process does not clean your kubeconfig files and you must remove them manually.
Please, check the contents of the $HOME/.kube/config file.

先ほど、 master 側で発行した join コマンドをそのまま、ワーカーノードで実行します。

以下の様に、クラスターに参加した旨のメッセージがでれば問題ありません。

This node has joined the cluster:
* Certificate signing request was sent to apiserver and a response was received.
* The Kubelet was informed of the new secure connection details.

Run 'kubectl get nodes' on the control-plane to see this node join the cluster.

その後、 master 側で、 kubectl get nodes を実行し、対象のワーカーノードが、 Ready 状態になっていれば問題ありません。

ワーカーノードをリセットしても、そのワーカーノードで動作していたPOD達は、masterで記憶されているので、コンテナ自体が消えるということはなさそうでした。

まとめ

kubectlコマンドを使用した際に突然、エラーがでたので焦りました。

案外簡単に解決できると思っていましたが、ワーカーノードをリセットする羽目になるとは思いませんでした。

証明書の管理方法などもう少し勉強が必要だなぁと思った次第です。

参考文献