从 Metric Server 到 Kubelet 服务证书
很少用 Kubeadm,一直用自有 CA 签发证书,所以 TLS Bootstrap 也极少接触,然后乐子就来了。
$ git clone https://github.com/kubernetes-incubator/metrics-server.git
$ cd metrics-server/deploy/1.8+
$ kubectl apply -f .
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
...
使用 kubectl top nodes
,返回的永远都是 error: metrics not available yet
。kubectl logs metrics-server-fc6d4999b-58xtc
查看日志,其中大量的:
unable to fetch metrics from Kubelet node-standard-3 (node-standard-3): Get https://node-standard-3:10250/stats/summary/: x509: certificate signed by unknown authority]
检查一下,很明显,kubelet 提供的 https 服务使用了未经认可的 CA:
$ openssl s_client -showcerts -connect node-standard-3:10250
...
Verify return code: 19 (self signed certificate in certificate chain)
...
Metric Server 支持一个参数 --kubelet-insecure-tls
,可以跳过这一检查,然而官方也明确说了,这种方式不推荐生产使用。
这时候我又想到个问题,那 API Server 是怎么访问 Kubelet 的?最后我看到,API Server 中有一行注释:
// Proxying to pods and services is IP-based... don't expect to be able to verify the hostname
proxyTLSClientConfig := &tls.Config{InsecureSkipVerify: true}
那么问题来了,如何让 Kubelet 具备一个“正式”的证书,让各种组件可以放心的使用 TLS 进行访问呢?查阅资料发现,目前的 kubeadm 流程中,kubelet 的 Bootstrap 因为节点动态的原因,已经不再自动完成 Kubelet 服务端点的证书签发了,使用统一 CA 自行签署,或者恢复 Bootstrap 中的服务证书申请流程,也就能完成任务了。
Kubelet 的 config.yaml
中加入一行:serverTLSBootstrap: true
,即可启动这一过程。重启 Kubelet,会发现出现了新的 CSR:
$ kubectl get csr
NAME AGE REQUESTOR CONDITION
csr-f29hk 5s system:node:node-standard-2 Pending
csr-n9pvr 3m31s system:node:node-standard-3 Pending
如果使用 base64 -d
对 csr 的 request 字段做解码,并查看其请求内容的话,会发现:
$ openssl req -in csr.pem -noout -text
...
X509v3 Subject Alternative Name:
DNS:node-standard-2, IP Address:10.211.55.28
...
证书请求中已经带有了 SAN 记录。
$ kubectl certificate approve csr-n9pvr
certificatesigningrequest.certificates.k8s.io/csr-n9pvr approved
通过之后,Kubelet 就有了使用 API Server 的 CA 签发的证书了。
稍等片刻,再次执行 kubectl top nodes
:
$ kubectl top nodes
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
node-standard-1 213m 10% 1220Mi 70%
node-standard-2 71m 3% 361Mi 20%
node-standard-3 61m 3% 355Mi 20%