单容器 rancher&k3s 证书更新

问题背景

大部分情况时,用户在部署k3s时都会使用k3s内部自动签发的证书,证书的有效期是1年。官方文档中介绍:https://rancher.com/docs/k3s/latest/en/advanced/#certificate-rotation

如果证书过期或者有效期少于90天,可以通过重启k3s来实现证书的轮转,以延长有效期。

如果是单独使用k3s,重启k3s才能实现证书轮转,这种操作对于很多用户来说,比较难以接受。

除此之外,k3s已经内置在rancher-server中,且在HA模式中会推荐作为rancher-server的local集群。尽管rancher-server的证书自带轮转功能,但是对接使用的k3s依然是1年有效期。单点模式下,需要重启rancher-server才能完成k3s证书轮转;HA模式下,则需要对Local k3s集群进行重启。这些操作,对生产环境的用户是灾难性的。

问题模拟

由于单点rancher-server会内置启动k3s,且会使用k3s的api。我们可以通过rancher-server来模拟k3s一年期证书的影响。

运行rancher-server(以2.4.8为例),可以查看相关证书的有效期:

# 以ubuntu bionic 为例

$ systemctl stop systemd-timesyncd

$ docker run -d –restart=unless-stopped -p 8080:80 -p 8443:443 rancher/rancher:v2.4.8

# check k3s certs

$ docker exec -it <cid> bash

cd /var/lib/rancher/k3s/server/tls

 for f in $(ls *.crt); do echo “===$f===”; openssl x509 -dates -noout -in $f; done

假设当前系统时间为 Oct 22 GMT 2020,那么CA根证书大概会到 Oct 20 2030 GMT,普通证书大概到 Oct 22 2021 GMT

模拟系统运行超过1年,证书超期,调整系统时间:

$ date -s “+13 months”

查看server logs,会发现其实server已经无法提供服务,出现大量证书过期提示:

2021-11-22 05:33:58.108446 I | http: TLS handshake error from 127.0.0.1:45536: remote error: tls: bad certificate

2021/11/22 05:33:58 [INFO] Waiting for server to become available: Get https://127.0.0.1:6443/version?timeout=30s: x509: certificate has expired or is not yet valid

2021-11-22 05:34:00.110461 I | http: TLS handshake error from 127.0.0.1:45538: remote error: tls: bad certificate

2021/11/22 05:34:00 [INFO] Waiting for server to become available: Get https://127.0.0.1:6443/version?timeout=30s: x509: certificate has expired or is not yet valid

此时,由于证书过期,我们根据k3s文档说明,重启k3s进行证书轮转。在Rancher环境中,重启server容器就是重启k3s,重启后你会发现证书确实轮转了。CA根证书的有效期没有变化,而普通证书大概到 Nov 22 2022 GMT

继续验证rancher-server是否可用,会发现server依然无法提供服务,且依然出现大量证书过期提示,进行server容器内,kubectl访问k3s也提示证书无效:

$ kubectl get  all

Unable to connect to the server: x509: certificate has expired or is not yet valid

进一步挽救前,先了解k3s api。k3s API本身启用6443端口,k3s内置的kube api-server启动6444端口,相当于在6443端口扩展了额外的k3s API,同时有将面向k8s api的请求转发给6444 kube-api-server端口。目前kube api-server端口的证书已经轮转,但是前面的6443端口的证书没有轮转,导致了server依然无法使用k3s api。挽救方式如下:

# 进入server 容器

$ kubectl –insecure-skip-tls-verify -n kube-system delete secrets k3s-serving

$ rm -f /var/lib/rancher/k3s/server/tls/dynamic-cert.json

再次重启server容器后,k3s-serving证书也会自动轮转,k3s api已经可用,server中不会出现证书过期的提示。

然而,其实我们只解决了k3s api和kube api-server的证书问题,rancher api的证书其实还是过期的:

# Rancher UI setting中获取cacert证书 保存到 rancher-ca.crt

# 尝试本地请求Rancher API

curl –cacert rancher-ca.crt -vv https://localhost:8443

# 返回信息中提示证书过期

下面表格中列出了调用链路上的各个证书,Rancher API(tls-rancher secret)的CA证书是10年,这里没有列出:

证书存放形式作用
Rancher API证书kubectl get secret serving-cert -n cattle-system;

Golang runtime 内存中;

浏览器中访问Rancher;

Rancher Agent访问连接Rancher Server

K3S API证书kubectl get secret k3s-serving -n kube-system

/var/lib/rancher/k3s/server/tls/dynamic-cert.json

访问k3s api时校验
Kube API证书/var/lib/rancher/k3s/server/tls/ 目录下各种证书K3s api转发给kube api时校验

由于Rancher API证书在内存和secret中储存,且内存是优先访问。当我们希望Rancher重新生成其API证书,通过删除serving-cert secret后,Rancher API证书依然是持续工作的,此时使用内存中的保留证书。删除serving-cert secre后再重启rancher,才能确保生产新的Rancher API证书。

$ kubectl delete secret serving-cert -n cattle-system

# restart server

$ docker restart <xxx>

此时证书重新生成,我们可以拿到一个有效期合理的证书。然而,证书在校验时还要验证请求Host是否在证书允许的IP/Domain中。这时的新证书还没有把Rancher server-url对应的Host加入允许的IP/Domain中,会发现Rancher Agent依然会报证书无效的错误而无法连接server。

# check the new cert

# localhost等本地IP可以访问,而server-url访问API还是会有问题

curl –cacert rancher-ca.crt -vv https://localhost:8443

……

……

* Server certificate:

*  subject: O=dynamic; CN=dynamic

*  start date: Oct 22 06:36:36 2020 GMT

*  expire date: Nov 22 07:32:39 2022 GMT

重新签发一个支持server-url Host的证书,通过Curl Client访问Rancher API某个路径即可。最终,Rancher API也可以正常访问,并且达到期望的有效期。注意Rancher中过滤了其他的Request Host,只会签发server-url host的证书(https://github.com/rancher/rancher/blob/release/v2.5/pkg/tls/tls.go#L250-L267):

# refresh cert with curl client

curl –insecure -sfL https://server-url/v3

刷新Rancher API证书时,可以在server logs看到相关提示:

[INFO] Updating TLS secret for serving-cert …

[INFO] Active TLS secret serving-cert

[INFO] Active TLS secret serving-cert

以下几点注意:

  • 通过浏览器访问无法刷新cert的可信任IP,因为Rancher代码中通过代码判断了浏览器的请求头不会触发刷新证书。
  • 通过浏览器访问,如果已经信任证书,即使证书过期也是可以访问的,这相当于忽略证书校验。然而,agent和server之间的访问会有问题,因为agent发起请求时并不会忽略证书校验。
  • Rancher API证书自带过期检测和定期刷新机制,但是这个检测执行间隔很长(>6h),有运气的话恰好会碰到。
  • 试图手动编辑secret里面的证书,通常不能立即生效。因为内存中还有一个副本,且具有优先访问权。

我们可以总结一下,Rancher/k3s在运行超过1年后,由于证书问题可能产生的影响:

场景影响解决方式
单点RancherRancher API证书可能失效;

K3s API证书一定失效;

Kube API证书一定失效;

删除serving-cert和k3s-serving;

删除文件dynamic-cert.json;

重启rancher-server;

通过curl重签加入server-url Host;

Rancher HA + RKERancher API证书可能失效;

RKE基本是10年证书,很难过期;

删除serving-cert;

重启rancher-server;

通过curl重签加入server-url Host;

Rancher HA + K3SRancher API证书可能失效;

K3s API证书一定失效;

Kube API证书一定失效;

删除serving-cert和k3s-serving;

删除文件dynamic-cert.json;

重启k3s;

重启rancher-server;

通过curl重签加入server-url Host;

纯k3sK3s API证书一定失效;

Kube API证书一定失效;

删除k3s-serving;

删除文件dynamic-cert.json;

重启k3s;

对于Rancher 2.3,虽然也内置了k3s,但是证书管理和Rancher 2.4有些不同,2.3的处理方式较为简单,直接进入容器删除对应目录的证书,重启rancher即可。

$ rm -rf /var/lib/rancher/k3s/server/tls/*.crt

其他备注

一键查看secret证书有效期:

$ kubectl get secret -n kube-system k3s-serving -o jsonpath='{.data.tls\.crt}’ | base64 -d | openssl x509 -noout -text | grep Not

Rancher2.3手动轮换证书:https://mp.weixin.qq.com/s/BFRmMVU4sUo3e-wnKHSP_A

赞(0) 打赏
未经允许不得转载:大咖说Rancher » 单容器 rancher&k3s 证书更新

支付宝扫一扫打赏

img

微信扫一扫打赏

img