S_lion's Studio

k8s证书机制

字数统计: 2.7k阅读时长: 10 min
2022/04/16 Share

k8s组件的认证方式

k8s各个组件会相互进行远程调用,例如 kube-apiserver 会调用 etcd 接口存储数据,kube-controllermanager 会调用 kube-apiserver 接口查询集群中的对象状态;同时kube-apiserver 也会和在工作节点上的kubeletkube-proxy 进行通信,以在工作节点上部署和管理应用。

以上这些组件之间的相互调用都是通过网络进行的。在进行网络通信时,通信双方需要验证对方的身份,以避免恶意第三方伪造身份窃取信息或者对系统进行攻击。为了相互验证对方的身份,通信双方中的任何一方都需要验证对端的合法性。

k8s里使用数字证书来提供身份证明,为了保证证书的权威性,会采用通信双方都信任的CA机构颁发,另外各组件之间进行通信时,数字证书的验证是通过 TLS 完成的,除了需要在建立通信时提供相关的证书和密钥外,在应用层面并不需要进行特殊处理。

在 Kubernetes 中,各个组件提供的接口中包含了集群的内部信息。如果这些接口被非法访问,将影响集群的安全,因此组件之间的通信需要采用双向 TLS 认证。即客户端和服务器端都需要验证对方的身份信息。在两个组件进行双向认证时,会涉及到下面这些证书相关的文件:

  • 服务器端证书:服务器用于证明自身身份的数字证书,里面主要包含了服务器端的公钥以及服务器的身份信息。
  • 服务器端私钥:服务器端证书中包含的公钥所对应的私钥。公钥和私钥是成对使用的,在进行 TLS 验证时,服务器使用该私钥来向客户端证明自己是服务器端证书的拥有者。
  • 客户端证书:客户端用于证明自身身份的数字证书,里面主要包含了客户端的公钥以及客户端的身份信息。
  • 客户端私钥:客户端证书中包含的公钥所对应的私钥,同理,客户端使用该私钥来向服务器端证明自己是客户端证书的拥有者。
  • 服务器端 CA 根证书:签发服务器端证书的 CA 根证书,客户端使用该 CA 根证书来验证服务器端证书的合法性。
  • 客户端端 CA 根证书:签发客户端证书的 CA 根证书,服务器端使用该 CA 根证书来验证客户端证书的合法性。

K8s中使用到的CA和证书

下图标识出了在 kubernetes 中主要使用到的证书和其使用的位置:

上图中使用序号对证书进行了标注。图中的箭头表明了组件的调用方向,箭头所指方向为服务提供方,另一头为服务调用方。为了实现 TLS 双向认证,服务提供方需要使用一个服务器证书,服务调用方则需要提供一个客户端证书,并且双方都需要使用一个 CA 证书来验证对方提供的证书。为了简明起见,上图中只标注了证书使用方提供的证书,并没有标注证书的验证方验证使用的 CA 证书。图中标注的这些证书的作用分别如下:

  1. etcd 集群中各个节点之间相互通信使用的证书。由于一个 etctd 节点既为其他节点提供服务,又需要作为客户端访问其他节点,因此该证书同时用作服务器证书和客户端证书。
  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中的证书位置

使用kubeadm创建完Kubernetes集群后, 默认会在/etc/kubernetes/pki目录下存放集群中需要用到的证书文件, 整体结构如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
[root@k8s-master ~]# tree /etc/kubernetes/
/etc/kubernetes/
├── admin.conf
├── controller-manager.conf
├── kubelet.conf
├── manifests
│   ├── etcd.yaml
│   ├── kube-apiserver.yaml
│   ├── kube-controller-manager.yaml
│   └── kube-scheduler.yaml
├── pki
│   ├── apiserver.crt
│   ├── apiserver-etcd-client.crt
│   ├── apiserver-etcd-client.key
│   ├── apiserver.key
│   ├── apiserver-kubelet-client.crt
│   ├── apiserver-kubelet-client.key
│   ├── ca.crt
│   ├── ca.key
│   ├── etcd
│   │   ├── ca.crt
│   │   ├── ca.key
│   │   ├── healthcheck-client.crt
│   │   ├── healthcheck-client.key
│   │   ├── peer.crt
│   │   ├── peer.key
│   │   ├── server.crt
│   │   └── server.key
│   ├── front-proxy-ca.crt
│   ├── front-proxy-ca.key
│   ├── front-proxy-client.crt
│   ├── front-proxy-client.key
│   ├── sa.key
│   └── sa.pub
└── scheduler.conf

Kubernetes 集群根证书

Kubernetes 集群根证书CA(Kubernetes集群组件的证书签发机构)

  • /etc/kubernetes/pki/ca.crt

  • /etc/kubernetes/pki/ca.key

以上这组证书为签发其他Kubernetes组件证书使用的根证书, 可以认为是Kubernetes集群中证书签发机构之一。

由此根证书签发的证书有:

  1. kube-apiserver 组件持有的服务端证书
  • /etc/kubernetes/pki/apiserver.crt

  • /etc/kubernetes/pki/apiserver.key

  1. kube-apiserver 组件持有的客户端证书, 用作 kube-apiserver 主动向 kubelet 发起请求时的客户端认证
  • /etc/kubernetes/pki/apiserver-kubelet-client.crt

  • /etc/kubernetes/pki/apiserver-kubelet-client.key

汇聚层证书

kube-apiserver 的另一种访问方式就是使用 kubectl proxy 来代理访问, 而该证书就是用来支持SSL代理访问的. 在该种访问模式下, 我们是以http的方式发起请求到代理服务的, 此时, 代理服务会将该请求发送给 kube-apiserver, 在此之前, 代理会将发送给 kube-apiserver 的请求头里加入证书信息。

kube-apiserver 代理根证书(客户端证书)

用在requestheader-client-ca-file配置选项中, kube-apiserver 使用该证书来验证客户端证书是否为自己所签发

  • /etc/kubernetes/pki/front-proxy-ca.crt
  • /etc/kubernetes/pki/front-proxy-ca.key

由此根证书签发的证书只有一组:

代理层(如汇聚层aggregator)使用此套代理证书来向 kube-apiserver 请求认证

代理端使用的客户端证书, 用作代用户与 kube-apiserver 认证

  • /etc/kubernetes/pki/front-proxy-client.crt
  • /etc/kubernetes/pki/front-proxy-client.key

etcd 集群根证书

etcd集群所用到的证书都保存在/etc/kubernetes/pki/etcd这路径下, 很明显, 这一套证书是用来专门给etcd集群服务使用的, 设计以下证书文件

etcd 集群根证书CA(etcd 所用到的所有证书的签发机构)

  • /etc/kubernetes/pki/etcd/ca.crt
  • /etc/kubernetes/pki/etcd/ca.key

由此根证书签发机构签发的证书有:

  1. etcd server 持有的服务端证书
  • /etc/kubernetes/pki/etcd/server.crt

  • /etc/kubernetes/pki/etcd/server.key

  1. peer 集群中节点互相通信使用的客户端证书
  • /etc/kubernetes/pki/etcd/peer.crt
  • /etc/kubernetes/pki/etcd/peer.key
  1. pod 中定义 Liveness 探针使用的客户端证书
  • /etc/kubernetes/pki/etcd/healthcheck-client.crt

  • /etc/kubernetes/pki/etcd/healthcheck-client.key

kubeadm 部署的 Kubernetes 集群是以 pod 的方式运行 etcd 服务的, 在该 pod 的定义中, 配置了 Liveness 探活探针。

当 describe etcd 的 pod 时, 会看到如下一行配置:

Liveness: exec [/bin/sh -ec ETCDCTL_API=3 etcdctl –endpoints=https://[127.0.0.1]:2379 –cacert=/etc/kubernetes/pki/etcd/ca.crt –cert=/etc/kubernetes/pki/etcd/healthcheck-client.crt –key=/etc/kubernetes/pki/etcd/healthcheck-client.key get foo] delay=15s timeout=15s period=10s #success=1 #failure=8

  1. 配置在 kube-apiserver 中用来与 etcd server 做双向认证的客户端证书
  • /etc/kubernetes/pki/apiserver-etcd-client.crt
  • /etc/kubernetes/pki/apiserver-etcd-client.key

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。该证书的用法和前面介绍的其他证书不同,因为实际上使用的是其公钥和私钥,而并不需要对证书进行验证。

  • /etc/kubernetes/pki/sa.key
  • /etc/kubernetes/pki/sa.pub

可以查看 service account 证书的公钥和私钥会分别被配置到了 kube-apiserver 和 kube-controller-manager 的命令行参数中,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@k8s-master ~]# cat /etc/kubernetes/manifests/kube-controller-manager.yaml
spec:
containers:
- command:
- kube-controller-manager
- ...
- --service-account-private-key-file=/etc/kubernetes/pki/sa.key # 用于对 service account token 进行签名的私钥

[root@k8s-master ~]# cat /etc/kubernetes/manifests/kube-apiserver.yaml
spec:
containers:
- command:
- kube-apiserver
- ...
- --service-account-key-file=/etc/kubernetes/pki/sa.pub # 用于验证 service account token 的公钥

KUBECONFIG

Kubernetes 中的各个组件,包括kube-controller-mananger、kube-scheduler、kube-proxy、kubelet等,采用一个kubeconfig 文件中配置的信息来访问 kube-apiserver。该文件中包含了 kube-apiserver 的地址,验证 kube-apiserver 服务器证书的 CA 证书,自己的客户端证书和私钥等访问信息。

以kubelet.conf为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: v1
clusters:
- cluster:
# 用于验证 kube-apiserver 服务器证书的 CA 根证书
certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX0tLS0tCg==
server: https://localhost:8443
name: kubernetes
contexts:
- context:
cluster: kubernetes
user: system:kube-controller-manager
name: system:kube-controller-manager@kubernetes
current-context: system:kube-controller-manager@kubernetes
kind: Config
preferences: {}
users:
- name: system:kube-controller-manager
user:
# 用于访问 kube-apiserver 的客户端证书
client-certificate-data: LS0tLS1CRUdJTiXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXQ0FURS0tLS0tCg==
# 客户端证书对应的私钥
client-key-data: LS0tLS1CRUdXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXtFWS0tLS0tCg==

参考文章

《一文带你彻底厘清 Kubernetes 中的证书工作机制》 赵化冰

Kubernetes PKI 证书和要求

CATALOG
  1. 1. k8s组件的认证方式
  2. 2. K8s中使用到的CA和证书
  3. 3. K8s中的证书位置
    1. 3.1. Kubernetes 集群根证书
    2. 3.2. 汇聚层证书
    3. 3.3. etcd 集群根证书
    4. 3.4. SERVICE ACCOUNT 证书
    5. 3.5. KUBECONFIG
  4. 4. 参考文章