本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
可扩展准入进入 Beta 阶段
在这篇文章中,我们将回顾 Kubernetes API 服务器中可用的一个特性,它允许您实现任意控制决策,并且在 Kubernetes 1.9 中已经相当成熟。
API 服务器处理的准入阶段是保护 Kubernetes 集群最强大的工具之一,通过限制可以创建的对象,但它一直局限于编译代码。在 1.9 中,我们将准入 webhook 提升到 Beta 阶段,允许您从 API 服务器进程外部利用准入。
什么是准入?
准入是处理 API 服务器请求的一个阶段,发生在资源持久化之前,但在授权之后。准入可以访问与授权相同的信息(用户、URL 等)以及 API 请求的完整正文(对于大多数请求)。
准入阶段由独立的插件组成,每个插件都专注于特定的领域,并对其所检查的内容具有语义知识。示例包括:PodNodeSelector(影响调度决策)、PodSecurityPolicy(防止特权升级容器)和 ResourceQuota(按命名空间强制执行资源分配)。
准入分为两个阶段
- 变更:允许修改正文内容本身以及拒绝 API 请求。
- 验证:允许内省查询和拒绝 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(例如 metrics、service-catalog 或 kube-projects)添加变更和验证准入插件,而无需重新编译它们。两种类型的准入 webhook 都运行在各自链的末尾,并具有与编译准入插件相同的能力和限制。
它们有什么用?
Webhook 准入插件允许对任何 API 服务器上的任何资源进行变更和验证,因此可能的应用非常广泛。一些常见的用例包括:
- Pod 等资源的变更。Istio 曾讨论过通过这种方式将 Sidecar 容器注入到 Pod 中。您还可以编写一个插件,强制将镜像标签解析为镜像 SHA。
- 名称限制。在多租户系统中,预留命名空间已成为一个用例。
- 复杂的 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 服务器何时应该调用此准入插件。在此示例中,仅用于命名空间的创建。您可以在此处指定任何资源,因此指定 serviceinstances.servicecatalog.k8s.io
的创建也是合法的。
第 22 行:failurePolicy
- 说明如果 webhook 准入服务器不可用时该怎么做。选项是 “Ignore”(失败开放)或 “Fail”(失败关闭)。失败开放会导致所有客户端的行为不可预测。
身份验证和信任
由于 webhook 准入插件具有很大的权限(请记住,它们可以查看发送给它们的任何请求的 API 资源内容,并且对于变更插件可能会修改它们),因此考虑以下几点非常重要:
- 各个 API 服务器如何验证其与 webhook 准入服务器的连接
- webhook 准入服务器如何精确地验证哪个 API 服务器正在与其联系
- 该特定 API 服务器是否具有发出请求的授权 有三种主要的连接类别
- 从 kube-apiserver 或 extension-apiservers 到外部托管的准入 webhook(未在集群中托管的 webhook)
- 从 kube-apiserver 到自托管的准入 webhook
- 从 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-apiserver 和 kubernetes-namespace-reservation 项目,以获取该库以及如何构建自己的安全且可移植的 webhook 准入服务器的示例。
通过 1.9 中引入的准入 webhook,我们使 Kubernetes 更能适应您的需求。我们希望这项由 Red Hat 和 Google 共同推动的工作能够支持更多的负载和生态系统组件。(Istio 就是一个例子。)现在是尝试的好时机!
如果您有兴趣提供反馈或为此领域做出贡献,请加入我们 SIG API machinery。