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

可扩展准入进入 Beta 版

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

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

什么是准入?

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

准入阶段由单独的插件组成,每个插件都专注于特定的方面,并且具有它们所检查内容的语义知识。示例包括:PodNodeSelector(影响调度决策)、PodSecurityPolicy(防止容器升级)和 ResourceQuota(强制每个命名空间的资源分配)。

准入分为两个阶段

  1. 修改,允许修改正文内容本身以及拒绝 API 请求。
  2. 验证,允许内省查询和拒绝 API 请求。准入插件可以同时处于两个阶段,但所有修改都发生在验证之前。

修改

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

修改准入插件的一个示例是 PodNodeSelector 插件,它使用命名空间上的注解 namespace.annotations[“scheduler.alpha.kubernetes.io/node-selector”] 来查找标签选择器并将其添加到 pod.spec.nodeselector 字段。这有效地限制了特定命名空间中的 Pod 可以落在哪些节点上,而不是污点,污点提供负面限制(也使用准入插件)。

验证

准入的验证阶段允许强制执行特定 API 资源上的不变量。验证阶段在所有修改器完成后运行,以确保资源不会再次更改。

验证准入插件的一个示例也是 PodNodeSelector 插件,它确保所有 Pod 的 spec.nodeSelector 字段都受到命名空间上节点选择器限制的约束。即使修改准入插件尝试在 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 曾讨论过这样做,以将 side-car 容器注入到 Pod 中。你还可以编写一个插件,强制将映像标记解析为映像 SHA。
  2. 名称限制。在多租户系统上,保留命名空间已成为一种用例。
  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 服务器何时应调用此准入插件。在这种情况下,仅适用于创建命名空间。你可以在此处指定任何资源,因此指定创建 serviceinstances.servicecatalog.k8s.io 也是合法的。
第 22 行:failurePolicy - 说明如果 Webhook 准入服务器不可用时该做什么。选项为“忽略”(失败打开)或“失败”(失败关闭)。失败打开会导致所有客户端的行为不可预测。

身份验证和信任

由于 Webhook 准入插件具有很大的权力(请记住,它们可以看到发送给它们的任何请求的 API 资源内容,并且可能会为修改插件修改它们),因此务必考虑

  • 各个 API 服务器如何验证它们与 Webhook 准入服务器的连接
  • Webhook 准入服务器如何精确地验证哪个 API 服务器正在联系它
  • 该特定 API 服务器是否具有发出请求的授权。有三种主要的连接类别
  1. 从 kube-apiserver 或扩展 apiserver 到外部托管的准入 Webhook(未在集群中托管的 Webhook)
  2. 从 kube-apiserver 到自托管的准入 Webhook
  3. 从扩展 apiserver 到自托管的准入 Webhook。为了支持这些类别,Webhook 准入插件接受一个 kubeconfig 文件,该文件描述如何连接到各个服务器。对于与外部托管的准入 Webhook 交互,由于身份验证/授权和访问路径归你连接的服务器所有,因此实际上没有手动配置该文件的替代方法。

对于自托管类别,巧妙构建的 Webhook 准入服务器和拓扑可以利用内置于准入插件中的安全默认值,并具有安全、可移植、零配置的拓扑,该拓扑可从任何 API 服务器工作。

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

如果你构建的 Webhook 准入服务器也是一个扩展 API 服务器,则可以将它作为普通的 API 服务器进行聚合。这具有许多优点

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


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

简而言之:安全的拓扑利用 API 服务器聚合的所有安全机制,并且不需要任何额外的配置。

其他拓扑也是可能的,但需要额外的手动配置以及大量的精力来创建一个安全的设置,尤其是在服务目录之类的扩展 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