配置聚合层

配置聚合层允许使用非核心 Kubernetes API 的其他 API 来扩展 Kubernetes apiserver。

开始之前

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

要检查版本,请输入 kubectl version

说明

要让聚合层在您的环境中工作以支持代理和扩展 API 服务器之间的双向 TLS 认证,需要满足一些设置要求。Kubernetes 和 kube-apiserver 拥有多个 CA,因此请确保代理是由聚合层 CA 签名的,而不是由其他 CA(例如 Kubernetes 通用 CA)签名的。

注意

针对不同类型的客户端重用同一个 CA 可能会对集群的功能产生负面影响。有关详细信息,请参阅CA 重用与冲突

认证流程

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

本节介绍认证和授权流程的工作原理,以及如何配置它们。

高级流程如下:

  1. Kubernetes apiserver:认证请求用户并授权其访问所请求的 API 路径的权限。
  2. Kubernetes apiserver:将请求代理至扩展 API 服务器。
  3. 扩展 API 服务器:验证来自 Kubernetes apiserver 的请求。
  4. 扩展 API 服务器:授权原始用户的请求。
  5. 扩展 API 服务器:执行操作。

本节的其余部分将详细介绍这些步骤。

该流程可参见下图。

aggregation auth flows

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

Kubernetes Apiserver 的认证与授权

发送给由扩展 API 服务器服务的 API 路径的请求,其起始方式与所有 API 请求相同:与 Kubernetes apiserver 通信。该路径已由扩展 API 服务器在 Kubernetes apiserver 中注册。

用户与 Kubernetes apiserver 通信,请求访问该路径。Kubernetes apiserver 使用在其中配置的标准认证和授权机制来认证用户,并授权对特定路径的访问。

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

到目前为止,所有步骤都是标准的 Kubernetes API 请求、认证和授权操作。

现在,Kubernetes apiserver 已准备好将请求发送给扩展 API 服务器。

Kubernetes Apiserver 代理请求

Kubernetes apiserver 现在将发送(或代理)请求给已注册处理该请求的扩展 API 服务器。为此,它需要知道以下几点:

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

为了满足这两个需求,您必须使用多个标志来配置 Kubernetes apiserver。

Kubernetes Apiserver 客户端认证

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

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

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

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

说明

您可以将此选项设置为空,例如 --requestheader-allowed-names=""。这将向扩展 API 服务器表明任何 CN 都是可接受的。

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

  1. 使用它们向扩展 API 服务器进行身份验证。
  2. kube-system 命名空间中创建一个名为 extension-apiserver-authentication 的 ConfigMap,并将 CA 证书和允许的 CN 放入其中。扩展 API 服务器可以随后获取这些信息以验证请求。

请注意,相同的客户端证书被 Kubernetes apiserver 用于向所有扩展 API 服务器进行身份验证。它不会为每个扩展 API 服务器创建一个客户端证书,而是创建一个用于以 Kubernetes apiserver 身份进行认证的单一证书。这个相同的证书会被复用于所有发往扩展 API 服务器的请求。

原始请求的用户名和组

当 Kubernetes apiserver 将请求代理至扩展 API 服务器时,它会告知扩展 API 服务器原始请求通过认证时的用户名和组。它通过其代理请求的 HTTP 头提供这些信息。您必须告知 Kubernetes apiserver 要使用的头名称。

  • 用于存储用户名的头,通过 --requestheader-username-headers
  • 用于存储组的头,通过 --requestheader-group-headers
  • 所有额外头的附加前缀,通过 --requestheader-extra-headers-prefix

这些头名称也会被放入 extension-apiserver-authentication ConfigMap 中,以便扩展 API 服务器可以获取并使用它们。

扩展 API 服务器验证请求

扩展 API 服务器在收到来自 Kubernetes apiserver 的代理请求后,必须验证该请求是否确实来自合法的认证代理(即 Kubernetes apiserver 所扮演的角色)。扩展 API 服务器通过以下方式验证:

  1. 如上所述,从 kube-system 中的 ConfigMap 中检索以下信息:
    • 客户端 CA 证书
    • 允许的名称列表 (CN)
    • 用于用户名、组和额外信息的头名称
  2. 检查 TLS 连接是否使用了以下客户端证书进行认证:
    • 该证书由其证书与检索到的 CA 证书匹配的 CA 签署。
    • 该证书拥有允许的 CN 列表中的一个 CN(除非列表为空,这种情况下允许所有 CN)。
    • 从相应的头中提取用户名和组。

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

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

为了拥有获取 ConfigMap 的权限,扩展 API 服务器需要相应的角色。在 kube-system 命名空间中有一个默认的名为 extension-apiserver-authentication-reader 的角色,可以将其分配给扩展 API 服务器。

扩展 API 服务器授权请求

扩展 API 服务器现在可以验证从头中提取的用户/组是否有权执行给定的请求。它通过向 Kubernetes apiserver 发送一个标准的 SubjectAccessReview 请求来执行此验证。

为了使扩展 API 服务器本身有权向 Kubernetes apiserver 提交 SubjectAccessReview 请求,它需要正确的权限。Kubernetes 包含一个名为 system:auth-delegator 的默认 ClusterRole,它具有相应的权限。可以将此角色授予扩展 API 服务器的 ServiceAccount。

扩展 API 服务器执行

如果 SubjectAccessReview 通过,扩展 API 服务器将执行该请求。

启用 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 选项(用于授权聚合 API 服务器请求)使用不同的 CA 证书。

警告

除非您了解相关风险以及保护 CA 使用的机制,否则请不要复用在不同上下文中使用的 CA。

如果您没有在运行 API 服务器的主机上运行 kube-proxy,则必须确保系统启用了以下 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 apiserver 确定请求应发送至扩展 API 服务器,它需要知道如何联系它。

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

下面是一个扩展 API 服务器的示例,它被配置为在端口“1234”上被调用,并使用自定义 CA 捆绑包验证 my-service-name.my-service-namespace.svc 的 ServerName 的 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)