Kubelet 证书如何自动续期

因为之前在安装K8S 节点的时候,使用的是手动签发

1年后Kubernetes 集群日志中出现 certificate has expired or is not yet valid 错误信息时,表明证书过期

我搭建 Kubernetes 集群时,一般只声明用于集群 Master、Etcd等通信的证书 为 10年 或者 更久,但未声明集群 Kubelet 组件证书 ,Kubelet 组件证书 默认有效期为(8760h0m0s)1年

集群运行1年以后就会导致报 certificate has expired or is not yet valid 错误,导致集群 Node不能于集群 Master正常通信

 

Kubernetes 在 1.4 版本(我记着是)推出了 TLS bootstrapping 功能;这个功能主要解决了以下问题:

 

当集群开启了 TLS 认证后,每个节点的 kubelet 组件都要使用由 apiserver 使用的 CA 签发的有效证书才能与 apiserver 通讯;此时如果节点多起来,为每个节点单独签署证书将是一件非常繁琐的事情;

TLS bootstrapping 功能就是让 kubelet 先使用一个预定的低权限用户连接到 apiserver,然后向 apiserver 申请证书,kubelet 的证书由 apiserver 动态签署;在配合 RBAC 授权模型下的工作

解决方法

添加开启证书轮换的配置参数

kubelet 在证书即将到期时会自动发起一个 renew 自己证书的 CSR 请求,同时 controller manager 需要在启动时增加参数

  • 修改 kubelet 组件配置,具体添加下面参数

    --feature-gates=RotateKubeletServerCertificate=true
    --feature-gates=RotateKubeletClientCertificate=true 
    --rotate-certificates #1.8版本以上包含1.8都支持证书更换自动重载,以下版本只能手动重启服务
  • 修改 controller-manager 组件配置,TLS bootstrapping 时的证书实际是由 kube-controller-manager 组件来签署的,也就是说证书有效期是 kube-controller-manager 组件控制的

  • --experimental-cluster-signing-duration=87600h0m0s #参数来设置签署的证书有效时间;默认为 8760h0m0s,将其改为 87600h0m0s 即 10 年后再进行 TLS bootstrapping 签署证书即可
    --feature-gates=RotateKubeletServerCertificate=true

RBAC授权

kubelet 所发起的 CSR 请求是由 controller manager 签署的;如果想要是实现自动签发,就需要让 controller manager 能够在 kubelet 发起证书请求的时候自动帮助其签署证书;

那么 controller manager 不可能对所有的 CSR 证书申请都自动签署,这时候就需要配置 RBAC 规则,保证 controller manager 只对 kubelet 发起的特定 CSR 请求自动批准即可

RBAC 中 ClusterRole 只是描述或者说定义一种集群范围内的能力,这三个 ClusterRole 在 1.7 之前需要自己手动创建,在 1.8 后 apiserver 会自动创建前两个;

# A ClusterRole which instructs the CSR approver to approve a user requesting
# node client credentials.
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: approve-node-client-csr
rules:
- apiGroups: ["certificates.k8s.io"]
  resources: ["certificatesigningrequests/nodeclient"]
  verbs: ["create"]
---
# A ClusterRole which instructs the CSR approver to approve a node renewing its
# own client credentials.
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: approve-node-client-renewal-csr
rules:
- apiGroups: ["certificates.k8s.io"]
  resources: ["certificatesigningrequests/selfnodeclient"]
  verbs: ["create"]
---
# A ClusterRole which instructs the CSR approver to approve a node requesting a
# serving cert matching its client cert.
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1beta1
metadata:
  name: approve-node-server-renewal-csr
rules:
- apiGroups: ["certificates.k8s.io"]
  resources: ["certificatesigningrequests/selfnodeserver"]
  verbs: ["create"]

可以看到前面两个是默认创建的,只需要创建最后一个

kubectl get clusterrole|egrep approve

approve-node-client-csr                                                 365d
approve-node-client-renewal-csr                                   365d
approve-node-server-renewal-csr                                  2m

以上三个 ClusterRole 含义如下

  • approve-node-client-csr: 具有自动批准 nodeclient 类型 CSR 请求的能力
  • approve-node-client-renewal-csr: 具有自动批准 selfnodeclient 类型 CSR 请求的能力
  • approve-node-server-renewal-csr: 具有自动批准 selfnodeserver 类型 CSR 请求的能力

所以,如果想要 kubelet 能够自动签发,那么就应当将适当的 ClusterRole 绑定到 kubelet 自动续期时所所采用的用户或者用户组身上

cat token.csv
f485b42fa3e4b75ae1eeac0ccdecbbc9,kubelet-bootstrap,10001,"system:kubelet-bootstrap"

cat bootstrap.kubeconfig |egrep user
user: kubelet-bootstrap

 

创建自动批准相关 CSR 请求的 ClusterRole

开启证书轮换下的引导过程

  • kubelet 读取 bootstrap.kubeconfig,使用其 CA 与 Token 向 apiserver 发起第一次 CSR 请求(nodeclient)
  • apiserver 根据 RBAC 规则自动批准首次 CSR 请求(approve-node-client-csr),并下发证书(kubelet-client.crt)
  • kubelet 使用刚刚签发的证书(O=system:nodes, CN=system:node:NODE_NAME)与 apiserver 通讯,并发起申请 10250 server 所使用证书的 CSR 请求
  • apiserver 根据 RBAC 规则自动批准 kubelet 为其 10250 端口申请的证书(kubelet-server-current.crt)
  • 证书即将到期时,kubelet 自动向 apiserver 发起用于与 apiserver 通讯所用证书的 renew CSR 请求和 renew 本身 10250 端口所用证书的 CSR 请求
  • apiserver 根据 RBAC 规则自动批准两个证书
  • kubelet 拿到新证书后关闭所有连接,reload 新证书,以后便一直如此

从以上流程我们可以看出,实现证书轮换创建 的RBAC 规则,则至少能满足四种情况:

  • 自动批准 kubelet 首次用于与 apiserver 通讯证书的 CSR 请求(nodeclient)
  • 自动批准 kubelet 首次用于 10250 端口鉴权的 CSR 请求(实际上这个请求走的也是 selfnodeserver 类型 CSR)
  • 自动批准 kubelet 后续 renew 用于与 apiserver 通讯证书的 CSR 请求(selfnodeclient)
  • 自动批准 kubelet 后续 renew 用于 10250 端口鉴权的 CSR 请求(selfnodeserver)

基于以上四种情况ClusterRoleBinding最终的RBAC 规则如下:

#自动批准 kubelet-bootstrap 用户 TLS bootstrapping 首次申请证书的 CSR 请求
kubectl create clusterrolebinding node-client-auto-approve-csr --clusterrole=system:certificates.k8s.io:certificatesigningrequests:nodeclient --user=kubelet-bootstrap
#自动批准 system:nodes 组用户更新 kubelet 自身与 apiserver 通讯证书的 CSR 请求
kubectl create clusterrolebinding node-client-auto-renew-crt --clusterrole=system:certificates.k8s.io:certificatesigningrequests:selfnodeclient --group=system:nodes
#自动批准 system:nodes 组用户更新 kubelet 10250 api 端口证书的 CSR 请求
kubectl create clusterrolebinding node-server-auto-renew-crt --clusterrole=system:certificates.k8s.io:certificatesigningrequests:selfnodeserver --group=system:nodes

kubectl get clusterrolebinding|egrep "node-(.*)-auto"
node-client-auto-approve-csr                            3h31m
node-client-auto-renew-crt                                3h30m
node-server-auto-renew-crt                              3h29m

重启kube-controller-manager 和 kubelet 服务

systemctl daemon-reload
systemctl restart kube-controller-manager.service
# 进入到ssl配置目录,删除 kubelet 证书
rm -f kubelet-client-current.pem kubelet-client-*.pem kubelet.key kubelet.crt
重启启动,启动正常后会颁发有效期10年的ssl证书
systemctl restart kubelet
进入到ssl配置目录,查看证书有效期
openssl x509 -in kubelet-client-current.pem -noout -text | grep "Not"
Not Before: Jun 20 05:51:00 2020 GMT
Not After : Jun 17 07:44:29 2029 GMT

kubectl get nodes
NAME                   STATUS           ROLES                 AGE                VERSION
k8s-node1              Ready            <none>                 365d                   v1.14.3

TLS bootstrapping 总结以及详细操作

kubelet 首次启动通过加载 bootstrap.kubeconfig 中的用户 Token 和 apiserver CA 证书发起首次 CSR 请求,这个 Token 被预先内置在 apiserver 节点的 token.csv 中,其身份为 kubelet-bootstrap 用户和 system:bootstrappers 用户组;

想要首次 CSR 请求能成功(成功指的是不会被 apiserver 401 拒绝),则需要先将 kubelet-bootstrap 用户和 system:node-bootstrapper 内置 ClusterRole 绑定;

对于首次 CSR 请求可以手动批准,也可以将 system:bootstrappers 用户组与 approve-node-client-csr ClusterRole 绑定实现自动批准(1.8 之前这个 ClusterRole 需要手动创建,1.8 后 apiserver 自动创建,并更名为 system:certificates.k8s.io:certificatesigningrequests:nodeclient)

默认签署的的证书只有 1 年有效期,如果想要调整证书有效期可以通过设置 kube-controller-manager 的 --experimental-cluster-signing-duration 参数实现,该参数默认值为 8760h0m0s

对于证书自动续签,需要通过协调两个方面实现

第一,想要 kubelet 在证书到期后自动发起续期请求,则需要在 kubelet 启动时增加 --feature-gates=RotateKubeletClientCertificate=true,RotateKubeletServerCertificate=true 来实现;

第二,想要让 controller manager 自动批准续签的 CSR 请求需要在 controller manager 启动时增加 --feature-gates=RotateKubeletServerCertificate=true 参数,并绑定对应的 RBAC 规则;

同时需要注意的是 1.7 版本的 kubelet 自动续签后需要手动重启 kubelet 以使其重新加载新证书,

而 1.8 后只需要在 kublet 启动时附带 --rotate-certificates 选项就会自动重新加载新证书

 

 参考文章:

https://mritd.me/2018/01/07/kubernetes-tls-bootstrapping-note/

https://www.cnblogs.com/lvcisco/p/11912637.html

posted @ 2020-06-20 14:14  屌丝的IT  阅读(3435)  评论(0编辑  收藏  举报