配置聚合层

配置聚合层允许使用额外的 API 扩展 Kubernetes apiserver,这些 API 不是 Kubernetes 核心 API 的一部分。

开始之前

你需要有一个 Kubernetes 集群,并且必须配置 kubectl 命令行工具才能与你的集群通信。建议在至少有两个不充当控制平面主机的节点的集群上运行本教程。 如果你还没有集群,可以使用 minikube 创建一个,或者你可以使用这些 Kubernetes 游乐场之一

要检查版本,请输入 kubectl version

身份验证流程

与自定义资源定义 (CRD) 不同,聚合 API 除了标准的 Kubernetes apiserver 之外,还涉及另一个服务器 - 你的扩展 apiserver。 Kubernetes apiserver 将需要与你的扩展 apiserver 通信,并且你的扩展 apiserver 将需要与 Kubernetes apiserver 通信。 为了确保这种通信的安全性,Kubernetes apiserver 使用 x509 证书向扩展 apiserver 进行身份验证。

本节介绍了身份验证和授权流程的工作方式,以及如何配置它们。

高级流程如下

  1. Kubernetes apiserver:验证请求用户并授权他们对请求的 API 路径的权限。
  2. Kubernetes apiserver:将请求代理到扩展 apiserver
  3. 扩展 apiserver:验证来自 Kubernetes apiserver 的请求
  4. 扩展 apiserver:授权来自原始用户的请求
  5. 扩展 apiserver:执行

本节的其余部分详细描述了这些步骤。

该流程可以在下图 中看到。

aggregation auth flows

上述泳道图的来源可以在本文档的源中找到。

Kubernetes Apiserver 身份验证和授权

对扩展 apiserver 提供的 API 路径的请求以与所有 API 请求相同的方式开始:与 Kubernetes apiserver 的通信。此路径已由扩展 apiserver 向 Kubernetes apiserver 注册。

用户与 Kubernetes apiserver 通信,请求访问该路径。 Kubernetes apiserver 使用 Kubernetes apiserver 配置的标准身份验证和授权来验证用户并授权访问特定路径。

有关向 Kubernetes 集群进行身份验证的概述,请参阅 “向集群进行身份验证”。 有关授权访问 Kubernetes 集群资源的概述,请参阅 “授权概述”

到目前为止的一切都是标准的 Kubernetes API 请求、身份验证和授权。

Kubernetes apiserver 现在已准备好将请求发送到扩展 apiserver。

Kubernetes Apiserver 代理请求

Kubernetes apiserver 现在将发送或代理请求到注册处理该请求的扩展 apiserver。 为此,它需要知道几件事

  1. Kubernetes apiserver 应该如何向扩展 apiserver 进行身份验证,通知扩展 apiserver 通过网络传来的请求来自有效的 Kubernetes apiserver?
  2. Kubernetes apiserver 应该如何通知扩展 apiserver 原始请求所验证的用户名和组?

为了提供这两者,你必须使用几个标志配置 Kubernetes apiserver。

Kubernetes Apiserver 客户端身份验证

Kubernetes apiserver 通过 TLS 连接到扩展 apiserver,使用客户端证书进行身份验证。 你必须在使用提供的标志启动时向 Kubernetes apiserver 提供以下内容

  • 通过 --proxy-client-key-file 获取私钥文件
  • 通过 --proxy-client-cert-file 获取已签名的客户端证书文件
  • 通过 --requestheader-client-ca-file 获取签署客户端证书文件的 CA 证书
  • 通过 --requestheader-allowed-names 获取签名客户端证书中的有效通用名称值 (CN)

Kubernetes apiserver 将使用 --proxy-client-*-file 指示的文件向扩展 apiserver 进行身份验证。 为了使符合标准的扩展 apiserver 将请求视为有效,必须满足以下条件

  1. 必须使用客户端证书建立连接,该证书由 --requestheader-client-ca-file 中的证书所在的 CA 签名。
  2. 必须使用 CN 是 --requestheader-allowed-names 中列出的 CN 之一的客户端证书建立连接。

使用这些选项启动时,Kubernetes apiserver 将

  1. 使用它们向扩展 apiserver 进行身份验证。
  2. 在名为 extension-apiserver-authenticationkube-system 命名空间中创建一个 configmap,它将在其中放置 CA 证书和允许的 CN。 这些反过来可以由扩展 apiserver 检索以验证请求。

请注意,Kubernetes apiserver 使用相同的客户端证书对所有扩展 apiserver 进行身份验证。 它不会为每个扩展 apiserver 创建客户端证书,而是创建一个作为 Kubernetes apiserver 进行身份验证的客户端证书。 对于所有扩展 apiserver 请求,都将重复使用这同一个客户端证书。

原始请求用户名和组

当 Kubernetes apiserver 将请求代理到扩展 apiserver 时,它会通知扩展 apiserver 原始请求成功进行身份验证的用户名和组。 它在代理请求的 http 标头中提供这些信息。 你必须通知 Kubernetes apiserver 要使用的标头的名称。

  • 通过 --requestheader-username-headers 获取在其中存储用户名的标头
  • 通过 --requestheader-group-headers 获取在其中存储组的标头
  • 通过 --requestheader-extra-headers-prefix 获取附加到所有额外标头的前缀

这些标头名称也放置在 extension-apiserver-authentication configmap 中,因此它们可以由扩展 apiserver 检索和使用。

扩展 Apiserver 验证请求

扩展 apiserver 在收到来自 Kubernetes apiserver 的代理请求后,必须验证该请求是否确实来自有效的身份验证代理,Kubernetes apiserver 正在履行该角色。 扩展 apiserver 通过以下方式进行验证

  1. 从上述 kube-system 中的 configmap 中检索以下内容
    • 客户端 CA 证书
    • 允许的名称列表 (CN)
    • 用户名、组和额外信息的标头名称
  2. 检查 TLS 连接是否使用客户端证书进行身份验证,该证书
    • 由其证书与检索到的 CA 证书匹配的 CA 签名。
    • 具有允许的 CN 列表中的 CN,除非该列表为空,在这种情况下,允许所有 CN。
    • 从相应的标头中提取用户名和组

如果以上通过,则该请求是来自合法的身份验证代理(在本例中为 Kubernetes apiserver)的有效代理请求。

请注意,扩展 apiserver 实现有责任提供上述内容。 许多实现默认情况下通过利用 k8s.io/apiserver/ 包来完成。 其他实现可能会提供使用命令行选项覆盖它的选项。

为了有权检索 configmap,扩展 apiserver 需要适当的角色。 在 kube-system 命名空间中有一个名为 extension-apiserver-authentication-reader 的默认角色可以分配。

扩展 Apiserver 授权请求

扩展 apiserver 现在可以验证从标头检索到的用户/组是否被授权执行给定的请求。 它通过向 Kubernetes apiserver 发送标准 SubjectAccessReview 请求来执行此操作。

为了授权扩展 apiserver 本身向 Kubernetes apiserver 提交 SubjectAccessReview 请求,它需要正确的权限。 Kubernetes 包括一个名为 system:auth-delegator 的默认 ClusterRole,该角色具有适当的权限。 可以将其授予扩展 apiserver 的服务帐户。

扩展 Apiserver 执行

如果 SubjectAccessReview 通过,则扩展 apiserver 执行该请求。

启用 Kubernetes Apiserver 标志

通过以下 kube-apiserver 标志启用聚合层。你的提供商可能已经处理好了这些标志。

--requestheader-client-ca-file=<path to aggregator CA cert>
--requestheader-allowed-names=front-proxy-client
--requestheader-extra-headers-prefix=X-Remote-Extra-
--requestheader-group-headers=X-Remote-Group
--requestheader-username-headers=X-Remote-User
--proxy-client-cert-file=<path to aggregator proxy cert>
--proxy-client-key-file=<path to aggregator proxy key>

CA 复用和冲突

Kubernetes API 服务器有两个客户端 CA 选项

  • --client-ca-file
  • --requestheader-client-ca-file

如果使用不当,它们每个都独立运行,并且可能会相互冲突。

  • --client-ca-file:当请求到达 Kubernetes API 服务器时,如果启用此选项,Kubernetes API 服务器会检查请求的证书。如果该证书是由 --client-ca-file 引用的文件中的 CA 证书之一签名的,则该请求将被视为合法请求,用户是通用名称 CN= 的值,而组是组织 O=。请参阅 关于 TLS 身份验证的文档
  • --requestheader-client-ca-file:当请求到达 Kubernetes API 服务器时,如果启用此选项,Kubernetes API 服务器会检查请求的证书。如果该证书是由 --requestheader-client-ca-file 引用的文件中的 CA 证书之一签名的,则该请求将被视为潜在的合法请求。然后,Kubernetes API 服务器会检查通用名称 CN= 是否是 --requestheader-allowed-names 提供的列表中的名称之一。如果名称允许,则请求被批准;如果不是,则请求不被批准。

如果同时提供 --client-ca-file--requestheader-client-ca-file,则请求首先检查 --requestheader-client-ca-file CA,然后检查 --client-ca-file。通常,这些选项中的每一个都使用不同的 CA,无论是根 CA 还是中间 CA;常规客户端请求与 --client-ca-file 匹配,而聚合请求与 --requestheader-client-ca-file 匹配。但是,如果两者使用*相同*的 CA,那么通常通过 --client-ca-file 的客户端请求将失败,因为该 CA 将与 --requestheader-client-ca-file 中的 CA 匹配,但通用名称 CN= 将**不**匹配 --requestheader-allowed-names 中允许的通用名称之一。这可能导致你的 kubelet 和其他控制平面组件以及最终用户无法向 Kubernetes API 服务器进行身份验证。

因此,对于 --client-ca-file 选项(用于授权控制平面组件和最终用户)和 --requestheader-client-ca-file 选项(用于授权聚合 API 服务器请求),请使用不同的 CA 证书。

如果你的 kube-proxy 没有在运行 API 服务器的主机上运行,则你必须确保系统启用以下 kube-apiserver 标志

--enable-aggregator-routing=true

注册 APIService 对象

你可以动态配置将哪些客户端请求代理到扩展 API 服务器。以下是一个注册示例


apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
  name: <name of the registration object>
spec:
  group: <API group name this extension apiserver hosts>
  version: <API version this extension apiserver hosts>
  groupPriorityMinimum: <priority this APIService for this group, see API documentation>
  versionPriority: <prioritizes ordering of this version within a group, see API documentation>
  service:
    namespace: <namespace of the extension apiserver service>
    name: <name of the extension apiserver service>
  caBundle: <pem encoded ca cert that signs the server cert used by the webhook>

APIService 对象的名称必须是有效的 路径段名称

联系扩展 API 服务器

一旦 Kubernetes API 服务器确定请求应该发送到扩展 API 服务器,它就需要知道如何联系它。

service 节是对扩展 API 服务器的服务引用。服务命名空间和名称是必需的。端口是可选的,默认为 443。

以下是一个扩展 API 服务器的示例,该服务器被配置为在端口“1234”上调用,并使用自定义 CA 包针对 ServerName my-service-name.my-service-namespace.svc 验证 TLS 连接。

apiVersion: apiregistration.k8s.io/v1
kind: APIService
...
spec:
  ...
  service:
    namespace: my-service-namespace
    name: my-service-name
    port: 1234
  caBundle: "Ci0tLS0tQk...<base64-encoded PEM bundle>...tLS0K"
...

下一步

上次修改时间为 2023 年 12 月 29 日下午 9:47 PST:修复过时的链接/锚点 (bcc55ae7c9)