过期后如何更新Kubernetes的PKI证书

32

我的kubernetes PKI过期了(确切地说是API服务器),我找不到续订的方法。我收到的错误信息是

May 27 08:43:51 node1 kubelet[8751]: I0527 08:43:51.922595    8751 server.go:417] Version: v1.14.2
May 27 08:43:51 node1 kubelet[8751]: I0527 08:43:51.922784    8751 plugins.go:103] No cloud provider specified.
May 27 08:43:51 node1 kubelet[8751]: I0527 08:43:51.922800    8751 server.go:754] Client rotation is on, will bootstrap in background
May 27 08:43:51 node1 kubelet[8751]: E0527 08:43:51.925859    8751 bootstrap.go:264] Part of the existing bootstrap client certificate is expired: 2019-05-24 13:24:42 +0000 UTC
May 27 08:43:51 node1 kubelet[8751]: F0527 08:43:51.925894    8751 server.go:265] failed to run Kubelet: unable to load bootstrap
kubeconfig: stat /etc/kubernetes/bootstrap-kubelet.conf: no such file or directory
https://kubernetes.io/docs/tasks/administer-cluster/kubeadm/kubeadm-certs/的文档介绍了如何更新证书,但仅当API服务器未过期时才有效。我尝试过进行更新,但发现API服务器已过期。
kubeadm alpha cert renew all

然后我尝试重启,但这导致整个集群失败,因此我回滚到快照(我的集群运行在VMware上)。

集群正在运行,所有容器似乎都在工作,但我无法通过kubectl访问它,因此我无法部署或查询。

我的kubernetes版本是1.14.2。

13个回答

72

所以解决方案是(首先进行备份)

$ cd /etc/kubernetes/pki/
$ mv {apiserver.crt,apiserver-etcd-client.key,apiserver-kubelet-client.crt,front-proxy-ca.crt,front-proxy-client.crt,front-proxy-client.key,front-proxy-ca.key,apiserver-kubelet-client.key,apiserver.key,apiserver-etcd-client.crt} ~/
$ kubeadm init phase certs all --apiserver-advertise-address <IP>
$ cd /etc/kubernetes/
$ mv {admin.conf,controller-manager.conf,kubelet.conf,scheduler.conf} ~/
$ kubeadm init phase kubeconfig all
$ reboot

然后

$ cp -i /etc/kubernetes/admin.conf $HOME/.kube/config

那对我有帮助,谢谢你的提示 :)


8
谢谢!我想补充一下,我还必须从/etc/kubernetes/pki/etcd/中删除我的etcd .crt和.key文件,否则我会得到“error execution phase certs/etcd-peer: failed to write certificate "etcd-peer": failure loading etcd/peer certificate: failed to load certificate: the certificate has expired”错误提示。 - yee379
1
我有两个主节点。该集群是使用kubespray进行的高可用设置。因此,我很困惑应该在哪个主节点上执行此过程..我应该在两个主节点上都执行吗?另外,--apiserver-advertise-address的值应该是什么? - AnjK
3
你刚刚救了一天。FYI:你可以考虑用 kubeadm init phase certs all --apiserver-advertise-address <public ip> --apiserver-cert-extra-sans=<private ip1>,<private ip2> 替换第三行,并运行 systemctl restart docker && system restart kubelet 代替 reboot - wizawu
2
我做了这个,现在所有节点都显示“未授权”。使用单个主节点运行kubernetes 1.16.9,有什么想法吗? - Reda Drissi
有没有在Windows机器上解决这个问题的方法?我的本地Kubernetes证书已经过期了。我尝试重新安装Docker桌面版并启用Kubernetes,但现在它无法启动,即使清除了数据也是如此? - Naveen Gopalakrishna
显示剩余2条评论

9

这个话题也在以下讨论中提到:


Kubernetes v1.15 在 "使用kubeadm进行证书管理" 中提供文档:

kubeadm alpha certs check-expiration
  • 自动证书续订:
    • kubeadm在控制平面升级期间自动续订所有证书。
  • 手动证书续订:
    • 您可以使用kubeadm alpha certs renew命令随时手动更新证书。
    • 此命令使用存储在/etc/kubernetes/pki中的CA(或front-proxy-CA)证书和密钥执行更新。

总体而言,对于Kubernetes v1.14,我认为以下过程最有帮助:


命令"kubeadmin alpha certs renew"非常有用。之后,我还需要执行一个额外的步骤来解决“bootstrap-kubelet.conf不存在”的问题,这会导致kubelet无法重新启动。按照此处所述的方式运行以下命令“sudo kubeadm alpha kubeconfig user --org system:nodes --client-name system:node:$(hostname) > kubelet.conf”,以解决该问题 https://github.com/kubernetes/kubernetes/issues/84252 - kasur

5
我使用的是 Kubernetes v15.1,并按照上述说明更新了我的证书,但仍然遇到了相同的错误。 /etc/kubernetes/kubelet.conf 仍然在引用已过期/旧的 "client-certificate-data"。
经过一些研究,我发现 kubeadm 如果未将证书更新设置为 true,则不会更新 /etc/kubernetes/kubelet.conf 文件。因此,请注意 kubeadm 版本低于 1.17 的错误(https://github.com/kubernetes/kubeadm/issues/1753)。
kubeadm 只有在集群升级时使用 certificate-renewal=true 才会进行升级。所以我必须手动删除 /etc/kubernetes/kubelet.conf,并使用 kubeadm init phase kubeconfig kubelet 重新生成它,最终解决了我的问题。

4
尝试使用kubeadm init phase certs命令进行证书更新。您可以通过以下命令检查证书过期时间: openssl x509 -in /etc/kubernetes/pki/apiserver.crt -noout -text openssl x509 -in /etc/kubernetes/pki/apiserver-kubelet-client.crt -noout -text 首先,请确保您拥有最新的k8s证书清单备份/etc/kubernetes/pki/*
删除/etc/kubernetes/pki/目录下的apiserver.*apiserver-kubelet-client.*证书文件。
通过kubeadm init phase certs命令生成新证书: sudo kubeadm init phase certs apiserver sudo kubeadm init phase certs apiserver-kubelet-client 重新启动kubeletdocker守护程序: sudo systemctl restart docker; sudo systemctl restart kubelet 您可以在官方K8s文档中找到更多相关信息。

2
谢谢..我已经按照上述步骤操作并创建了front-proxy-ca。所有证书都在 /etc/kubernetes/pki 中更新,但是当我重新启动 kubelet 时仍然出现以下错误: - Kim Nielsen
2
5月27日16:19:43 node1 kubelet[28167]: E0527 16:19:43.234981 28167 bootstrap.go:264] 现有的引导客户端证书部分已过期:2019-05-24 13:24:42 +0000 UTC5月27日16:19:43 node1 kubelet[28167]: F0527 16:19:43.235227 28167 server.go:265] Kubelet运行失败:无法加载引导kubeconfig:stat /etc/kubernetes/bootstrap-kubelet.conf:没有这样的文件或目录5月27日16:19:43 node1 systemd[1]: kubelet.service:主进程退出,代码=退出,状态=255/n/a - Kim Nielsen
3
多谢你,我通过你的帮助搞定了。我只需要重新创建所有的配置文件即可。 - Kim Nielsen
1
@KimNielsen 你是怎么解决这个问题的?我有一个由2个主节点组成的集群设置,我在其中一个主节点上更新了证书。然后我重启了服务器,但它仍然显示了你遇到的同样的错误。之前所有正在运行的容器现在都已经停止了。 - AnjK
我实际上就像我在解决方案中粘贴的那样做了。当时我只有一个主节点,所以我不知道如果有多个主节点是否会有所不同。 - Kim Nielsen

3

这会更新 /etc/kubernetes/ssl 下的所有证书。

kubeadm alpha certs renew all --config=/etc/kubernetes/kubeadm-config.yaml

重新启动服务器组件,请执行以下操作:

kill -s SIGHUP $(pidof kube-apiserver)
kill -s SIGHUP $(pidof kube-controller-manager)
kill -s SIGHUP $(pidof kube-scheduler)

2
[root@nrchbs-slp4115 ~]# kubectl get apiservices |egrep metrics
v1beta1.metrics.k8s.io                 kube-system/metrics-server   True        125m


[root@nrchbs-slp4115 ~]# kubectl get svc -n kube-system
NAME             TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)                  AGE
kube-dns         ClusterIP   10.96.0.10   <none>        53/UDP,53/TCP,9153/TCP   20d
metrics-server   ClusterIP   10.99.2.11   <none>        443/TCP                  125m


[root@nrchbs-slp4115 ~]# kubectl get ep -n kube-system
NAME                      ENDPOINTS                                               AGE
kube-controller-manager   <none>                                                  20d
kube-dns                  10.244.0.5:53,10.244.0.6:53,10.244.0.5:53 + 3 more...   20d
kube-scheduler            <none>                                                  20d
metrics-server            10.244.2.97:443                                         125m
[root@nrchbs-slp4115 ~]#

1
在编程中,如果你能够包含一些细节或者参考资料以供进一步学习,那么这将会是额外的加分项。这样可以使你的答案更有用。 - mw509

2

如果有其他人需要进行多主设置,我可以提供帮助。在第一个主节点更新后,我找到了另一个问题的解决方法:

只有使用certificate-renewal=true升级集群时,kubeadm才会执行升级操作。因此,我手动删除了/etc/kubernetes/kubelet.conf文件,并使用kubeadm init phase kubeconfig kubelet重新生成它,最终解决了我的问题。


1

在我的情况下,证书续订后出现了同样的问题。我的集群是使用Kubespray构建的。我的kubelet停止工作,并且它说我没有/etc/kubernetes/bootstrap-kubelet.conf文件,所以我查看了这个配置文件的作用。

--bootstrap-kubeconfig string
  | Path to a kubeconfig file that will be used to get client certificate for kubelet. If the file specified by --kubeconfig does not exist, the bootstrap kubeconfig is used to request a client certificate from the API server. On success, a kubeconfig file referencing the generated client certificate and key is written to the path specified by --kubeconfig. The client certificate and key file will be stored in the directory pointed by --cert-dir.

我理解这个文件可能不是必需的。


请注意,我使用以下方式更新了k8s 1.19:

kubeadm alpha certs renew apiserver-kubelet-client
kubeadm alpha certs renew apiserver
kubeadm alpha certs renew front-proxy-client

...而那并不足够。


解决方案是

cp -r /etc/kubernetes /etc/kubernetes.backup

kubeadm alpha kubeconfig user --client-name system:kube-controller-manager > /etc/kubernetes/controller-manager.conf
kubeadm alpha kubeconfig user --client-name system:kube-scheduler > /etc/kubernetes/scheduler.conf
kubeadm alpha kubeconfig user --client-name system:node:YOUR_MASTER_HOSTNAME_IS_HERE --org system:nodes > /etc/kubernetes/kubelet.conf

kubectl --kubeconfig /etc/kubernetes/admin.conf get nodes

1
最好的解决方案就像Kim Nielsen所写的那样。
$ cd /etc/kubernetes/pki/
$ mv {apiserver.crt,apiserver-etcd-client.key,apiserver-kubelet-client.crt,front-proxy-ca.crt,front-proxy-client.crt,front-proxy-client.key,front-proxy-ca.key,apiserver-kubelet-client.key,apiserver.key,apiserver-etcd-client.crt} ~/
$ kubeadm init phase certs all --apiserver-advertise-address <IP>
$ cd /etc/kubernetes/
$ mv {admin.conf,controller-manager.conf,kubelet.conf,scheduler.conf} ~/
$ kubeadm init phase kubeconfig all
$ reboot

通过下面的命令,您可以检查新认证何时到期:

$ kubeadm alpha certs check-expiration --config=/etc/kubernetes/kubeadm-config.yaml 

或者

$ kubeadm certs check-expiration --config=/etc/kubernetes/kubeadm-config.yaml

然而,如果您有多个主服务器,则需要在这些服务器上复制这些文件。

登录第二台主服务器并执行(备份):

$ cd /etc/kubernetes/pki/
$ mv {apiserver.crt,apiserver-etcd-client.key,apiserver-kubelet-client.crt,front-proxy-ca.crt,front-proxy-client.crt,front-proxy-client.key,front-proxy-ca.key,apiserver-kubelet-client.key,apiserver.key,apiserver-etcd-client.crt} ~/
$ cd /etc/kubernetes/
$ mv {admin.conf,controller-manager.conf,kubelet.conf,scheduler.conf} ~/

接下来,请登录到第一个主节点(您创建新证书的地方),并执行以下命令(将node2更改为第二个主节点机器的IP地址):

$ rsync /etc/kubernetes/pki/*.crt -e ssh root@node2:/etc/kubernetes/pki/
$ rsync /etc/kubernetes/pki/*.key -e ssh root@node2:/etc/kubernetes/pki/
$ rsync /etc/kubernetes/*.conf -e ssh root@node2:/etc/kubernetes/

1
我使用一个名为config.yaml的文件来配置主节点,因此对我来说,答案是:
sudo -i
mkdir -p ~/k8s_backup/etcd
cd /etc/kubernetes/pki/
mv {apiserver.crt,apiserver-etcd-client.key,apiserver-kubelet-client.crt,front-proxy-ca.crt,front-proxy-client.crt,front-proxy-client.key,front-proxy-ca.key,apiserver-kubelet-client.key,apiserver.key,apiserver-etcd-client.crt} ~/k8s_backup
cd /etc/kubernetes/pki/etcd
mv {healthcheck-client.crt,healthcheck-client.key,peer.crt,peer.key,server.crt,server.key} ~/k8s_backup/etcd/
kubeadm init phase certs all --ignore-preflight-errors=all --config /etc/kubernetes/config.yaml

cd /etc/kubernetes
mv {admin.conf,controller-manager.conf,kubelet.conf,scheduler.conf} ~/k8s_backup
kubeadm init phase kubeconfig all --config /etc/kubernetes/config.yaml --ignore-preflight-errors=all

为了保险起见,我重新启动

shutdown now -r

如果我有两个主节点怎么办?我需要在两台主机上都执行该过程吗? 使用--config /etc/kubernetes/config.yaml而不是--apiserver-advertise-address <IP>是否足够? - AnjK
实际上,在重新启动后,我无法连接到集群并显示错误:“拒绝连接到服务器10.0.2.101:6443 - 您是否指定了正确的主机或端口?”。在使用$docker ps 进行检查时,没有相关于k8s的容器处于运行状态。 - AnjK

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接