配置聚合层

配置聚合层允许通过额外的 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`
  • 签署客户端证书文件的 CA 证书通过 `—requestheader-client-ca-file`
  • 签名客户端证书中有效的通用名称 (CN) 值通过 `—requestheader-allowed-names`

Kubernetes apiserver 将使用 `—proxy-client-*-file` 指示的文件向扩展 apiserver 进行认证。为了使请求被合规的扩展 apiserver 视为有效,必须满足以下条件:

  1. 连接必须使用由其证书位于 `—requestheader-client-ca-file` 中的 CA 签名的客户端证书进行。
  2. 连接必须使用其 CN 属于 `—requestheader-allowed-names` 中列出的名称之一的客户端证书进行。

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

  1. 使用它们向扩展 apiserver 进行身份验证。
  2. 在 `kube-system` 命名空间中创建一个名为 `extension-apiserver-authentication` 的配置映射 (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 证书
    • 允许的名称列表 (CNs)
    • 用户名、组和额外信息的头名称
  2. 检查 TLS 连接是否使用客户端证书进行身份验证,该证书:
    • 由其证书与检索到的 CA 证书匹配的 CA 签名。
    • 在允许的 CN 列表中有一个 CN,除非列表为空,在这种情况下所有 CN 都允许。
    • 从相应的头中提取用户名和组

如果上述检查通过,则该请求是来自合法认证代理(本例中为 Kubernetes apiserver)的有效代理请求。

请注意,提供上述功能是扩展 apiserver 实现的责任。许多实现默认通过利用 `k8s.io/apiserver/` 包来完成此操作。其他实现可能会提供选项,使用命令行选项来覆盖它。

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

扩展 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 apiserver 有两个客户端 CA 选项

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

这些功能独立运行,如果使用不当,可能会相互冲突。

  • `--client-ca-file`:当请求到达 Kubernetes apiserver 时,如果此选项已启用,Kubernetes apiserver 会检查请求的证书。如果该证书由 `--client-ca-file` 引用文件中的某个 CA 证书签名,则该请求被视为合法请求,用户是通用名称 `CN=` 的值,而组是组织 `O=`。请参阅 TLS 认证文档
  • `--requestheader-client-ca-file`:当请求到达 Kubernetes apiserver 时,如果此选项已启用,Kubernetes apiserver 会检查请求的证书。如果该证书由 `--requestheader-client-ca-file` 引用文件中的某个 CA 证书签名,则该请求被视为潜在的合法请求。然后 Kubernetes apiserver 检查通用名称 `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 apiserver 进行身份验证。

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

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

--enable-aggregator-routing=true

注册 APIService 对象

您可以动态配置哪些客户端请求被代理到扩展 apiserver。以下是一个注册示例:


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 对象的名称必须是有效的路径段名称

联系扩展 apiserver

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

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

以下是一个扩展 apiserver 的示例,该 apiserver 配置为在端口“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:修复过时链接/锚点 (bcc55ae7c9)