文章目录
- 参考
- 前置知识 数字证书原理
- 梳理
- k8s组件的认证方式
- 原理
- k8s使用的主要证书
- 各个证书说明
- k8s中的证书配置
- etcd证书配置
- kube-apiserver 证书配置
- 采用 kubeconfig 访问 kube-apiserver
- Service Account 证书
- 过程
- 认证方法:客户端证书还是 token ?
- 使用 TLS bootstrapping 简化 Kubelet 证书制作
数字证书原理
数字签名是什么?
一文带你彻底厘清 Kubernetes 中的证书工作机制
前置知识 数字证书原理
梳理
k8s组件的认证方式
原理
- 数字证书的验证是在协议层面通过TLS完成的,应用层不需要特殊处理,有两种方式
- 单向TLS验证:客户端验证服务端的证书,只需要验证服务端身份
- 双向TLS验证:客户端和服务端双向验证,双方互相验证
- k8s各个组件的接口都包含了集群的内部信息,因此采用双向验证,会涉及到的相关文件
- 服务器端证书:包含服务器端公钥和服务端身份信息
- 服务器端私钥
- 客户端证书:包含客户端公钥和客户端身份信息
- 客户端私钥
- 服务器端CA根证书:验证服务器端证书的合法性
- 客户端CA根证书:验证客户端证书的合法性
k8s使用的主要证书
- 上图仅标明,证书使用方的证书
各个证书说明
序号 | 证书作用 | 类型 |
1 | etcd节点间通讯的证书 | 服务器和客户端证书(因节点间互相访问) |
2 | etcd向外提供服务使用 | 服务器证书(因被访问) |
3 | apiserver访问etcd使用 | 客户端证书 |
4 | apiserver对外提供服务使用 | 服务器证书 |
5 | kube-controller-manager访问apiserver使用 | 客户端证书 |
6 | kube-scheduler访问 apiserver使用 | 客户端证书 |
7 | kube-proxy访问apiserver使用 | 客户端证书 |
8 | kubelet访问apiserver使用 | 客户端证书 |
9 | kubectl访问apiserver使用 | 客户端证书 |
10 | kubelet对外提供服务使用 | 服务器证书 |
11 | apiserver访问kubelet使用 | 客户端证书 |
12 | kube-controller-manager生成和验证service-accout token的证书 | 并不需要证书,实际上使用的是公钥和私钥 k8s为server accout 生成JWT token, secret将此token加载到pod上 公钥分配到apiserver上用于验证 私钥分配到pod上用于数字签名 |
- etcd 集群中各个节点之间相互通信使用的证书。由于一个 etcd 节点既为其他节点提供服务,又需要作为客户端访问其他节点,因此该证书同时用作服务器证书和客户端证书。
- etcd 集群向外提供服务使用的证书。该证书是服务器证书。
- kube-apiserver 作为客户端访问 etcd 使用的证书。该证书是客户端证书。
- kube-apiserver 对外提供服务使用的证书。该证书是服务器证书。
- kube-controller-manager 作为客户端访问 kube-apiserver 使用的证书,该证书是客户端证书。
- kube-scheduler 作为客户端访问 kube-apiserver 使用的证书,该证书是客户端证书。
- kube-proxy 作为客户端访问 kube-apiserver 使用的证书,该证书是客户端证书。
- kubelet 作为客户端访问 kube-apiserver 使用的证书,该证书是客户端证书。
- 管理员用户通过 kubectl 访问 kube-apiserver 使用的证书,该证书是客户端证书。
- kubelet 对外提供服务使用的证书。该证书是服务器证书。
- kube-apiserver 作为客户端访问 kubelet 采用的证书。该证书是客户端证书。
- kube-controller-manager 用于生成和验证 service-account token 的证书。该证书并不会像其他证书一样用于身份认证,而是将证书中的公钥/私钥对用于 service account token 的生成和验证。kube-controller-manager 会用该证书的私钥来生成 service account token,然后以 secret 的方式加载到 pod 中。pod 中的应用可以使用该 token 来访问 kube-apiserver, kube-apiserver 会使用该证书中的公钥来验证请求中的 token。我们将在文中稍后部分详细介绍该证书的使用方法。
k8s中的证书配置
其实主要就分为几类
- 服务器证书(就是身份信息+公钥)
- 服务器证书的私钥
- 验证证书的CA根证书
etcd证书配置
- etcd 对外提供服务的服务器证书及私钥。 被访
- etcd 节点之间相互进行认证的 peer 证书、私钥以及验证 peer 的 CA。 访问,被访,及验证
- etcd 验证访问其服务的客户端的 CA。 验证
/usr/local/bin/etcd \\
--cert-file=/etc/etcd/kube-etcd.pem \\ # 对外提供服务的服务器证书
--key-file=/etc/etcd/kube-etcd-key.pem \\ # 服务器证书对应的私钥
--peer-cert-file=/etc/etcd/kube-etcd-peer.pem \\ # peer 证书,用于 etcd 节点之间的相互访问
--peer-key-file=/etc/etcd/kube-etcd-peer-key.pem \\ # peer 证书对应的私钥
--trusted-ca-file=/etc/etcd/cluster-root-ca.pem \\ # 用于验证访问 etcd 服务器的客户端证书的 CA 根证书
--peer-trusted-ca-file=/etc/etcd/cluster-root-ca.pem\\ # 用于验证 peer 证书的 CA 根证书
...
kube-apiserver 证书配置
- kube-apiserver 对外提供服务的服务器证书及私钥。 被访
- kube-apiserver 访问 etcd 所需的客户端证书及私钥。 访问
- kube-apiserver 访问 kubelet 所需的客户端证书及私钥。 访问
- 验证访问其服务的客户端的 CA。 验证
- 验证 etcd 服务器证书的 CA 根证书。验证
- 验证 service account token 的公钥。验证
/usr/local/bin/kube-apiserver \\
--tls-cert-file=/var/lib/kubernetes/kube-apiserver.pem \\ # 用于对外提供服务的服务器证书
--tls-private-key-file=/var/lib/kubernetes/kube-apiserver-key.pem \\ # 服务器证书对应的私钥
--etcd-certfile=/var/lib/kubernetes/kube-apiserver-etcd-client.pem \\ # 用于访问 etcd 的客户端证书
--etcd-keyfile=/var/lib/kubernetes/kube-apiserver-etcd-client-key.pem \\ # 用于访问 etcd 的客户端证书的私钥
--kubelet-client-certificate=/var/lib/kubernetes/kube-apiserver-kubelet-client.pem \\ # 用于访问 kubelet 的客户端证书
--kubelet-client-key=/var/lib/kubernetes/kube-apiserver-kubelet-client-key.pem \\ # 用于访问 kubelet 的客户端证书的私钥
--client-ca-file=/var/lib/kubernetes/cluster-root-ca.pem \\ # 用于验证访问 kube-apiserver 的客户端的证书的 CA 根证书
--etcd-cafile=/var/lib/kubernetes/cluster-root-ca.pem \\ # 用于验证 etcd 服务器证书的 CA 根证书
--kubelet-certificate-authority=/var/lib/kubernetes/cluster-root-ca.pem \\ # 用于验证 kubelet 服务器证书的 CA 根证书
--service-account-key-file=/var/lib/kubernetes/service-account.pem \\ # 用于验证 service account token 的公钥
...
采用 kubeconfig 访问 kube-apiserver
- Kubernetes 中的各个组件,包括kube-controller-mananger、kube-scheduler、kube-proxy、kubelet等,采用一个kubeconfig 文件中配置的信息来访问 kube-apiserver。
- 该文件中包含了 kube-apiserver 的地址,验证 kube-apiserver 服务器证书的 CA 证书,自己的客户端证书和私钥等访问信息
- 在启动这些组件时,需要在参数中指出 kubeconfig 文件的路径,例如 kube-controller-manager 的启动命令如下:
/usr/local/bin/kube-controller-manager \\
--kubeconfig=/etc/kubernetes/controller-manager.conf
# 下面几个证书和访问 kube-apiserver 无关,我们会在后面介绍到
--cluster-signing-cert-file=/var/lib/kubernetes/cluster-root-ca.pem # 用于签发证书的 CA 根证书
--cluster-signing-key-file=/var/lib/kubernetes/cluster-root-ca-key.pem # 用于签发证书的 CA 根证书的私钥
--service-account-private-key-file=/var/lib/kubernetes/service-account-key.pem # 用于对 service account token 进行签名的私钥
...
Service Account 证书
- Kubernetes 中有两类用户,一类为 user account,一类为 service account。
- service account 主要被 pod 用于访问 kube-apiserver。 在为一个 pod 指定了 service account 后,kubernetes 会为该 service account 生成一个 JWT token,并使用 secret 将该 service account token 加载到 pod 上。pod 中的应用可以使用 service account token 来访问 api server。
- service account 证书被用于生成和验证 service account token。该证书的用法和前面介绍的其他证书不同,因为实际上使用的是其公钥和私钥,而并不需要对证书进行验证。
- 可以看到 service account 证书的公钥和私钥分别被配置到了 kube-apiserver 和 kube-controller-manager 的命令行参数中,如下所示:
/usr/local/bin/kube-apiserver \\
--service-account-key-file=/var/lib/kubernetes/service-account.pem \\ # 用于验证 service account token 的公钥
...
/usr/local/bin/kube-controller-manager \\
--service-account-private-key-file=/var/lib/kubernetes/service-account-key.pem # 用于对 service account token 进行签名的私钥
...
过程
下图展示了 kubernetes 中生成、使用和验证 service account token 的过程。
认证方法:客户端证书还是 token ?
- k8s组件间用证书,集群内用service account,Istio会自动为每个service account 生成一个证书
- 可以看到,Kubernetes 提供了两种客户端认证的方法,控制面组件采用的是客户端数字证书;而在集群中部署的应用则采用了 service account token 的方式。
- 为什么 Kubernetes 不为 service account 也生成一个证书,并采用该证书进行身份认证呢?
- 实际上 Istio 就是这样做的,Istio 会自动为每个 service account 生成一个证书,并使用该证书来在 pod 中的应用之间建立双向 tls 认证。
- 我没有找到 Kubernetes 这个设计决策的相关说明,如果你知道原因或对此有自己的见解,欢迎联系我进行探讨。
##认证方法:客户端证书还是 token ?
- Kubernetes 提供了一个
certificates.k8s.io
API,可以使用配置的 CA 根证书来签发用户证书。 - 该 API 由 kube-controller-manager 实现,其签发证书使用的根证书在下面的命令行中进行配置。
- 我们希望 Kubernetes 采用集群根 CA 来签发用户证书,因此在 kube-controller-manager 的命令行参数中将相关参数配置为了集群根 CA。
/usr/local/bin/kube-controller-manager \\
--cluster-signing-cert-file=/var/lib/kubernetes/cluster-root-ca.pem # 用于签发证书的 CA 根证书
--cluster-signing-key-file=/var/lib/kubernetes/cluster-root-ca-key.pem # 用于签发证书的 CA 根证书的私钥
...
使用 TLS bootstrapping 简化 Kubelet 证书制作
- 在安装 Kubernetes 时,我们需要为每一个工作节点上的 Kubelet 分别生成一个证书。
- 由于工作节点可能很多,手动生成 Kubelet 证书的过程会比较繁琐。
- 为了解决这个问题,Kubernetes 提供了 TLS bootstrapping 的方式来简化 Kubelet 证书的生成过程。
- 其原理是预先提供一个 bootstrapping token,kubelet 通过该 kubelet 调用 kube-apiserver 的证书签发 API 来生成 自己需要的证书。
- 要启用该功能,需要在 kube-apiserver 中启用 --enable-bootstrap-token-auth ,并创建一个 kubelet 访问 kube-apiserver 使用的 bootstrap token secret。如果使用 kubeadmin 安装,可以使用 kubeadm token create命令来创建 token。
- 采用TLS bootstrapping 生成证书的流程如下:
- 调用 kube-apiserver 生成一个 bootstrap token。
- 将该 bootstrap token 写入到一个 kubeconfig 文件中,作为 kubelet 调用 kube-apiserver 的客户端验证方式。
- 通过
--bootstrap-kubeconfig
启动参数将 bootstrap token 传递给 kubelet 进程。 - Kubelet 采用bootstrap token 调用 kube-apiserver API,生成自己所需的服务器和客户端证书。
- 证书生成后,Kubelet 采用生成的证书和 kube-apiserver 进行通信,并删除本地的 kubeconfig 文件,以避免 bootstrap token 泄漏风险。