为什么需要 Kubernetes 准入控制器

2023-03-18 15:07:32 浏览数 (4)

Kubernetes 准入控制器是集群管理必要功能。这些控制器主要在后台工作,并且许多可以作为编译插件使用,它可以极大地提高部署的安全性。

准入控制器在 API 请求传递到 APIServer 之前拦截它们,并且可以禁止或修改它们。这适用于大多数类型的 Kubernetes 请求。准入控制器在经过适当的身份验证和授权后处理请求。

默认情况下启用了几个准入控制器,因为大多数正常的 Kubernetes 操作都依赖于它们。这些控制器中的大多数都包含一些 Kubernetes 源代码树,并被编译为插件。但是,也可以编写和部署第三方准入控制器。一些说明性示例将在稍后解决这个问题。如需更详细地了解实现准入控制器的细节,请参阅Kubernetes 文档。https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers/

准入控制器工作原理

Kubernetes 控制平面由几个组件组成。其中一个组件是 kube-apiserver,简单的 API server。它公开了一个 REST 端点,用户、集群组件以及客户端应用程序可以通过该端点与集群进行通信。总的来说,它会进行以下操作:

  • 从客户端应用程序(如 kubectl)接收标准 HTTP 请求。
  • 验证传入请求并应用授权策略。
  • 在成功的身份验证中,它能根据端点对象(Pod、Deployments、Namespace 等)和 http 动作(Create、Put、Get、Delete 等)执行操作。
  • 对 etcd 数据存储进行更改以保存数据。
  • 操作完成,它就向客户端发送响应。

现在让我们考虑这样一种情况:在请求经过身份验证后,但在对 etcd 数据存储进行任何更改之前,我们需要拦截该请求。例如:

  • 拦截客户端发送的请求。
  • 解析请求并执行操作。
  • 根据请求的结果,决定对 etcd 进行更改还是拒绝对 etcd 进行更改。

Kubernetes 准入控制器就是用于这种情况的插件。在代码层面,准入控制器逻辑与 API server 逻辑解耦,这样用户就可以开发自定义拦截器(custom interceptor),无论何时对象被创建、更新或从 etcd 中删除,都可以调用该拦截器。

有了准入控制器,从任意来源到 API server 的请求流将如下所示:

根据准入控制器执行的操作类型,它可以分为 3 种类型:

  • Mutating(变更)
  • Validating(验证)
  • Both(两者都有)

Mutating:这种控制器可以解析请求,并在请求向下发送之前对请求进行更改(变更请求)。

例如:AlwaysPullImages

Validating:这种控制器可以解析请求并根据特定数据进行验证。

例如:NamespaceExists

Both:这种控制器可以执行变更和验证两种操作。

例如:CertificateSigning

默认准入控制器

Kubernetes 具有多个内置准入控制器。一个简单的例子,DefaultIngressClass将默认入口类应用到还没有指定类的入口对象。同样,DefaultStorageClass将默认存储类应用到PersistentVolumeClaims还没有的存储类。必须启用此控制器以允许基于存储类的动态存储配置。

准入控制器在维护安全性方面非常有帮助。例如,它们可以减轻对多租户集群的拒绝服务 (DoS) 攻击。考虑LimitRanger插件,顾名思义,它强制限制范围。限制范围以每个命名空间为基础定义资源消耗的强制范围。这可以防止租户耗尽彼此的资源。

另一个问题是所谓的事件泛滥,集群被事件淹没,无法充分处理其他合法请求。对于EventRateLimit此类情况,控制器是一种强大的缓解工具。它的设计使其能够限制每个命名空间或每个用户的事件发生率。

此外,还有两个重要的控制器允许开发人员将他们的准入插件作为 webhook 运行,以便在运行时进行配置。MutatingAdmissionWebhook使 webhook 能够修改提交的资源,通常用于强制执行自定义默认值。同时,ValidatingAdmissionWebhook控制器启用已注册的 webhook 来决定处于最终状态的 API 验证资源是继续通过还是被完全丢弃。

第三方准入控制器

Kubernetes 有两个领先的开源策略引擎:Open Policy Agent (OPA) Gatekeeper 和 Kyverno。

这两个引擎都是对云原生计算基金会 (CNCF) 的捐赠,该基金会致力于云原生技术的标准化和推广。它在其上级组织 Linux 基金会下运作。值得注意的是,Kubernetes 是一个 CNCF 项目。

Kyverno 的主要优势在于它不需要学习额外的语言。它的所有策略都定义为 Kubernetes 资源。相反,Gatekeeper 利用 OPA 的声明性语言 Rego。Gatekeeper 是更大的 OPA 系统的一部分,而 Kyverno 是 Kubernetes 的独立项目。总而言之,Gatekeeper 是更 成熟的项目,但 Kyverno 的学习曲线更小。

使用控制器的目的

在物理机上执行多项服务的最初方法是让虚拟机共享同一主机,并使用管理程序分隔它们的操作系统。一个复杂的云配置系统(例如,由 A**定义的那些)使系统保持独立,并确保租户不会意外或故意伤害彼此。

Kubernetes 最初被设计为单个组织或用户可以使用的协作系统。此外,它比其他云系统之间的依赖更强。然而,随着 Kubernetes 在可用部署的多样性和处理更大集群规模的能力方面的增长,制定确保单个用户不会干扰系统操作的策略变得越来越重要。

为了使这个过程自动化,组织需要一个策略系统。Kubernetes 具有一些内置支持,但它不具备功能齐全的专用策略引擎的能力。

自定义准入控制器

您可以使用 Webhook 使用任何可以处理 HTTP 请求并返回 Javascript 对象表示法 (JSON) 的语言来编写自定义准入控制器逻辑。例如,Go、Python 或 Ruby 都是有效的选项。

下面的示例演示了如何为自定义准入控制器设置 webhook。它类似于上面介绍的 LimitRanger,它拒绝对超过资源命名空间限制的 Pod 的请求。请注意,此示例不包括完整的控制器源代码,但您可以查阅有关准入 webhook 服务器的 Kubernetes 文档以深入了解该过程。https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#experimenting-with-admission-webhooks

首先,使用配置对象注册 webhook:

代码语言:javascript复制
apiVersion: admissionregistration.k8s.io/v1beta1
kind: ValidatingWebhookConfiguration
metadata:
  name: mywebhook
webhooks:
  - name: mywebhook
    clientConfig:
      service:
        name: mywebhook
        namespace: project1
        path: "/hook"
    rules:
      - operations: ["CREATE"]
        apiVersions: ["v1"]
        apiGroups: [""]
        resources: ["pods"]

这说明 ValidatingWebhookController webhook。它还指定要访问的服务以及在运行服务器的容器上探测的路径。它还确定在决定是否调用 webhook 时要应用哪些规则。此示例侧重于创建新 pod。

实际上,在集群上创建此资源将在最后发生 - 在为 webhook 服务器创建部署之后。部署包含与上述文件中的定义匹配的服务:

代码语言:javascript复制
apiVersion: v1
kind: Service
metadata:
  name: mywebhook
  namespace: project1
spec:
  - ports:
      name: mywebhook
      port: 80
      targetPort: 8000

下面是 webhook 的示例部署,与常规应用程序没有什么不同。我们不会探索使用传输层安全 (TLS) 来保护通信,但强烈建议这样做。

代码语言:javascript复制
apiVersion: apps/v1
kind: Deployment
metadata:
  name: mywebhook
  namespace: project1
spec:
  selector:
    matchLabels:
      app: mywebhook
  template:
    metadata:
      labels:
        app: mywebhook
    spec:
      containers:
        - image: webhook1:latest
          name: mywebhook

新的 Pod 请求提交给 Kubernetes 并通过 Kubernetes 传递后ValidatingWebhook,相关信息会作为POST请求发送到配置的 URL 路径,并包含一个 JSON 对象供 webhook 处理。

验证是否正常工作

部署完 webhook 服务器并完成配置之后,我们还需要对它进行测试和验证,

用 kubectl create -f examples/.yaml 创建 Pod。如果是前两种情况,我们可以通过检查日志来验证 Pod 运行时的用户 ID,例如:

代码语言:javascript复制
$ kubectl create -f examples/pod-test.yaml
$ kubectl logs pod-test
代码语言:javascript复制
{
  "apiVersion": "admission.k8s.io/v1",
  "kind": "AdmissionReview",
  "response": {
    "uid": "6ce7a33c-ea67-40e5-9cc8-f710d31985dc",
    "allowed": true
  }
}

当然我们也可以自定义更复杂的准入控制器,明确某些 Pod 必须以非 root 身份运行,如果不对,那么就可以拒绝对象创建请求。

自定义准入控制器可以像这个示例一样简单,也可以复杂得多。如需更全面的概述,请参阅admission webhook 文档中的信息。https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#experimenting-with-admission-webhooks

参考文献

  • https://kubernetes.io/docs/reference/access-authn-authz/admission-controllers
  • https://docs.okd.io/latest/architecture/additional_concepts/dynamic_admission_controllers.html
  • https://kubernetes.io/blog/2018/01/extensible-admission-is-beta/
  • https://medium.com/ibm-cloud/diving-into-kubernetes-mutatingadmissionwebhook-6ef3c5695f74
  • https://github.com/kubernetes/kubernetes/blob/v1.10.0-beta.1/test/images/webhook/main.go
  • https://github.com/istio/istio
  • https://www.stackrox.com/post/2019/
  • https://zhuanlan.zhihu.com/p/106206871
  • https://blog.csdn.net/FL63Zv9Zou86950w/article/details/114005897

1 人点赞