证书是 K8S 集群内部通讯的必备配置。K8S 大规模使用到现在也有接近10年时间了,很多搭建的比较早的集群,CA 基本都快过期了,这里记录一下更换 CA 的步骤和注意事项。

先给一下官方文档:https://kubernetes.io/zh-cn/docs/tasks/tls/manual-rotation-of-ca-certificates/

先了解一下证书的分类和用处

一个完整的 K8S 集群,总共需要2个 CA 证书。一个是 K8S 相关组件使用的,另一个是 ETCD 组件使用的。这2个CA 证书,会签发出其他客户端证书。

CA 一般是10年-20年有效期;客户端证书一般是1年有效期,并且可以自动重新签发。

集群的通讯关系如下

  1. ETCD 默认只和 kube-apiserver 通信。如果有监控或者使用 Cilium 等组件,会产生额外的访问,需要一起更新掉相关证书。

    • etcd <-> kube-apiserver
    • etcd <-> Prometheus, Cilium
  2. 其他组件默认只和 kube-apiserver 通信。

    • kube-apiserver <-> kube-controller-manager
    • kube-apiserver <-> kube-scheduler
    • kube-apiserver <-> kube-proxy
    • kube-apiserver <-> kubelet
    • kube-apiserver <-> kubectl

因为这些通讯一般都是双向验证,所以想成功通讯,必须满足2个条件

  1. 信任 CA
  2. 持有 CA 签发的有效证书

基于以上条件,更新 CA 的步骤就是

  1. 创建新的 CA
  2. 同时信任新旧 CA (下面都叫 bundle CA )
  3. 使用新 CA 签发的证书
  4. 删除旧 CA (部分地方可以跳过)

详细的步骤如下

以下步骤适用于不停机更新的情况,所以较为复杂。如果可以停机,则直接暴力替换(先停止所有服务,再把对应的证书替换到正确的目录下,然后重启服务)即可。

一、准备工作

  1. 创建新的 CA
  2. 使用新的 CA 签发需要的全部证书
  3. 把旧的 CA 追加到新 CA 里面

二、更新 ETCD CA 和 证书

  1. 先备份 ETCD 数据

    # 查看 ETCD 状态
    alias et='etcdctl --endpoints=192.168.10.101:2379,192.168.10.102.2379,192.168.10.103.2379 --cacert=/etc/etcd/ssl/ca-etcd.pem --cert=/etc/etcd/ssl/cert-etcd.pem --key=/etc/etcd/ssl/cert-etcd-key.pem'

    et endpoint status -w table

    # 备份 ETCD DB
    et1 snapshot save etcd-backup-$(date +%Y%m%d).db
    # 检查备份文件
    et1 snapshot status etcd-backup-$(date +%Y%m%d).db --write-out=table
  2. 更新 ETCD 使用 CA bundle 证书

    # 1. 先更新 ETCD 使用 CA bundle 证书,然后重启 ETCD 节点。【在每个 ETCD 节点上执行】

    --trusted-ca-file "/etc/ssl/certs/ca-etcd-bundle.pem" \
    --peer-trusted-ca-file "/etc/ssl/certs/ca-etcd-bundle.pem" \

    # 上一步做完之后,每个 ETCD 节点都同时信任新旧 CA 证书。
    # 下面可以更新客户端证书了。
    # 2. 使用新 CA 签发的客户端证书 `cert-etcd.pem` 和 `cert-etcd-key.pem`,然后重启 ETCD 节点生效。
    --client-cert-auth \
    --trusted-ca-file "/etc/ssl/certs/ca-etcd-bundle.pem" \ # 上一步的修改
    --cert-file "/etc/ssl/certs/cert-etcd.pem" \ # 新签发的证书
    --key-file "/etc/ssl/certs/cert-etcd-key.pem" \ # 新签发的证书
    --peer-client-cert-auth \
    --peer-trusted-ca-file "/etc/ssl/certs/ca-etcd-bundle.pem" \ # 上一步的修改
    --peer-cert-file "/etc/ssl/certs/cert-etcd.pem" \ # 新签发的证书
    --peer-key-file "/etc/ssl/certs/cert-etcd-key.pem" \ # 新签发的证书
  3. 到这里 ETCD 之间已经使用新的 CA 进行通讯了。但是 kube-apiserver 还是使用旧的 CA 证书和 ETCD 通讯。

三、更新 K8S 组件使用 CA bundle 证书

  1. 更新 kube-controller-manager

    # 确认 Controller Manager 的主节点
    kubectl get lease -n kube-system

    # ssh 到非主控节点,更新 kube-controller-manager.yaml 使用新 CA 证书
    vim /etc/kubernetes/manifests/kube-controller-manager.yaml
    - --cluster-signing-cert-file=/etc/kubernetes/ssl/new-ca/ca-kubernetes.pem # 保证使用的是新的 CA ,这里不能使用 Bundle CA
    - --cluster-signing-key-file=/etc/kubernetes/ssl/new-ca/ca-kubernetes-key.pem # 保证使用的是新的 CA key
    - --root-ca-file=/etc/kubernetes/ssl/new-ca/ca-kubernetes-bundle.pem # 老的和新的 bundle CA

    # 使用 docker stop 来重启 Controller-Manager 容器。
    # 在每一个节点上执行。且保证主节点是最后一个做。

    # 检查 Default 命名空间里的 ServiceAccount 证书,查看是否自动更新成 Bundle CA 证书。
    # 重启所有使用了 Service Account 的集群内服务:比如 coredns, kubeproxy 等。
  2. 更新 kube-apiserver 使用 Bundle CA 证书

    # 更新 kube-apiserver.yaml 使用 Bundle CA 证书
    vim /etc/kubernetes/manifests/kube-apiserver.yaml
    - --client-ca-file=/etc/kubernetes/ssl/new-ca/ca-kubernetes-bundle.pem

    # 使用 docker stop 来重启 API Server
    # 在每一个节点上执行并重启服务。
  3. 更新 kube-controller-manager 的 client-ca-file 使用新 CA 证书

    # 这个证书是用于和 API Server 通信的,所以需要上一步完成之后,才做这一步。
    vim /etc/kubernetes/manifests/kube-controller-manager.yaml
    - --client-ca-file=/etc/kubernetes/ssl/new-ca/ca-kubernetes.pem # 保证使用的是新的 CA 证书。这里只能使用单CA证书,不能使用 Bundle CA !!!

    # 在每一个节点上执行并重启服务。
  4. 更新 kube-scheduler.yaml 使用 Bundle CA 证书

    vim /etc/kubernetes/scheduler.conf
    certificate-authority: /etc/kubernetes/ssl/new-ca/ca-kubernetes-bundle.pem

    # 在每一个节点上执行并重启服务。
  5. 更新 kubelet 节点使用 Bundle 证书

    vim /etc/kubernetes/kubelet.conf
    certificate-authority: /etc/kubernetes/ssl/new-ca/ca-kubernetes-bundle.pem

    # 在每一个节点上执行并重启服务。

四、更新控制节点使用新 CA 签发的客户端证书

更新到这里如果没有错误,后面就可以正常更新节点证书了。

期间 API Server 会出现少量 非法的 beader token 错误,可以忽略。全部的控制节点更新完成之后,这个错误就会消失。

五、最后更新其他地方使用到的客户端证书

  • 比如 Prometheus 监控 ETCD 或者 Kubelet 的情况会用到的证书。
  • 还有 kubeconfig 文件里的 CA 和 Client 证书等等。Kubeconfig 的里的 CA 可以写多个,但是好像默认使用第一个。

写在最后

如果中间某一步出现了问题,怎么办?

答:肯定是证书文件没放对! 一个一个检查证书文件。

如果实在没有检查出来哪里有问题,怎么办?

答:直接停止全部的服务,然后把正确的证书文件复制到对应目录,然后启动服务。直接暴力全部替换。