本文已超过一年。较旧的文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
可扩展准入控制进入 Beta 阶段
在这篇文章中,我们将回顾 Kubernetes API 服务器中的一个功能,它允许您实现任意控制决策,并且在 Kubernetes 1.9 中已经相当成熟。
API 服务器处理的准入阶段是保护 Kubernetes 集群的最强大工具之一,它通过限制可以创建的对象来工作,但它一直局限于编译代码。在 1.9 版本中,我们将准入 Webhook 提升到 Beta 阶段,允许您利用 API 服务器进程之外的准入控制。
什么是准入控制?
准入控制(Admission) 是 处理 API 服务器请求 的一个阶段,它发生在资源持久化之前,但在授权之后。准入控制可以访问与授权相同的信息(用户、URL 等)以及 API 请求的完整正文(对于大多数请求)。
准入阶段由独立的插件组成,每个插件都专注于特定领域,并具有对其检查内容进行语义理解的能力。示例包括:PodNodeSelector(影响调度决策)、PodSecurityPolicy(阻止容器特权升级)和 ResourceQuota(强制执行每个 Namespace 的资源配额)。
准入控制分为两个阶段
- 修改(Mutation),允许修改请求体内容本身以及拒绝 API 请求。
- 校验(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 服务器(如 metrics、service-catalog 或 kube-projects)的准入链中,而无需重新编译它们。这两种准入 Webhook 都运行在各自链的末端,并具有与编译型准入插件相同的能力和限制。
它们有什么用?
Webhook 准入插件允许对任何 API 服务器上的任何资源进行修改和校验,因此其应用范围非常广泛。一些常见的用例包括:
- 修改诸如 Pod 之类的资源。Istio 曾讨论过使用这种方式将 Sidecar 容器注入到 Pod 中。您也可以编写一个插件,强制将镜像标签解析为镜像 SHA。
- 名称限制。在多租户系统中,预留 Namespace 已成为一种用例。
- 复杂的 CustomResource 校验。由于可以看到整个对象,聪明的准入插件可以对依赖字段(A 要求 B)甚至外部资源进行复杂校验(与 LimitRanges 对比)。
- 安全响应。如果您强制将镜像标签解析为镜像 SHA,您可以编写一个准入插件来阻止某些 SHA 的镜像运行。
注册
两种类型的 Webhook 准入插件都在 API 中注册,并且所有 API 服务器(kube-apiserver 和所有扩展 API 服务器)共享它们的通用配置。在注册过程中,一个 Webhook 准入插件描述了:
- 如何连接到 Webhook 准入服务器
- 如何验证 Webhook 准入服务器(它真的是我期望的那个服务器吗?)
- 将数据发送到该服务器的哪个位置(哪个 URL 路径)
- 它将处理哪些资源和哪些 HTTP 动词
- 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 服务器是否有权限发起请求。连接主要分为三类:
- 从 kube-apiserver 或扩展 apiservers 到外部托管的准入 Webhook(未托管在集群中的 Webhook)
- 从 kube-apiserver 到自托管的准入 Webhook
- 从扩展 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-apiserver 和 kubernetes-namespace-reservation 项目,它们提供了库以及如何构建您自己的安全且可移植的 Webhook 准入服务器的示例。
通过在 1.9 版本中引入准入 Webhook,我们使 Kubernetes 更能适应您的需求。我们希望这项由 Red Hat 和 Google 共同推动的工作能够支持更多的负载和生态系统组件。(Istio 就是一个例子。)现在是时候尝试一下了!
如果您有兴趣提供反馈或为此领域做出贡献,请加入我们的 SIG API machinery。