本文已超过一年。较旧的文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。

可扩展准入控制进入 Beta 阶段

在这篇文章中,我们将回顾 Kubernetes API 服务器中的一个功能,它允许您实现任意控制决策,并且在 Kubernetes 1.9 中已经相当成熟。

API 服务器处理的准入阶段是保护 Kubernetes 集群的最强大工具之一,它通过限制可以创建的对象来工作,但它一直局限于编译代码。在 1.9 版本中,我们将准入 Webhook 提升到 Beta 阶段,允许您利用 API 服务器进程之外的准入控制。

什么是准入控制?

准入控制(Admission)处理 API 服务器请求 的一个阶段,它发生在资源持久化之前,但在授权之后。准入控制可以访问与授权相同的信息(用户、URL 等)以及 API 请求的完整正文(对于大多数请求)。

准入阶段由独立的插件组成,每个插件都专注于特定领域,并具有对其检查内容进行语义理解的能力。示例包括:PodNodeSelector(影响调度决策)、PodSecurityPolicy(阻止容器特权升级)和 ResourceQuota(强制执行每个 Namespace 的资源配额)。

准入控制分为两个阶段

  1. 修改(Mutation),允许修改请求体内容本身以及拒绝 API 请求。
  2. 校验(Validation),允许内省查询并拒绝 API 请求。一个准入插件可以同时参与这两个阶段,但所有修改必须发生在校验之前。

修改(Mutation)

准入控制的修改阶段允许在资源持久化之前修改其内容。由于在准入链中同一字段可以被多次修改,因此修改阶段准入插件的顺序很重要。

一个修改型准入插件的例子是 PodNodeSelector 插件,它使用 Namespace 上的 annotation namespace.annotations[“scheduler.alpha.kubernetes.io/node-selector”] 来查找标签选择器,并将其添加到 pod.spec.nodeselector 字段。这主动限制了特定 Namespace 中的 Pod 可以调度到哪些节点上,与 Taint(提供负面限制,也是通过准入插件实现)相对。

校验(Validation)

准入控制的校验阶段允许对特定 API 资源强制执行不变性。校验阶段在所有修改器(mutator)完成之后运行,以确保资源不会再次改变。

一个校验型准入插件的例子也是 PodNodeSelector 插件,它确保所有 Pod 的 spec.nodeSelector 字段都受到 Namespace 上节点选择器限制的约束。即使一个修改型准入插件在 PodNodeSelector 在修改链中运行之后试图更改 spec.nodeSelector 字段,校验链中的 PodNodeSelector 也会阻止该 API 资源的创建,因为它会校验失败。

什么是准入 Webhook?

准入 Webhook 允许 Kubernetes 安装者或集群管理员将修改型和校验型准入插件添加到 kube-apiserver 以及任何基于 k8s.io/apiserver 1.9 的扩展 API 服务器(如 metricsservice-catalogkube-projects)的准入链中,而无需重新编译它们。这两种准入 Webhook 都运行在各自链的末端,并具有与编译型准入插件相同的能力和限制。

它们有什么用?

Webhook 准入插件允许对任何 API 服务器上的任何资源进行修改和校验,因此其应用范围非常广泛。一些常见的用例包括:

  1. 修改诸如 Pod 之类的资源。Istio 曾讨论过使用这种方式将 Sidecar 容器注入到 Pod 中。您也可以编写一个插件,强制将镜像标签解析为镜像 SHA。
  2. 名称限制。在多租户系统中,预留 Namespace 已成为一种用例。
  3. 复杂的 CustomResource 校验。由于可以看到整个对象,聪明的准入插件可以对依赖字段(A 要求 B)甚至外部资源进行复杂校验(与 LimitRanges 对比)。
  4. 安全响应。如果您强制将镜像标签解析为镜像 SHA,您可以编写一个准入插件来阻止某些 SHA 的镜像运行。

注册

两种类型的 Webhook 准入插件都在 API 中注册,并且所有 API 服务器(kube-apiserver 和所有扩展 API 服务器)共享它们的通用配置。在注册过程中,一个 Webhook 准入插件描述了:

  1. 如何连接到 Webhook 准入服务器
  2. 如何验证 Webhook 准入服务器(它真的是我期望的那个服务器吗?)
  3. 将数据发送到该服务器的哪个位置(哪个 URL 路径)
  4. 它将处理哪些资源和哪些 HTTP 动词
  5. API 服务器在连接失败时应该做什么(例如,如果准入 Webhook 服务器宕机)
1 apiVersion: admissionregistration.k8s.io/v1beta1  
2 kind: ValidatingWebhookConfiguration  
3 metadata:  
4   name: namespacereservations.admission.online.openshift.io  
5 webhooks:  
6 - name: namespacereservations.admission.online.openshift.io  
7   clientConfig:  
8     service:  
9       namespace: default  
10      name: kubernetes  
11     path: /apis/admission.online.openshift.io/v1alpha1/namespacereservations  
12    caBundle: KUBE\_CA\_HERE  
13  rules:  
14  - operations:  
15    - CREATE  
16    apiGroups:  
17    - ""  
18    apiVersions:  
19    - "\*"  
20    resources:  
21    - namespaces  
22  failurePolicy: Fail

第 6 行:name - Webhook 本身的名称。对于修改型 Webhook,这些名称会排序以提供顺序。
第 7 行:clientConfig - 提供关于如何连接到、信任以及向 Webhook 准入服务器发送数据的信息。
第 13 行:rules - 描述 API 服务器何时应该调用此准入插件。在这种情况下,仅适用于 Namespace 的创建。您可以在此处指定任何资源,因此指定创建 serviceinstances.servicecatalog.k8s.io 也是合法的。
第 22 行:failurePolicy - 说明如果 Webhook 准入服务器不可用时该怎么办。选项包括“Ignore”(失败开放)或“Fail”(失败关闭)。失败开放会导致所有客户端出现不可预测的行为。

认证和信任

由于 Webhook 准入插件具有很大的权力(请记住,它们可以看到发送给它们的任何请求的 API 资源内容,并且对于修改型插件,它们可能会修改这些内容),因此考虑以下几点很重要:

  • 各个 API 服务器如何验证它们与 Webhook 准入服务器的连接
  • Webhook 准入服务器如何精确认证是哪个 API 服务器正在联系它
  • 该特定 API 服务器是否有权限发起请求。连接主要分为三类:
  1. 从 kube-apiserver 或扩展 apiservers 到外部托管的准入 Webhook(未托管在集群中的 Webhook)
  2. 从 kube-apiserver 到自托管的准入 Webhook
  3. 从扩展 apiservers 到自托管的准入 Webhook。为了支持这些类别,Webhook 准入插件接受一个 kubeconfig 文件,该文件描述了如何连接到各个服务器。对于与外部托管的准入 Webhook 交互,手动配置该文件是唯一的选择,因为身份验证/授权和访问路径由您连接的服务器拥有。

对于自托管类别,精心构建的 Webhook 准入服务器和拓扑可以利用内置于准入插件的安全默认行为,并拥有一个安全、可移植、零配置的拓扑,可以从任何 API 服务器工作。

简单、安全、可移植、零配置的拓扑

如果您将您的 Webhook 准入服务器也构建为一个扩展 API 服务器,就可以将其聚合为一个普通的 API 服务器。这有许多优点:

  • 您的 Webhook 将像默认 kube-apiserver service kubernetes.default.svc 下的任何其他 API 一样可用(例如 https://kubernetes.default.svc/apis/admission.example.com/v1/mymutatingadmissionreviews)。除此之外,您还可以使用 kubectl 进行测试。
  • 您的 Webhook 会自动(无需任何配置)利用 kube-apiserver 提供的集群内身份验证和授权。您可以使用正常的 RBAC 规则限制对您的 Webhook 的访问。
  • 您的扩展 API 服务器和 kube-apiserver 会自动(无需任何配置)使用其集群内凭据与 Webhook 通信。
  • 扩展 API 服务器不会将它们的 Service Account Token 泄露给您的 Webhook,因为它们通过 kube-apiserver 传递,而 kube-apiserver 是一个安全的前置代理。


来源:https://drive.google.com/a/redhat.com/file/d/12nC9S2fWCbeX_P8nrmL6NgOSIha4HDNp

简而言之:安全的拓扑结构利用了 API 服务器聚合的所有安全机制,并且无需额外配置。

其他拓扑结构是可能的,但需要额外的手动配置以及大量精力来创建安全的设置,尤其是在涉及 service catalog 等扩展 API 服务器时。上述拓扑是零配置的,并且可移植到每个 Kubernetes 集群。

如何编写 Webhook 准入服务器?

编写一个完整的包含身份验证和授权的服务器可能令人望而却步。为了使其更容易,有一些基于 Kubernetes 1.9 的项目提供了库,用于在 200 行或更少的代码中构建您的 Webhook 准入服务器。请查看 generic-admission-apiserverkubernetes-namespace-reservation 项目,它们提供了库以及如何构建您自己的安全且可移植的 Webhook 准入服务器的示例。

通过在 1.9 版本中引入准入 Webhook,我们使 Kubernetes 更能适应您的需求。我们希望这项由 Red Hat 和 Google 共同推动的工作能够支持更多的负载和生态系统组件。(Istio 就是一个例子。)现在是时候尝试一下了!

如果您有兴趣提供反馈或为此领域做出贡献,请加入我们的 SIG API machinery