为什么 kube-proxy 使用服务帐户而不是 tls 证书向 kube-api-server 进行身份验证

为什么 kube-proxy 使用服务帐户而不是 tls 证书向 kube-api-server 进行身份验证

我正在深入研究 Kubernetes PKI。我注意到,几乎所有控制平面组件(包括 kubelet)都使用 TLS 证书向 api-server 进行身份验证。
只有 kube-proxy 和 flannelDaemonsets以服务帐户身份运行进行身份验证。文档指出:

DaemonSet:由于 kubelet 本身在每个节点上都加载,并且足以启动基本服务,因此您可以将 kube-proxy 和其他特定于节点的服务作为 kube-system 命名空间中的守护进程集而不是独立进程来运行。由于它将在集群内,因此您可以为其提供具有适当权限的适当服务帐户来执行其活动。这可能是配置此类服务最简单的方法。

关于身份验证,这里有什么特别之处?Daemonsets
由于 kubelet 本身已加载到每个节点上,并且足以启动基本服务“?

答案1

为了更好地理解这个问题,值得提醒一下基本Kubernetes 组件

Kubernetes 组件

基本上我们可以将集群划分为:

  • 主节点:控制平面,负责制定集群的全局决策
  • 工作节点——负责通过提供 Kubernetes 运行时环境来运行 Pod。

让我们看一下“Node”(worker)部分组件:

库贝莱特

在每个上运行的代理 节点 在集群中。它确保 容器 正在运行 。kubelet 采用通过各种机制提供的一组 PodSpec,并确保这些 PodSpec 中描述的容器正在运行且健康。kubelet 不管理不是由 Kubernetes 创建的容器。

kube-proxy

kube-proxy 是一个网络代理,运行在每个 节点 在你的集群中实现 Kubernetes 的一部分 服务 概念。 kube-proxy 维护节点上的网络规则。这些网络规则允许从集群内部或外部的网络会话与您的 Pod 进行网络通信。kube-proxy 使用操作系统数据包过滤层(如果有且可用)。否则,kube-proxy 会自行转发流量。

容器运行时

容器运行时是负责运行容器的软件。Kubernetes 支持多种容器运行时: Docker容器克里欧以及任何实施 Kubernetes CRI(容器运行时接口)

由于kubelet和 容器运行时 是负责运行 pod 和建立与控制平面的连接的两个主要组件,因此它们必须直接安装在节点的操作系统上。这也意味着kubelet它必须具有您在问题中提到的 TLS 证书,以确保与控制平面的安全连接。那 呢kube-proxy

它可以在集群配置期间以两种方式安装 - 直接在节点的操作系统上安装(例如,这种方式用于Kubernetes 的艰难之路)或 DaemonSet(kubeadm)。

kube-proxy什么时候直接安装它还将分别生成 TLS 证书, 就像kubelet

第二种方式是问题中提到的“DeamonSet”。这意味着它不是直接在节点上作为 OS 守护进程运行,而是通过以下方式进行配置:守护进程集部署后,它将作为 pod 在每个节点上运行。与直接在 OS 上运行相比,其优势如下:

  • 使用 DeamonSet 功能,我们可以确保在发生故障时,该 pod 将在节点上自动重新创建
  • 对节点操作系统的直接干扰较少 - 我们只需使用 ServiceAccount,而无需生成新的 TLS 证书对

回答你的问题:

关于身份验证,守护进程集有何特殊之处?

为了更好地理解它,我们可以更深入地研究kube-proxy使用 DaemonSets 配置的集群kubeadm。基于Kubernetes 文档

kube-proxy 在命名空间中创建 一个 ServiceAccount kube-system ;然后将 kube-proxy 部署为 DaemonSet:

  • 控制平面的凭证(ca.crttoken)来自 ServiceAccount
  • API 服务器的位置(URL)来自 ConfigMap
  • ServiceAccount 与 ClusterRolekube-proxy 中的权限进行绑定 system:node-proxier

有三点。我们先来看看第一点:

凭证——秘密

从 pod 定义中获取服务账户名称:

kubectl get daemonset kube-proxy -n kube-system -o yaml
  ...
  serviceAccount: kube-proxy
  serviceAccountName: kube-proxy
  ...

正如所见,它有分配了服务帐号称为kube-proxy

我们来检查一下:

kubectl get sa kube-proxy -n kube-system -o yaml

输出:

apiVersion: v1
kind: ServiceAccount
metadata:
  creationTimestamp: "2021-08-16T14:14:56Z"
  name: kube-proxy
  namespace: kube-system
  resourceVersion: "259"
  uid: (UID)
secrets:
- name: kube-proxy-token-2qhph

如您所见,我们所指的秘密名为kube-proxy-token-2qhph

kubectl get secret kube-proxy-token-2qhph -n kube-system -o yaml

输出:

apiVersion: v1
data:
  ca.crt: (APISERVER'S CA BASE64 ENCODED)
  namespace: (NAMESPACE BASE64 ENCODED)
  token: (BEARER TOKEN BASE64 ENCODED)
kind: Secret
metadata:
  annotations:
    kubernetes.io/service-account.name: kube-proxy
    kubernetes.io/service-account.uid: ...
  creationTimestamp: "2021-08-16T14:14:56Z"
  name: kube-proxy-token-2qhph
  namespace: kube-system
  resourceVersion: "256"
  uid: (UID)
type: kubernetes.io/service-account-token

这个秘密包含

创建的密钥包含 API 服务器的公共 CA 和签名的 JSON Web Token (JWT)。

我们正在使用此“JSON Web Token”承载令牌来验证请求:

服务帐户是一种自动启用的身份验证器,它使用签名的承载令牌来验证请求。

签名的 JWT 可用作承载令牌,以作为给定服务帐户进行身份验证。请参阅多于了解如何将令牌包含在请求中。通常,这些机密会挂载到 Pod 中,以便在集群内访问 API 服务器,但也可以在集群外部使用。

要获取有关引导令牌的更多信息,我建议阅读以下 Kubernetes 文档:使用 Bootstrap 令牌进行身份验证kubeadm 令牌Kubernetes RBAC 101:身份验证

配置图

通过与获取 ServiceAccount 名称类似的步骤,我们将获取挂载到kube-proxypod 的 ConfigMap 名称:

kubectl get daemonset kube-proxy -n kube-system -o yaml
...
volumes:
      - configMap:
          defaultMode: 420
          name: kube-proxy
 ...

现在,让我们获取 ConfigMap 定义:

kubectl get cm kube-proxy -n kube-system -o yaml
  kubeconfig.conf: |-
    apiVersion: v1
    kind: Config
    clusters:
    - cluster:
        certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
        server: https://10.230.0.12:6443
      name: default
    contexts:
    - context:
        cluster: default
        namespace: default
        user: default
      name: default
    current-context: default
    users:
    - name: default
      user:
        tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token

下面的这个 IP 地址server:是 API 地址,因此kube-proxy知道它并可以与其通信。还有对ca.rt和的引用token,它们是从kube-proxy-token-2qhph秘密安装的。

集群角色

让我们检查一下前面提到的 ClusterRole - system:node-proxier

kubectl describe clusterrole system:node-proxier
Name:         system:node-proxier
Labels:       kubernetes.io/bootstrapping=rbac-defaults
Annotations:  rbac.authorization.kubernetes.io/autoupdate: true
PolicyRule:
  Resources                        Non-Resource URLs  Resource Names  Verbs
  ---------                        -----------------  --------------  -----
  events                           []                 []              [create patch update]
  events.events.k8s.io             []                 []              [create patch update]
  nodes                            []                 []              [get list watch]
  endpoints                        []                 []              [list watch]
  services                         []                 []              [list watch]
  endpointslices.discovery.k8s.io  []                 []              [list watch]

我们可以让这个角色列出并监视节点、端点、服务等的端点......

通过描述ClusterRoleBinding,kubeadm:node-proxier我们可以确认该角色system:node-proxier被ServiceAccount使用kube-proxy

kubectl describe clusterrolebinding kubeadm:node-proxier
Name:         kubeadm:node-proxier
Labels:       <none>
Annotations:  <none>
Role:
  Kind:  ClusterRole
  Name:  system:node-proxier
Subjects:
  Kind            Name        Namespace
  ----            ----        ---------
  ServiceAccount  kube-proxy  kube-system

为了获得更多详细信息,我建议阅读kubeadm实施细节

回答你的第二个问题:

“背后的意义是什么”由于 kubelet 本身在每个节点上都加载,并且足以启动基本服务“?

它只是意味着节点与控制平面建立了连接(作为kubelet负责该连接的组件),因此控制平面可以kube-proxy使用预定义的容器运行时开始在节点上调度 pod。

相关内容