文章目录

  • 参考
  • 前置知识 数字证书原理
  • 梳理
  • k8s组件的认证方式
  • 原理
  • k8s使用的主要证书
  • 各个证书说明
  • k8s中的证书配置
  • etcd证书配置
  • kube-apiserver 证书配置
  • 采用 kubeconfig 访问 kube-apiserver
  • Service Account 证书
  • 过程
  • 认证方法:客户端证书还是 token ?
  • 使用 TLS bootstrapping 简化 Kubelet 证书制作


参考

数字证书原理

数字签名是什么?

一文带你彻底厘清 Kubernetes 中的证书工作机制

前置知识 数字证书原

梳理

k8s组件的认证方式

k8s deployment ssl 证书 k8s证书认证_kubernetes

原理

  • 数字证书的验证是在协议层面通过TLS完成的,应用层不需要特殊处理,有两种方式
  • 单向TLS验证:客户端验证服务端的证书,只需要验证服务端身份
  • 双向TLS验证:客户端和服务端双向验证,双方互相验证
  • k8s各个组件的接口都包含了集群的内部信息,因此采用双向验证,会涉及到的相关文件
  • 服务器端证书:包含服务器端公钥和服务端身份信息
  • 服务器端私钥
  • 客户端证书:包含客户端公钥和客户端身份信息
  • 客户端私钥
  • 服务器端CA根证书:验证服务器端证书的合法性
  • 客户端CA根证书:验证客户端证书的合法性

k8s使用的主要证书

k8s deployment ssl 证书 k8s证书认证_ca证书_02

  • 上图仅标明,证书使用方的证书

各个证书说明

序号

证书作用

类型

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上用于数字签名

  1. etcd 集群中各个节点之间相互通信使用的证书。由于一个 etcd 节点既为其他节点提供服务,又需要作为客户端访问其他节点,因此该证书同时用作服务器证书和客户端证书。
  2. etcd 集群向外提供服务使用的证书。该证书是服务器证书。
  3. kube-apiserver 作为客户端访问 etcd 使用的证书。该证书是客户端证书。
  4. kube-apiserver 对外提供服务使用的证书。该证书是服务器证书。
  5. kube-controller-manager 作为客户端访问 kube-apiserver 使用的证书,该证书是客户端证书。
  6. kube-scheduler 作为客户端访问 kube-apiserver 使用的证书,该证书是客户端证书。
  7. kube-proxy 作为客户端访问 kube-apiserver 使用的证书,该证书是客户端证书。
  8. kubelet 作为客户端访问 kube-apiserver 使用的证书,该证书是客户端证书。
  9. 管理员用户通过 kubectl 访问 kube-apiserver 使用的证书,该证书是客户端证书。
  10. kubelet 对外提供服务使用的证书。该证书是服务器证书。
  11. kube-apiserver 作为客户端访问 kubelet 采用的证书。该证书是客户端证书。
  12. 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中的证书配置

其实主要就分为几类

  1. 服务器证书(就是身份信息+公钥)
  2. 服务器证书的私钥
  3. 验证证书的CA根证书

etcd证书配置

  1. etcd 对外提供服务的服务器证书及私钥。 被访
  2. etcd 节点之间相互进行认证的 peer 证书、私钥以及验证 peer 的 CA。 访问,被访,及验证
  3. 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 证书配置

  1. kube-apiserver 对外提供服务的服务器证书及私钥。 被访
  2. kube-apiserver 访问 etcd 所需的客户端证书及私钥。 访问
  3. kube-apiserver 访问 kubelet 所需的客户端证书及私钥。 访问
  4. 验证访问其服务的客户端的 CA。 验证
  5. 验证 etcd 服务器证书的 CA 根证书。验证
  6. 验证 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 的过程。

k8s deployment ssl 证书 k8s证书认证_云原生_03

认证方法:客户端证书还是 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 生成证书的流程如下:
  1. 调用 kube-apiserver 生成一个 bootstrap token。
  2. 将该 bootstrap token 写入到一个 kubeconfig 文件中,作为 kubelet 调用 kube-apiserver 的客户端验证方式。
  3. 通过 --bootstrap-kubeconfig 启动参数将 bootstrap token 传递给 kubelet 进程。
  4. Kubelet 采用bootstrap token 调用 kube-apiserver API,生成自己所需的服务器和客户端证书。
  5. 证书生成后,Kubelet 采用生成的证书和 kube-apiserver 进行通信,并删除本地的 kubeconfig 文件,以避免 bootstrap token 泄漏风险。