我正在深入研究 Kubernetes PKI。我注意到,几乎所有控制平面组件(包括 kubelet)都使用 TLS 证书向 api-server 进行身份验证。
只有 kube-proxy 和 flannelDaemonsets
以服务帐户身份运行进行身份验证。文档指出:
DaemonSet:由于 kubelet 本身在每个节点上都加载,并且足以启动基本服务,因此您可以将 kube-proxy 和其他特定于节点的服务作为 kube-system 命名空间中的守护进程集而不是独立进程来运行。由于它将在集群内,因此您可以为其提供具有适当权限的适当服务帐户来执行其活动。这可能是配置此类服务最简单的方法。
关于身份验证,这里有什么特别之处?Daemonsets
“
由于 kubelet 本身已加载到每个节点上,并且足以启动基本服务“?
答案1
为了更好地理解这个问题,值得提醒一下基本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
在命名空间中创建 一个 ServiceAccountkube-system
;然后将 kube-proxy 部署为 DaemonSet:
- 控制平面的凭证(
ca.crt
和token
)来自 ServiceAccount- API 服务器的位置(URL)来自 ConfigMap
- ServiceAccount 与 ClusterRole
kube-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-proxy
pod 的 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。