目录

K3s 百年证书

文章简介:K3s 自带的 CA 有效期 10 年,其签发的 mTLS 证书只有 1 年,远不能满足“一次部署、长期免运维”的生产诉求。本文给出零侵入式方案,让 K3s 一次性使用 100 年有效期的 CA 与终端实体证书,真正做到“证书一生只装一次”。

背景

k3s 默认生成的证书 10 年 CA 证书以及 1 年的客户端证书如果证书的有效期少于 90 天,k3s server 在重启的时候会续签证书。这就意味着我们需要定期每周或者每月重启 k3s。但是有一个致命问题 ca 证书不会续签,且只有 10 年有效期,当前我们在使用的版本 1.21.* 版本是没有 rotate-ca 的,也就意味着 10 年到期后集群就不可用了。 issue: How to configure my own CA for k3s Certificate and access management for edge computing ,自定义 CA 证书的问题在 此 MR 中解决了,我们可以通过使用contrib/util/generate-custom-ca-certs.sh 修改一下 openssl 自签 100 年证书。同时 此 MR 添加了 rotate-ca 命令,用于 ca 证书过期后更换 ca 证书。实际使用过程中发现 rotate-ca 命令貌似不可用。后使用 restore etcd snapshot 后重新自签一套新证书后启动 k3s 解决。当前版本可以直接生成 rotate-ca 证书,直接 rotate-ca 即可。旧环境可以直接升级到 1.27.x 后使用 rotate-ca 即可。

整体思路

  1. 提前生成超长寿命 CA(100 年)
  2. K3s 启动时生成 CATTLE_NEW_SIGNED_CERT_EXPIRATION_DAYS 有效期的 server/client cert
  3. 同步调整 Kubernetes 控制平面 CSR 有效期(100 年)

步骤 1:生成 100 年 CA 及中间证书

k3s 使用 certutil.NewSelfSignedCACert 签发 CA 证书,有效期是写死的 10 年,这个值不是很生产可用。社区也遇到了这个问题,其中 CA 部分采用的解决办法是自签名一个自定义证书,脚本默认 20 年证书,这里我们改成 100 年:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
--- "ansible/files/generate-custom-ca-certs copy.sh" 2024-08-06 17:43:32.663442036 +0800
+++ ansible/files/generate-custom-ca-certs.sh 2024-08-06 17:53:07.285515777 +0800
@@ -30,6 +30,11 @@
 PRODUCT="${PRODUCT:-k3s}"
 DATA_DIR="${DATA_DIR:-/var/lib/rancher/${PRODUCT}}"
 
+if [[ -d "${DATA_DIR}/server/tls" ]]; then
+    echo "SKIPING: ${DATA_DIR}/server/tls is exists"
+    exit 0
+fi
+
 if type -t openssl-3 &>/dev/null; then
   OPENSSL=openssl-3
 else
@@ -93,7 +98,7 @@
 else
   echo "Generating root certificate authority RSA key and certificate"
   ${OPENSSL} genrsa ${OPENSSL_GENRSA_FLAGS:-} -out root-ca.key 4096
-  ${OPENSSL} req -x509 -new -nodes -sha256 -days 7300 \
+  ${OPENSSL} req -x509 -new -nodes -sha256 -days 37000 \
                  -subj "/CN=${PRODUCT}-root-ca@${TIMESTAMP}" \
                  -key root-ca.key \
                  -out root-ca.pem \
@@ -116,7 +121,7 @@
   ${OPENSSL} req -new -nodes \
                  -subj "/CN=${PRODUCT}-intermediate-ca@${TIMESTAMP}" \
                  -key intermediate-ca.key |
-  ${OPENSSL} ca  -batch -notext -days 3700 \
+  ${OPENSSL} ca  -batch -notext -days 37000 \
                  -in /dev/stdin \
                  -out intermediate-ca.pem \
                  -keyfile root-ca.key \
@@ -139,7 +144,7 @@
   ${OPENSSL} req -new -nodes \
                  -subj "/CN=${CERT_NAME}@${TIMESTAMP}" \
                  -key ${TYPE}-ca.key |
-  ${OPENSSL} ca  -batch -notext -days 3700 \
+  ${OPENSSL} ca  -batch -notext -days 37000 \
                  -in /dev/stdin \
                  -out ${TYPE}-ca.pem \
                  -keyfile intermediate-ca.key \

修改后执行即可:

1
bash k3s-generate-custom-ca-certs.sh

步骤 2:调整 K3s Server / Client 证书有效期

k3s 创建 tls 证书其 server 证书有效期是 365 天,可以通过环境变量 CATTLE_NEW_SIGNED_CERT_EXPIRATION_DAYS 修改为希望的值,单位天:

1
echo 'CATTLE_NEW_SIGNED_CERT_EXPIRATION_DAYS=36500' >> /etc/systemd/system/k3s.service.env

步骤 3:让 Kubernetes CSR 也一次签 100 年

Kubernetes 控制平面自带的 kube-controller-manager 默认对 CSR 签发 1 年,可以覆盖这个配置 /etc/rancher/k3s/config.yaml:

1
2
kube-controller-manager-arg:
  - cluster-signing-duration=876000h # 100year

最终验证

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 查看 CA 有效期
for i in `ls /var/lib/rancher/k3s/server/tls/*.crt`; do echo $i; openssl x509 -enddate -noout -in $i; done

/var/lib/rancher/k3s/server/tls/client-admin.crt
notAfter=Jun 14 03:39:24 2125 GMT
/var/lib/rancher/k3s/server/tls/client-auth-proxy.crt
notAfter=Jun 14 03:39:24 2125 GMT
/var/lib/rancher/k3s/server/tls/client-ca.crt
notAfter=Oct 27 03:37:22 2126 GMT
/var/lib/rancher/k3s/server/tls/client-ca.nochain.crt
notAfter=Oct 27 03:37:22 2126 GMT
/var/lib/rancher/k3s/server/tls/client-controller.crt
notAfter=Jun 14 03:39:24 2125 GMT
/var/lib/rancher/k3s/server/tls/client-k3s-cloud-controller.crt
notAfter=Jun 14 03:39:24 2125 GMT
/var/lib/rancher/k3s/server/tls/client-k3s-controller.crt
notAfter=Jun 14 03:39:24 2125 GMT
/var/lib/rancher/k3s/server/tls/client-kube-apiserver.crt
notAfter=Jun 14 03:39:24 2125 GMT
/var/lib/rancher/k3s/server/tls/client-kube-proxy.crt
notAfter=Jun 14 03:39:24 2125 GMT
/var/lib/rancher/k3s/server/tls/client-scheduler.crt
notAfter=Jun 14 03:39:24 2125 GMT
/var/lib/rancher/k3s/server/tls/client-supervisor.crt
notAfter=Jun 14 03:39:24 2125 GMT
/var/lib/rancher/k3s/server/tls/intermediate-ca.crt
notAfter=Oct 27 03:37:22 2126 GMT
/var/lib/rancher/k3s/server/tls/request-header-ca.crt
notAfter=Oct 27 03:37:23 2126 GMT
/var/lib/rancher/k3s/server/tls/root-ca.crt
notAfter=Oct 27 03:37:22 2126 GMT
/var/lib/rancher/k3s/server/tls/server-ca.crt
notAfter=Oct 27 03:37:22 2126 GMT
/var/lib/rancher/k3s/server/tls/server-ca.nochain.crt
notAfter=Oct 27 03:37:22 2126 GMT
/var/lib/rancher/k3s/server/tls/serving-kube-apiserver.crt
notAfter=Jun 14 03:39:24 2125 GMT

# 查看 server 证书有效期
openssl x509 -in /var/lib/rancher/k3s/server/tls/serving-kube-apiserver.crt -noout -dates
notBefore=Jul  8 03:37:22 2025 GMT
notAfter=Jun 14 03:39:24 2125 GMT

# 查看 kubelet client 证书有效期
openssl x509 -in /var/lib/rancher/k3s/agent/client-kubelet.crt -noout -dates
notBefore=Jul  8 03:37:22 2025 GMT
notAfter=Jun 14 17:00:14 2125 GMT

结语

  • CA 100 年(脚本一次性生成,K3s 直接复用)
  • Server / Client 证书 100 年(环境变量控制)
  • Kubernetes CSR 100 年(controller-manager 参数控制)

至此,一次部署,证书终身免运维的 K3s 集群正式就绪。