因为之前在安装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/