程序锅

  • 首页
  • 分类
  • 标签
  • 归档
  • 关于

  • 搜索
基础知识 Etcd LeetCode 计算机体系结构 Kubernetes Containerd Docker 容器 云原生 Serverless 项目开发维护 ELF 深入理解程序 Tmux Vim Linux Kernel Linux numpy matplotlib 机器学习 MQTT 网络基础 Thrift RPC OS 操作系统 Clang 研途 数据结构和算法 Java 编程语言 Golang Python 个人网站搭建 Nginx 计算机通用技术 Git

Kubernetes APIServer-Kubernetes 证书

发表于 2023-10-16 | 分类于 Kubernetes | 0 | 阅读次数 2110

kubernetes 的证书

了解证书的基本原理之后,接下去我们了解 kubernetes 的证书情况。在这之前,对 kubernetes 证书中使用比较多、比较直观的就是 kubeconfig 文件。在这个文件中,可以看到配置了好几个证书,但是不清楚这些证书的作用。然后去翻翻核心组件中,发现启动参数中,又配置了好多证书。接着继续看看 pki 目录,发现又有很多证书,但是对这些证书的情况并不是特别了解,主要有以下几个疑问:

  • kubernetes 的证书都有哪些?
  • 核心组件启动参数中的那些证书配置,到底是什么作用?
  • kubeconfig 文件中的内容有哪些?配置的证书到底是什么?
  • 在使用 kubeconfig 访问 apiserver 的情况下,修改了 apiserver 的地址,这个地址是可以 ping 通的。但是,使用改了 IP 地址之后的 kubeconfig 访问时会访问不了,会告诉你 tls: failed to verify certificate: x509: certificate is valid for 10.32.0.1, ********, 172.30.172.96, not 127.0.0.1,这个是怎么回事?
  • kubernetes 是怎么通过证书就知道使用该证书的用户是谁?从而赋予相应的权限。很显然是证书中的某个字段,带了相应的用户信息,那么是哪个字段呢?

证书列表

在介绍证书之前,先了解一个前提条件:Kubernetes 为了安全性,都是采用双向认证的。双向认证和单向认证的区别如下:

  • 服务器单向认证:只需要服务器端提供证书,客户端通过服务器端证书验证服务的身份,但服务器并不验证客户端的身份。这种情况一般适用于对 Internet 开放的服务,例如搜索引擎网站,任何客户端都可以连接到服务器上进行访问,但客户端需要验证服务器的身份,以避免连接到伪造的恶意服务器。
  • 双向 TLS 认证:除了客户端需要验证服务器的证书,服务器也要通过客户端证书验证客户端的身份。这种情况下服务器提供的是敏感信息,只允许特定身份的客户端访问。

接下去我们继续,在使用 kubeadm 安装 kubernetes 的时候会自动生成集群所需要的证书,生成的证书通常位于 /etc/kubernetes/pki/ 目录。下面是 kubeadm 安装完集群之后生成的证书:

$ tree /etc/kubernetes/pki/
/etc/kubernetes/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
  • ca.crt 和 ca.key 这两个是签发 kubernetes 中其他证书的 CA(certification authority) 证书和私钥,相当于认证机构的根证书和私钥,是 kubernetes 中的主 CA。

  • apiserver-etcd-client.crt 和 apiserver-etcd-client.key ,这两个是 kube-apiserver 访问 etcd 时使用的客户端证书。其中 apiserver-etcd-client.crt 是由 etcd 的 CA 证书签发的。

  • apiserver.crt 和 apiserver.key 是 kube-apiserver 对外提供服务的服务端证书及私钥,由上述的 CA 的证书签发。如果按照我们之前讲述的话,上述的 ca.crt 是证书机构的根证书,apiserver.crt 则是证书机构签发的证书。

  • apiserver-kubelet-client.crt 和 apiserver-kubelet-client.key 是 kube-apiserver 访问 kubelet 时需要的客户端证书及私钥。

  • front-proxy-ca.crt、front-proxy-ca.key、front-proxy-client.crt 和 front-proxy-client.key 分别是聚合层(aggregator)的 CA 根证书及私钥(用于验证请求的客户端证书是否可信),访问聚合层的客户端证书及私钥。

    当 API Server 需要与聚合层的 API 服务器通信时,它会通过前端代理发送请求。这时,聚合层的 API 服务器需要验证发起请求的 API Server 是否可信。这个验证过程就会用到 front-proxy-ca.crt。因此,访问聚合层的客户端证书需要由该 CA 根证书签名。

  • etcd/ca.crt 和 etcd/ca.key 这两个签发 etcd 相关证书的 CA 证书和私钥。

  • etcd/server.crt 和 etcd/server.key 这两个是 etcd 对外服务的服务器证书和私钥。

  • etcd/peer.crt 和 etcd/peer.key 这两个是 etcd 节点之间相互进行认证的证书和私钥。

  • etcd/healthcheck-client.crt 和 etcd/healthcheck-client.key 这两个是 etcd 访问其他服务的客户端证书和私钥。

使用下述命令分别查看相应证书的 Issuer 和 Subject 来查看相应的签名关系,

openssl x509 -in /etc/kubernetes/pki/apiserver.crt  -text
  • ca.crt 的 Issuer 和 Subject 都是 kubernetes,因为它是认证机构的根证书,所以是自签名的。

    Issuer: CN=kubernetes
    Subject: CN=kubernetes
    
  • apiserver-etcd-client.crt 的 Issuer 是 etcd-ca

    Issuer: CN=etcd-ca
    Subject: O=system:masters, CN=kube-apiserver-etcd-client
    
  • apiserver.crt 的 Issuer 是 kubernetes

    Issuer: CN=kubernetes
    Subject: CN=kube-apiserver
    
  • apiserver-kubelet-client.crt 的 Issuer 是 kubernetes

    Issuer: CN=kubernetes
    Subject: O=system:masters, CN=kube-apiserver-kubelet-client
    
  • front-proxy-ca.crt 的 Issuer 和 Subject 都是 front-proxy-ca,因为它是认证机构的根证书,所以是自签名的

    Issuer: CN=front-proxy-ca
    Subject: CN=front-proxy-ca
    
  • front-proxy-client.crt 的 Issuer 是 front-proxy-ca

    Issuer: CN=front-proxy-ca
    Subject: CN=front-proxy-client
    
  • etcd/ca.crt 的 Issuer 和 Subject 都是 etcd-ca

    Issuer: CN=etcd-ca
    Subject: CN=etcd-ca
    
  • etcd/server.crt 的 Issuer 是 etcd-ca,Subject 是节点名

    Issuer: CN=etcd-ca
    Subject: CN=izbp1bndrgrf******z
    
  • etcd/peer.crt 的 Issuer 是 etcd-ca,Subject 是节点名

    Issuer: CN=etcd-ca
    Subject: CN=izbp1bndrgrf******z
    
  • etcd/healthcheck-client.crt 的 Issuer 是 etcd-ca

    Issuer: CN=etcd-ca
    Subject: O=system:masters, CN=kube-etcd-healthcheck-client
    

各组件配置的证书情况

Etcd

containers:
  - command:
    - etcd
    # etcd 对外提供服务的服务器证书
    - --cert-file=/etc/kubernetes/pki/etcd/server.crt
    # etcd 服务器证书对应的私钥
    - --key-file=/etc/kubernetes/pki/etcd/server.key
		
		# peer 证书,用于 etcd 节点之间的相互访问
    - --peer-cert-file=/etc/kubernetes/pki/etcd/peer.crt	
    # peer 证书对应的私钥
    - --peer-key-file=/etc/kubernetes/pki/etcd/peer.key		  
   	# 用于验证 peer 证书的 CA 根证书,上述 peer 证书都是由该证书签发
    - --peer-trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt
    
    # 用于验证访问 etcd 服务器的客户端证书的 CA 根证书,因此访问 etcd 的客户端证书都需要由该 CA 根证书签名。
    # 在 kubernetes 中,访问 etcd 的只有 apiserver,因此上述提到的 apiserver-etcd-client.crt 证书是由 etcd 的 CA 根证书签名的。
    - --trusted-ca-file=/etc/kubernetes/pki/etcd/ca.crt	

kube-apiserver

containers:
  - command:
    - kube-apiserver
    # kube-apiserver 对外提供服务的服务器证书
    - --tls-cert-file=/etc/kubernetes/pki/apiserver.crt
    # 服务器证书对应的私钥
    - --tls-private-key-file=/etc/kubernetes/pki/apiserver.key
    
    # 用于访问 kubelet 的客户端证书
    - --kubelet-client-certificate=/etc/kubernetes/pki/apiserver-kubelet-client.crt
    # 用于访问 kubelet 的客户端证书的私钥
    - --kubelet-client-key=/etc/kubernetes/pki/apiserver-kubelet-client.key

		# 用于访问 etcd 的客户端证书
    - --etcd-certfile=/etc/kubernetes/pki/apiserver-etcd-client.crt
    # 用于访问 etcd 的客户端证书对应的私钥
    - --etcd-keyfile=/etc/kubernetes/pki/apiserver-etcd-client.key
    
    # 用于验证访问 kube-apiserver 的客户端的证书的 CA 根证书,因此访问 kube-apiserver 的客户端证书需要由该证书签名。如果采用其他 CA 证书签名的话是没有用的,只能使用 kubernetes 主 CA 根证书签名的证书才有用。
   	- --client-ca-file=/etc/kubernetes/pki/ca.crt
   	
   	# 用于验证 etcd 服务器证书的 CA 根证书
    - --etcd-cafile=/etc/kubernetes/pki/etcd/ca.crt
    
    # 用于访问聚合层的客户端证书
    - --proxy-client-cert-file=/etc/kubernetes/pki/front-proxy-client.crt
    - --proxy-client-key-file=/etc/kubernetes/pki/front-proxy-client.key
    
    # 聚合层用于验证访问自己的客户端的证书是否可信,因此访问聚合层的客户端证书需要由该证书签名。
    - --requestheader-client-ca-file=/etc/kubernetes/pki/front-proxy-ca.crt
    
    # 用于验证 service account token 的公钥
    - --service-account-key-file=/etc/kubernetes/pki/sa.pub
    - --service-account-signing-key-file=/etc/kubernetes/pki/sa.key

kube-controller-manager

containers:
  - command:
    - kube-controller-manager
    # 访问 kube-apiserver 时使用的 kubeconfig 文件。
    - --kubeconfig=/etc/kubernetes/controller-manager.conf
    # kubeconfig 中使用的用户,需要具有创建 tokenreviews.authentication.k8s.io 的权限。
    - --authentication-kubeconfig=/etc/kubernetes/controller-manager.conf
    # 同上,具有创建 subjectaccessreviews.authorization.k8s.io 的权限。
    - --authorization-kubeconfig=/etc/kubernetes/controller-manager.conf
    
    # 用于验证访问 kube-controller-manager 的客户端的证书。
    - --client-ca-file=/etc/kubernetes/pki/ca.crt
    
    # 为其他组件签发证书时需要使用的 CA 证书和私钥。
    - --cluster-signing-cert-file=/etc/kubernetes/pki/ca.crt
    - --cluster-signing-key-file=/etc/kubernetes/pki/ca.key
    
    # 将这个证书作为集群中 Pod Service Account 的 ca.crt 字段的来源,为 Pod 内运行的服务提供验证 kube-apiserver 的证书。
    - --root-ca-file=/etc/kubernetes/pki/ca.crt
    # 对 service account token 进行加密的私钥文件的路径。kube-controller-manager 使用这个私钥生成相应 service account token,Pod 访问 kube-apiserver 的时候会使用这些 token,然后这些 token 会被 kube-apiserver 验证,由于 kube-apiserver 启动的时候指定了相应的公钥,因此它可以进行验证。
    - --service-account-private-key-file=/etc/kubernetes/pki/sa.key

通过上述的配置,我们可以发现在访问 kube-apiserver 的时候,kube-controller-manager 使用的是 kubeconfig 文件中配置的信息,而不是直接使用某个证书。其实,在 kubernetes 中 kube-controller-mananger、kube-scheduler、kubelet 等组件,都会只配置一个kubeconfig 文件来访问 kube-apiserver,文件中包含了 kube-apiserver 的地址,验证 kube-apiserver 服务器证书的 CA 证书,自己的客户端证书和私钥等访问信息。关于 kubeconfig,我们会抽出来单独介绍。

SubjectAccessReview(subjectaccessreviews.authorization.k8s.io)和 TokenReview(tokenreviews.authentication.k8s.io)是两种特殊的 API 资源。它们不是由 Kubernetes 控制器或核心组件主动创建的,而是由集群管理员、开发者或第三方应用程序在需要进行认证或授权检查时创建。

  • subjectaccessreviews 是查询某个用户或 service account 是否有相应的权限,也就是某个用户或 service account 是否有权限执行特定的操作(如创建、查看、删除资源等)。详细见 https://kubernetes.io/zh-cn/docs/reference/kubernetes-api/authorization-resources/subject-access-review-v1/。
  • tokenreviews 是对某个 token 进行身份验证,返回令牌是否有效,以及有效令牌所关联的用户信息,为身份验证决策提供依据。详细见https://kubernetes.io/zh-cn/docs/reference/kubernetes-api/authentication-resources/token-review-v1/。

kube-scheduler

kube-scheduler 和 kube-controller-manager 类似,都会配置了一个 kubeconfig 文件。

containers:
  - command:
    - kube-scheduler
    - --authentication-kubeconfig=/etc/kubernetes/scheduler.conf
    - --authorization-kubeconfig=/etc/kubernetes/scheduler.conf
    - --bind-address=127.0.0.1
    - --kubeconfig=/etc/kubernetes/scheduler.conf
    - --leader-elect=true

kubelet

我们通过 systemctl cat kubelet 命令可以查看 kubelet.service 及其所有相关 drop-in 文件的内容,如下所示。可以看到 kubelet 也使用了 kubeconfig 文件,一个是 bootstrap-kubelet.conf,另一个是 kubelet.conf 文件。

# /usr/lib/systemd/system/kubelet.service
[Unit]
Description=kubelet: The Kubernetes Node Agent
Documentation=https://kubernetes.io/docs/
Wants=network-online.target
After=network-online.target

[Service]
ExecStart=/usr/bin/kubelet
Restart=always
StartLimitInterval=0
RestartSec=10

[Install]
WantedBy=multi-user.target

# /usr/lib/systemd/system/kubelet.service.d/10-kubeadm.conf
# Note: This dropin only works with kubeadm and kubelet v1.11+
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
# This is a file that "kubeadm init" and "kubeadm join" generates at runtime, populating the KUBELET_KUBEADM_ARGS variable dynamically
EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
# This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, the user should use
# the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. KUBELET_EXTRA_ARGS should be sourced from this file.
EnvironmentFile=-/etc/sysconfig/kubelet
ExecStart=
ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS --node-ip=********

kubelet.service 和 kubelet.service.d/10-kubeadm.conf 文件的区别,

  • kubelet.service 文件是一个 systemd 单元文件,它定义了如何启动 kubelet 服务。这个文件包括一些基本的服务描述、依赖关系和如何执行 kubelet 进程。通常,这个文件不会包含太多的启动参数,因为这些参数可能会根据不同的安装和配置方式而变化。

  • 10-kubeadm.conf 是一个 systemd "drop-in" 配置文件。它位于 kubelet.service.d/ 目录下,这个目录通常用于存放可以补充或覆盖主服务文件 (kubelet.service) 中设置的特定配置。

这种设计允许 kubelet.service 主服务文件保持相对标准化,而所有特定于 kubeadm 的配置都可以通过 drop-in 文件 (10-kubeadm.conf) 来管理。当 systemd 启动 kubelet 服务时,它会合并主服务文件和所有相关的 drop-in 文件,以形成 kubelet 的最终运行配置。

由于 kubeadm 可以通过这些额外的配置来管理 kubelet,因此用户在大多数情况下不需要直接编辑 kubelet.service 文件。任何与 kubeadm 集群管理相关的 kubelet 配置更改应该通过修改 10-kubeadm.conf 或添加新的 drop-in 文件来进行。

kubeconfig

上文提到 Kubernetes 中的各个组件,比如 kube-controller-mananger、kube-scheduler、kubelet 等,都依赖 kubeconfig 文件来访问 kube-apiserver。

kubeconfig 文件格式

kubeconfig 是 Kubernetes 的一个配置文件,它包含了访问 Kubernetes 集群所需的信息,主要由以下三部分组成。

  • 集群(clusters):定义了要连接的 Kubernetes 集群的信息,包括集群的名称、服务器的地址和验证服务器证书的 CA 证书。
  • 用户(users):定义了用户的认证信息,包括用户的名称、客户端的证书和密钥。
  • 上下文(contexts):定义了用户和集群之间的关系。一个上下文包含了一个用户和一个集群,以及用户在该集群中的默认命名空间。通过在 kubeconfig 文件中定义不同的上下文,可以轻松地在不同的 Kubernetes 集群和命名空间之间切换。

kubeconfig 文件举例

上文已经提到了较多的 kubeconfig 文件,下面我们拿 /etc/kubernetes/config 中的 admin.conf 文件为例进行讲解(其中具体的证书内容和私钥由相应的 <> 替代了)。

apiVersion: v1
clusters:
- cluster:
    certificate-authority-data: <ca.crt + base64>
    server: https://***.***.***.***:***
  name: kubernetes
contexts:
- context:
    cluster: kubernetes
    user: kubernetes-admin
  name: kubernetes-admin@kubernetes
current-context: kubernetes-admin@kubernetes
kind: Config
preferences: {}
users:
- name: kubernetes-admin
  user:
    client-certificate-data: <client.crt>
    client-key-data: <client.key>
  • clusters 中的 certificate-authority-data 是验证服务器证书的 CA 证书 base64 之后的内容。

    可以看到 certificate-authority-data 的内容,其实就是 kubernetes 主证书的内容。

    # 1. 首先将 certificate-authority-data 的内容使用 base64 进行解码
    $ echo <ca.crt + base64> | base64 -d > k-ca.crt
    
    # 2. 使用 diff 进行比较,是完全一样的
    $ diff k-ca.crt /etc/kubernetes/pki/ca.crt
    
    # 3. 查看 k-ca.crt 的内容
    $ openssl x509 -in k-ca.crt -text
    Issuer: CN=kubernetes
    Subject: CN=kubernetes
    
  • users 中的 client-certificate-data 是客户端的证书 base64 之后的内容。

    可以看到 client-certificate-data 证书的内容中,Issuer 是 kubernetes,也就表明该客户端证书是由 kubernetes 的 CA 证书机构签名的。上文提到 kube-apiserver 的参数 client-ca-file 配置的是验证访问 kube-apiserver 的客户端的证书的 CA 根证书,因此这里客户端的证书也必须由 CA 证书机构签名。

    # 1. 首先将 client-certificate-data 的内容使用 base64 进行解码
    $ echo <client.crt> | base64 -d > client.crt
    
    # 2. 查看 client.crt 的内容
    $ openssl x509 -in client.crt -text
    Issuer: CN=kubernetes
    Subject: O=system:masters, CN=kubernetes-admin
    

证书签发

证书签发是指为 kubernetes 的客户端签发相应的证书,客户端访问 kube-apiserver 时使用签发的证书。

通常有两种方式,

  • 使用 /etc/kubernetes/pki/ca.key 和 /etc/kubernetes/pki/ca.crt 生成相应的证书,生成的方式可参考之前讲数字证书时提到的方式。

    # 生成私钥
    $ openssl genrsa -out dawnguo.key 2048
    
    # 生成证书请求
    $ openssl req -new -key dawnguo.key -out dawnguo.csr -subj "/CN=dawnguo/O=system:masters"
    
    # 对证书请求进行签名,并生成相应的客户端证书
    $ openssl x509 -req -in dawnguo.csr -CA /etc/kubernetes/pki/ca.crt -CAkey /etc/kubernetes/pki/ca.key -CAcreateserial -out dawnguo.crt -days 10000 -extensions v3_ext
    
    # 对证书进行 base64 编码
    $ cat dawnguo.crt | base64 | tr -d '\n'
    
    # 对 key(密钥)进行编码
    $ cat dawnguo.key | base64 | tr -d '\n'
    
  • 使用 certificates.k8s.io API 创建证书,这个本质上其实还是上述的流程,对于我们来说只需要提供一个 csr 就可以了。

可参考以下两个链接,

  • https://feisky.gitbooks.io/kubernetes/content/practice/user-management.html

  • https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/certificate-signing-requests/#normal-user

另外,需要注意的是上述,由于我们使用了 system:master 组(/O 指定的内容),所以这个用户名可以随意,因为 RBAC 主要是根据这个组来进行判断。但是假如新增了一个用户,而这个用户没有任何组的话,我们则需要创建相应的 role 和 rolebinding 资源。

其他问题

解决上述遗留的几个问题,

  • 在使用 kubeconfig 访问 apiserver 的情况下,修改了 apiserver 的地址,这个地址是可以 ping 通的。但是,使用改了 IP 地址之后的 kubeconfig 访问时会访问不了,会告诉你 tls: failed to verify certificate: x509: certificate is valid for 10.32.0.1, ********, 172.30.172.96, not 127.0.0.1,这个是怎么回事?

    这里需要查看 kube-apiserver 的服务端证书,也就是 /etc/kubernetes/pki/apiserver.crt。该证书的 X509v3 extensions 字段,指定了该服务可正常访问的域名和 IP 地址。

    X509v3 extensions:
                X509v3 Subject Alternative Name:
                    DNS:izbp1bndrgrf54****zf1bz, DNS:kubernetes, DNS:kubernetes.default, DNS:kubernetes.default.svc, DNS:kubernetes.default.svc.cluster.local, IP Address:10.32.0.1, IP Address:********, IP Address:172.30.172.96
    
  • kubernetes 是怎么通过证书就知道使用该证书的用户是谁?从而赋予相应的权限。很显然是证书中的某个字段,带了相应的用户信息,那么是哪个字段呢?

    用户信息由证书中 Subject 字段提供,其中 O 表示用户归属的组,CN 表示用户名。之后 kube-apiserver 通过 RBAC 机制确定该用户拥有的权限,从而限制使用该证书访问时的权限。

相关链接

kube-controller-manager:https://kubernetes.io/zh-cn/docs/reference/command-line-tools-reference/kube-controller-manager/

PKI 证书和要求:https://kubernetes.io/zh-cn/docs/setup/best-practices/certificates/

关于 Kubernetes 证书的那点事:https://cloud.tencent.com/developer/article/1744610

用户认证:https://kubernetes.io/zh-cn/docs/reference/access-authn-authz/authentication/

卷死我
dawnguo 微信支付

微信支付

dawnguo 支付宝

支付宝

  • 本文作者: dawnguo
  • 本文链接: /archives/248
  • 版权声明: 本博客所有文章除特别声明外,均采用CC BY-NC-SA 3.0 许可协议。转载请注明出处!
# Kubernetes
Kubernetes APIServer-综述
Kubernetes APIServer-ServiceAccount 和 Token
  • 文章目录
  • 站点概览
dawnguo

dawnguo

215 日志
24 分类
37 标签
RSS
Creative Commons
© 2018 — 2025 程序锅
0%