# 从 Metric Server 到 Kubelet 服务证书

很少用 Kubeadm，一直用自有 CA 签发证书，所以 TLS Bootstrap 也极少接触，然后乐子就来了。

```bash
$ 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` 查看日志，其中大量的：

```bash
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：

```shell
$ 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 中有一行注释：

```go
// 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：

```shell
$ 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 字段做解码，并查看其请求内容的话，会发现：

```shell
$ openssl req -in csr.pem -noout -text
...
X509v3 Subject Alternative Name:
                DNS:node-standard-2, IP Address:10.211.55.28
...
```

证书请求中已经带有了 SAN 记录。

```shell
$ kubectl certificate approve csr-n9pvr
certificatesigningrequest.certificates.k8s.io/csr-n9pvr approved
```

通过之后，Kubelet 就有了使用 API Server 的 CA 签发的证书了。

稍等片刻，再次执行 `kubectl top nodes`：

```shell
$ 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%
```
