在您的 Kubernetes 集群上实施治理

使用 OPA Gatekeeper 为您的 Kubernetes 集群创建和实施策略和治理,以便您应用到集群的资源符合该策略。
47 位读者喜欢这篇文章。
Kubernetes

Jason Baker。CC BY-SA 4.0。

当您使用 Kubernetes 时,它会逐渐成为您的生产圣殿。您投入时间和资源来开发和培育它,并且您自然而然地开始寻找方法来控制组织中的 Kubernetes 最终用户。它可以做什么? 它可以创建哪些资源? 它可以以特定方式标记两个部署吗? 我们应该遵循哪些最佳实践?

认识一下 OPA Gatekeeper。本文将向您展示如何使用它来为您的 Kubernetes 集群创建和实施策略和治理,以便您应用到集群的资源符合该策略。

为什么要使用 OPA Gatekeeper?

OPA Gatekeeper 为您提供两个关键能力

  • 控制最终用户可以在集群上做什么
  • 在集群中实施公司策略

然而,Gatekeeper 的真正力量在于它对组织的影响。Gatekeeper 有助于减少 DevOps 管理员和开发人员自身之间的依赖性。您可以自动化组织策略的实施,这使 DevOps 工程师无需担心开发人员犯错。它还为开发人员提供关于哪里出错以及他们需要更改什么的即时反馈。

OPA Gatekeeper 是 Open Policy Agent 的一个子项目,专门用于在 Kubernetes 集群中实施 OPA。(有趣的事实:该项目是 Google、Microsoft、Red Hat 和 Styra 之间的合作。)本文需要对 Kubernetes 和 OPA 都有基本的了解,如果您已经熟悉 OPA,请随意跳过此部分并继续下一部分。

什么是 OPA?

OPA 就像一个超级引擎。您可以在其中编写所有策略,然后使用每个输入执行它,以检查它是否违反任何策略,如果违反,以何种方式违反。

OPA 背后的主要思想是将策略决策逻辑与策略实施用法分离的能力。

假设您在多服务架构中工作。您可能需要制定策略决策,例如,当微服务接收到 API 请求时(例如授权)。该逻辑基于您组织中预测的规则,因此在这种情况下,您可以将所有决策逻辑卸载并统一到专用服务:OPA。

如何使用 OPA

  1. 与 OPA 集成: 如果您的服务是用 Go 编写的,您可以将 OPA 作为包嵌入到您的项目中。否则,您可以将 OPA 部署为主机级守护程序。
  2. 编写和存储您的策略: 要在 OPA 中定义您的策略,您需要用 Rego 编写它们并将它们发送到 OPA。这样,每当您使用 OPA 进行策略实施时,OPA 都会针对这些策略查询输入。
  3. 请求策略评估: 当您的应用程序需要制定策略决策时,它将使用 JSON 发送 API 查询请求,其中包含通过 HTTP 传输的所有必需数据。

如果您想阅读更多关于 OPA 以及如何使用它的信息,并了解更多关于其功能的信息,我建议阅读 OPA 的文档

Kubernetes 准入 Webhook

在我们深入了解 Gatekeeper 的底层工作原理之前,我们首先需要了解 Kubernetes 准入 Webhook。

当请求进入 Kubernetes API 时,它在执行之前会经过一系列步骤。

  1. 请求已通过身份验证和授权。
  2. 请求由一系列特殊的 Kubernetes Webhook 集合(称为准入控制器)处理,这些控制器可以修改、更改和验证请求中的对象。
  3. 请求被持久化到 etcd 以供执行。

Kubernetes 准入控制器是集群的中间件。它们控制什么可以进入集群。准入控制器管理请求过多资源的部署、实施 Pod 安全策略,甚至阻止部署易受攻击的镜像。

准入控制器的底层是一系列预定义的 HTTP 回调(即 Webhook),它们拦截 Kubernetes API 并在请求通过身份验证和授权后处理请求。

准入控制器有两种类型

  • MutatingAdmissionWebhook(变更准入 Webhook)
  • ValidatingAdmissionWebhook(验证准入 Webhook)

变更准入控制器首先被调用,因为它们的工作是强制执行自定义默认值,并在必要时修改发送到 API 服务器的对象。在完成所有修改并且传入对象已验证后,将调用验证准入控制器,并且可以拒绝请求以强制执行自定义策略。请注意,某些控制器既是验证又是变更的。如果其中一个拒绝请求,则请求将失败。

它功能强大、免费,您可能已经在使用它

一些准入控制器是开箱即用的预配置的,您可能已经在使用它们。例如,LimitRanger 是一个准入 Webhook,它可以防止 Pod 在集群资源耗尽时运行。有关 MutatingAdmissionWebhook 的更多信息,请参阅 IBM Cloud 博客上的“深入了解 Kubernetes MutatingAdmissionWebhooks”。

动态准入控制

您可能想知道为什么准入控制器是通过 Webhook 实现的。这就是准入控制器的亮点所在,也是动态准入控制发挥作用的地方。

Webhook 使开发人员可以自由灵活地自定义任何资源上的“创建”、“更新”或“删除”等操作的准入逻辑。这非常有用,因为几乎每个组织都需要添加/调整其策略和最佳实践。

密钥问题源于准入控制器的运行方式。修改准入控制器需要将它们重新编译到 Kube-apiserver 中,并且只能在 apiserver 激活时启用它们。使用 Webhook 实现准入控制器允许管理员创建自定义 Webhook,并将变更或验证准入 Webhook 添加到准入 Webhook 链中,而无需重新编译它们。Kubernetes apiserver 执行已注册的 Webhook,这些 Webhook 是标准接口。

有关动态准入控制的更多信息,我建议阅读 K8s 文档

OPA Gatekeeper 的工作原理

Gatekeeper 充当 Kubernetes API 服务器和 OPA 之间的桥梁。实际上,这意味着 Gatekeeper 检查进入集群的每个请求,以查看它是否违反任何预定义的策略。如果违反,apiserver 将拒绝它。

在底层,Gatekeeper 使用动态准入控制 API 与 Kubernetes 集成,并作为可自定义的 ValidatingAdmission Webhook 安装。一旦安装完成,每当集群中的资源被创建、更新或删除时,apiserver 就会触发它。

由于 Gatekeeper 通过 OPA 运行,因此所有策略都必须用 Rego 编写。幸运的是,Kubernetes 通过使用 OPA Constraints Framework 涵盖了这一点。

约束是一个 CRD,表示我们想要在特定类型的资源上实施的策略。当调用 ValidatingAdmission 控制器时,Gatekeeper Webhook 会评估所有约束,并将请求连同要实施的策略发送给 OPA。所有约束都作为逻辑进行评估,如果某个约束不满足,则整个请求将被拒绝。

如何使用 OPA Gatekeeper:一个简单的场景

假设您想要强制执行没有所有者标签的资源。

首先,在您的集群上安装 Gatekeeper

kubectl apply -f 
https://raw.githubusercontent.com/open-policy-agent/gatekeeper \
/release-3.4/deploy/gatekeeper.yaml

您可以通过运行以下命令来测试它

kubectl get pods --all-namespaces

如果一切正常,您应该会看到一个名为 gatekeeper-controller-managergatekeeper-system 命名空间下运行的 Pod。

应用 ConstraintTemplate,这将要求约束描述的所有标签都存在

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        # Schema for the `parameters` field
        openAPIV3Schema:
          properties:
            labels:
              type: array
              items: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredlabels
        violation[{"msg": msg, "details": {"missing_labels": missing}}] {
          provided := {label | input.review.object.metadata.labels[label]}
          required := {label | label := input.parameters.labels[_]}
          missing := required - provided
          count(missing) > 0
          msg := sprintf("you must provide labels: %v", [missing])
        }

应用约束,该约束将使用您之前创建的 K8sRequiredLabel,将其范围限定为命名空间,因此每个命名空间都将被强制具有所有者标签

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: ns-must-have-owner
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
  parameters:
    labels: ["owner"]

审计

正如我喜欢说的那样,集群是您的生产圣殿,因此您需要持续监控以检测对预先存在的不当配置的补救措施。这就是审计的用武之地。

当调用 Gatekeeper Webhook 时,它会将审计结果作为违规行为存储在相关约束的状态字段中。例如

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: ns-must-have-owner
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
  parameters:
    labels: ["owner"]
status:
  auditTimestamp: "2019-08-06T01:46:13Z"
  byPod:
  - enforced: true
    id: gatekeeper-controller-manager-0
  violations:
  - enforcementAction: deny
    kind: Namespace
    message: 'you must provide labels: {"hr"}'
    name: default
  - enforcementAction: deny
    kind: Namespace
    message: 'you must provide labels: {"hr"}'
    name: gatekeeper-system
  - enforcementAction: deny
    kind: Namespace
    message: 'you must provide labels: {"hr"}'
    name: kube-public
  - enforcementAction: deny
    kind: Namespace
    message: 'you must provide labels: {"hr"}'
    name: kube-system

也许您想要创建一个策略来强制执行所有 Ingress 主机名都是唯一的。在这种情况下,您将需要使用审计功能。但是,强制执行唯一 Ingress 主机名的约束必须能够访问除正在评估的对象之外的所有 Ingress。这种情况需要将数据复制到 OPA 中。

一个简单的场景

默认情况下,审计不需要复制,但是有两种方法可以手动配置数据复制

  1. 使用 OPA 缓存机制: 将标志 audit-from-cache 设置为 true,这将使 OPA 缓存可以用作所有审计查询的真实来源。任何对象都必须先缓存,然后才能对其进行约束违规审计。
  2. 使用 Kubernetes config 资源: 创建一个 config 资源,并在 syncOnly 中定义您要复制到 OPA 的资源。不用担心,更新 syncOnly 应该会动态更新所有同步的对象。

例如,以下配置将所有命名空间和 Pod 资源复制到 OPA

apiVersion: config.gatekeeper.sh/v1alpha1
kind: Config
metadata:
  name: config
  namespace: "gatekeeper-system"
spec:
  sync:
    syncOnly:
      - group: ""
        version: "v1"
        kind: "Namespace"
      - group: ""
        version: "v1"
        kind: "Pod"

Dry Run(试运行)

您可以更进一步,在添加和强制执行约束之前对其进行测试。这就是试运行功能发挥作用的地方。

试运行提供与审计相同的功能,使您能够部署约束并查看状态中报告的所有约束违规行为,而无需进行实际更改。要为试运行模式配置约束,您只需在约束的规范中使用 enforcementAction: dryrun 标签。默认情况下,enforcementAction 设置为“deny”,因为默认行为是拒绝任何违规的准入请求。

例如

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: ns-must-have-owner
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
  parameters:
    labels: ["owner"]
status:
  auditTimestamp: "2019-08-06T01:46:13Z"
  byPod:
  - enforced: true
    id: gatekeeper-controller-manager-0
  violations:
  - enforcementAction: dryrun
    kind: Namespace
    message: 'you must provide labels: {"hr"}'
    name: default
  - enforcementAction: deny
    kind: Namespace
    message: 'you must provide labels: {"hr"}'
    name: gatekeeper-system
  - enforcementAction: deny
    kind: Namespace
    message: 'you must provide labels: {"hr"}'
    name: kube-public
  - enforcementAction: deny
    kind: Namespace
    message: 'you must provide labels: {"hr"}'
    name: kube-system

放眼全局

现在您的生产环境安全可靠,我想暂停一下,问您一个问题:Gatekeeper 与单元测试有何不同?就我个人而言,当我第一次听说 Gatekeeper 时,我不明白,“为什么它必须只关于生产环境?” 毕竟,理想情况下,难道这一切不都是通过相同的管道进行的吗?

作为一名开发人员,将 Kubernetes 策略视为单元测试非常有意义,这让我感到疑惑,我的代码和 Kubernetes 资源之间有什么区别?

认识 Datree。

Datree 是一个命令行界面 (CLI) 解决方案,使您能够针对 YAML 文件测试策略。CLI 附带所有 Kubernetes 最佳实践的内置策略,以及用于您创建的任何策略的集中式管理解决方案。在 CI 中或作为 precommit 钩子运行 Datree,并像使用本地测试库一样使用它。它是一个开源项目,因此是免费的。您可以在 GitHub 上找到该项目,并在 Datree 的网站上获取所有信息。

我鼓励您查看我们的代码并提供您的反馈,以便它可以成为您生产环境的最佳解决方案。

总结

在我看来,仅仅因为 Kubernetes 允许您部署可以访问主机网络命名空间的 Pod,例如,并不意味着这是一个好主意。

当您采用 Kubernetes 时,您也在改变您组织的文化。DevOps 不是一蹴而就的事情;它是一个过程,了解如何管理它非常重要,尤其是在规模方面。

我希望这将启发您开始思考您的策略以及如何在您的组织内实施它们。


本文最初发表在 Datree 的博客上,并经许可重新发表。

接下来阅读什么
User profile image.
规划和设计应用程序架构,以及研究和采用开发最佳实践和编码标准是我的真正热情。在过去的四年中,我的工作主要围绕理解全栈开发过程的每个部分以及了解应用程序的生态系统。

评论已关闭。

Creative Commons 许可协议本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.