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

可扩展准入进入 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 的任何扩展 apiserver(例如 metricsservice-catalogkube-projects)添加变更和验证准入插件,而无需重新编译它们。两种类型的准入 webhook 都运行在各自链的末尾,并具有与编译准入插件相同的能力和限制。

它们有什么用?

Webhook 准入插件允许对任何 API 服务器上的任何资源进行变更和验证,因此可能的应用非常广泛。一些常见的用例包括:

  1. Pod 等资源的变更。Istio 曾讨论过通过这种方式将 Sidecar 容器注入到 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 准入服务器不可用时该怎么做。选项是 “Ignore”(失败开放)或 “Fail”(失败关闭)。失败开放会导致所有客户端的行为不可预测。

身份验证和信任

由于 webhook 准入插件具有很大的权限(请记住,它们可以查看发送给它们的任何请求的 API 资源内容,并且对于变更插件可能会修改它们),因此考虑以下几点非常重要:

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

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

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

如果您将您的 webhook 准入服务器也构建为扩展 API 服务器,那么就可以像普通的 API 服务器一样聚合它。这有许多优点:

  • 您的 webhook 将像默认 kube-apiserver 服务 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 服务器不会将其服务帐户令牌泄露给您的 webhook,因为它们通过 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