本文发表已超过一年。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已不再准确。

OPA Gatekeeper:Kubernetes 的策略与治理

可利用 Open Policy Agent Gatekeeper 项目来帮助在 Kubernetes 环境中强制执行策略并加强治理。本文将带你了解该项目的目标、历史和当前状态。

以下 Kubecon EU 2019 会议的录音是开始使用 Gatekeeper 的绝佳起点:

动机

如果你的组织一直在运行 Kubernetes,你可能一直在寻找控制最终用户在集群上可以做什么的方法,以及确保集群符合公司策略的方法。这些策略可能旨在满足治理和法律要求,或者强制执行最佳实践和组织惯例。使用 Kubernetes,如何在不牺牲开发敏捷性和运营独立性的情况下确保合规性?

例如,你可以强制执行以下策略:

  • 所有镜像必须来自批准的仓库
  • 所有 ingress 主机名必须全局唯一
  • 所有 Pod 都必须有资源限制
  • 所有命名空间必须有一个列出联系人的标签

Kubernetes 允许通过准入控制器 Webhook 将策略决策与 API 服务器解耦,以便在准入请求持久化为 Kubernetes 中的对象之前进行拦截。Gatekeeper 的创建是为了让用户通过配置而非代码来定制准入控制,并了解集群的状态,而不仅仅是准入时正在评估的单个对象。Gatekeeper 是一个可定制的 Kubernetes 准入 Webhook,它强制执行由 Open Policy Agent (OPA) 执行的策略,OPA 是一个由 CNCF 托管的云原生环境策略引擎。

演进

在深入了解 Gatekeeper 的当前状态之前,让我们先看看 Gatekeeper 项目是如何演变的。

  • Gatekeeper v1.0 - 使用 OPA 作为准入控制器,并通过 kube-mgmt sidecar 强制执行基于 configmap 的策略。它提供校验和修改准入控制。由 Styra 捐赠。
  • Gatekeeper v2.0 - 使用 Kubernetes 策略控制器作为准入控制器,并通过 OPA 和 kube-mgmt sidecar 强制执行基于 configmap 的策略。它提供校验和修改准入控制以及审计功能。由 Microsoft 捐赠。
  • Gatekeeper v3.0 - 准入控制器集成了 OPA 约束框架,以强制执行基于 CRD 的策略,并允许声明式配置的策略可靠地共享。使用 kubebuilder 构建,它提供校验,并最终提供修改(待实现)准入控制和审计功能。这使得可以为 Rego 策略创建策略模板,将策略创建为 CRD,并将审计结果存储在策略 CRD 上。该项目由 Google、Microsoft、Red Hat 和 Styra 协作开发。

Gatekeeper v3.0 特性

现在,让我们更仔细地了解 Gatekeeper 的当前状态以及如何利用所有最新特性。考虑一个组织,他们希望确保集群中的所有对象都包含作为对象标签一部分提供的部门信息。如何使用 Gatekeeper 实现这一点?

校验准入控制

一旦所有 Gatekeeper 组件都在你的集群中安装完成,当集群中的资源被创建、更新或删除时,API 服务器将触发 Gatekeeper 准入 Webhook 来处理准入请求。

在校验过程中,Gatekeeper 充当 API 服务器和 OPA 之间的桥梁。API 服务器将强制执行 OPA 执行的所有策略。

策略和约束

随着 OPA 约束框架的集成,约束是作者声明系统需要满足给定要求集的声明。每个约束都使用 Rego 编写,Rego 是 OPA 使用的一种声明式查询语言,用于枚举违反系统预期状态的数据实例。所有约束都按逻辑 AND 进行评估。如果一个约束不满足,则整个请求将被拒绝。

在定义约束之前,你需要创建一个约束模板,该模板允许人们声明新的约束。每个模板既描述了强制执行约束的 Rego 逻辑,也描述了约束的 schema,其中包括 CRD 的 schema 以及可以传递给约束的参数,非常类似于函数的参数。

例如,这是一个约束模板 CRD,它要求在任意对象上存在某些标签。

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
        listKind: K8sRequiredLabelsList
        plural: k8srequiredlabels
        singular: k8srequiredlabels
      validation:
        # Schema for the `parameters` field
        openAPIV3Schema:
          properties:
            labels:
              type: array
              items: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8srequiredlabels

        deny[{"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])
        }        

在集群中部署约束模板后,管理员现在可以按照约束模板的定义创建单个约束 CRD。例如,这是一个约束 CRD,它要求所有命名空间上都存在标签 hr

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

同样,可以很容易地从同一个约束模板创建另一个约束 CRD,它要求所有命名空间上都存在标签 finance

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

如你所见,使用约束框架,我们可以通过约束模板可靠地共享 Rego,使用 match 字段定义强制范围,并为约束提供用户定义的参数,以便为每个约束创建自定义行为。

审计

审计功能允许定期根据集群中强制执行的约束评估复制的资源,以检测预先存在的配置错误。Gatekeeper 将审计结果存储为相关约束的 status 字段中列出的违规项。

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: ns-must-have-hr
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
  parameters:
    labels: ["hr"]
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

数据复制

审计要求在将 Kubernetes 资源复制到 OPA 后,才能根据强制执行的约束进行评估。需要访问集群中除正在评估对象之外的对象的约束也需要数据复制。例如,强制执行 ingress 主机名唯一性的约束必须能够访问集群中的所有其他 ingress。

要配置需要复制的 Kubernetes 数据,请创建一个包含要复制到 OPA 的资源的 sync config 资源。例如,以下配置将所有命名空间和 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"

未来规划

Gatekeeper 项目背后的社区将专注于提供修改准入控制以支持修改场景(例如:在创建新资源时自动使用部门信息标注对象),支持外部数据以将集群外部的上下文注入到准入决策中,支持 dry run 以在强制执行策略之前查看策略对集群中现有资源的影响,以及更多审计功能。

如果你有兴趣了解更多关于该项目的信息,请查看 Gatekeeper 仓库。如果你有兴趣帮助定义 Gatekeeper 的方向,请加入 OPA Slack 上的 #kubernetes-policy 频道,并参加我们的每周会议,讨论开发、问题、用例等。