配置聚合层

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

开始之前

你需要拥有一个 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 列表中有一个 CN,除非该列表为空,在这种情况下允许所有 CN。

使用这些选项启动时,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 证书
    • 允许的名称 (CN) 列表
    • 用户名、用户组和额外信息的头名称
  2. 检查 TLS 连接是否使用以下客户端证书进行认证
    • 由其证书与检索到的 CA 证书匹配的 CA 签名。
    • 在允许的 CN 列表中有一个 CN,除非该列表为空,在这种情况下允许所有 CN。
    • 从相应的头中提取用户名和用户组

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

请注意,提供上述功能是扩展 apiserver 实现的责任。许多扩展 apiserver 默认通过利用 k8s.io/apiserver/ 包来实现。其他扩展 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 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 Server 的主机上运行 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 的示例,它配置为在端口 "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)