编写自定义限制条件模板

本页面介绍了如果您找不到适合您的需求的预先写好的限制条件模板,可以如何编写自定义限制条件模板,以及如何使用该模板扩展政策控制器

本页面适用于想要提供并维护自动化以进行审核或强制执行,并使用声明式配置模板,从而确保云平台中运行的所有资源满足组织合规性要求的 IT 管理员和运维人员。如需详细了解我们在 Google Cloud 内容中提及的常见角色和示例任务,请参阅常见的 GKE Enterprise 用户角色和任务

Policy Controller 政策使用 OPA 限制条件框架进行描述,并采用 Rego 进行编写。政策可以评估 Kubernetes 对象的任何字段。

使用 Rego 编写政策是一项专门技能。因此,默认情况下,系统会安装常见限制条件模板库。创建限制条件时,您可能可调用这些限制条件模板。如果您有特殊需要,则可以创建您自己的限制条件模板。

通过限制条件模板,您可以将政策逻辑与其特定要求分离,以进行重复使用和委任。您可以使用第三方开发的限制条件模板(如开源项目、软件供应商或监管专家)来创建限制条件。

准备工作

限制条件模板示例

以下是一个限制条件模板示例,该模板拒绝名称与限制条件创建者提供的值匹配的所有资源。本页的其余部分讨论了模板的内容,并在此过程中突出显示一些重要概念。

如果您将 Config Sync 与分层代码库搭配使用,我们建议您在 cluster/ 目录中创建自己的限制条件。

apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
  name: k8sdenyname
spec:
  crd:
    spec:
      names:
        kind: K8sDenyName
      validation:
        # Schema for the `parameters` field
        openAPIV3Schema:
          properties:
            invalidName:
              type: string
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8sdenynames
        violation[{"msg": msg}] {
          input.review.object.metadata.name == input.parameters.invalidName
          msg := sprintf("The name %v is not allowed", [input.parameters.invalidName])
        }

限制条件示例

以下是一个限制条件示例,您可以实施该限制条件来拒绝所有名为 policy-violation 的资源:

apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sDenyName
metadata:
  name: no-policy-violation
spec:
  parameters:
    invalidName: "policy-violation"

限制条件模板的组成部分

限制条件模板有两个重要部分:

  • 您希望用户创建的限制条件的架构。限制条件模板的架构存储在 crd 字段中。

  • 评估限制条件时执行的 Rego 源代码。模板的 Rego 源代码存储在 targets 字段中。

架构(crd 字段)

CRD 字段是用于创建 Kubernetes 自定义资源定义(其中定义了 Kubernetes API 服务器的限制条件资源)的蓝图。您只需要填充以下字段。

字段 说明
spec.crd.spec.names.kind 限制条件的种类。小写时,此字段的值必须等于 metadata.name
spec.crd.spec.validation.openAPIV3Schema

限制条件资源的 spec.parameters 字段的架构(Policy Controller 会自动定义限制条件的架构的其余部分)。它遵循与常规 CRD 资源相同的规则。

将限制条件模板前缀命名为 K8s 是一种惯例,以避免与其他其他类型的限制条件模板发生冲突,例如定位 Google Cloud 资源的 Forseti 模板。

Rego 源代码(targets 字段)

以下部分详细介绍了 Rego 源代码。

位置

Rego 源代码存储在 spec.targets 字段下,其中 targets 是采用以下格式的对象的数组:

{"target": "admission.k8s.gatekeeper.sh","rego": REGO_SOURCE_CODE, "libs": LIST_OF_REGO_LIBRARIES}
  • target:告知 Policy Controller 我们正在查看的系统(在本例中为 Kubernetes);targets 中只允许有一个条目。
  • rego:限制条件的源代码。
  • libs:可用于限制条件模板使用的 Rego 代码库列表(可选);它旨在简化共享库的使用,并且不在本教程的讨论范围之内。

源代码

以下是上述限制条件的 Rego 源代码:

package k8sdenynames

violation[{"msg": msg}] {
   input.review.object.metadata.name == input.parameters.invalidName
   msg := sprintf("The name %v is not allowed", [input.parameters.invalidName])
}

注意事项:

  • OPA(Rego 的运行时环境)需要 package k8sdenynames。系统会忽略该值。
  • Policy Controller 调用来查看是否存在任何违规行为的 Rego 规则称为 violation。如果此规则匹配,则发生违反限制条件的情况。
  • violation 规则具有签名 violation[{"msg": "violation message for the user"}],其中 "msg" 是返回给用户的违规消息。
  • 提供给限制条件的参数在关键字 input.parameters 下可用。
  • request-under-test 存储在关键字 input.review 下。

关键字 input.review 包含以下字段。

字段 说明
uid 特定请求的唯一 ID;它在审核期间无法使用。
kind

object-under-test 的种类信息。其格式如下:

  • kind:资源种类
  • group:资源组
  • version:资源版本
name 资源名称。 如果用户依赖 API 服务器在 CREATE 请求上生成名称,则资源名称可能会为空。
namespace 资源命名空间(不适用于集群范围内的资源)。
operation 所请求的操作(例如,CREATE 或 UPDATE)在审核期间不可用。
userInfo

发出请求的用户信息在审核期间不可用。其格式如下:

  • username:发出请求的用户
  • uid:用户的 UID。
  • groups:用户所属的群组列表
  • extra:Kubernetes 提供的任何其他用户信息
object 用户尝试修改或创建的对象。
oldObject 对象的原始状态;它仅适用于 UPDATE 操作。
dryRun 不论此请求是否由 kubectl --dry-run 调用;其在审核期间都不可用。

编写参照限制条件模板

参照限制条件模板是允许用户将一个对象相对于其他对象进行限制的模板。此模板的一个示例可能是,“不允许在已知存在匹配的入口之前创建 Pod”。另一个示例可能是,“不允许两个服务具有相同的主机名”。

借助 Policy Controller,您可以通过查看 API 服务器中用户提供的一组资源来编写参照限制条件。修改资源后,Policy Controller 会将其缓存到本地,以便 Rego 源代码可以轻松地引用它。Policy Controller 在 data.inventory 关键字下使此缓存可用。

集群范围的资源缓存在以下位置:

data.inventory.cluster["GROUP_VERSION"]["KIND"]["NAME"]

例如,可在以下位置找到名为 my-favorite-node 的节点:

data.inventory.cluster["v1"]["Node"]["my-favorite-node"]

命名空间范围的资源在此处缓存:

data.inventory.namespace["NAMESPACE"]["GROUP_VERSION"]["KIND"]["NAME"]

例如,可以在下面的命名空间 shipping-prod 中找到名为 production-variables 的 ConfigMap。

data.inventory.namespace["shipping-prod"]["v1"]["ConfigMap"]["production-variables"]

对象的全部内容存储在此缓存位置,如果您认为合适,可以在 Rego 源代码中引用。

有关 Rego 的更多信息

上述信息提供了 Policy Controller 的独特功能,让您能够轻松地采用 Rego 编写对 Kubernetes 资源的限制条件。有关如何采用 Rego 编写限制条件的完整教程不在本教程的讨论范围内。但是,Open Policy Agent 的文档包含有关 Rego 语言本身的语法和功能的信息。

安装限制条件模板

创建限制条件模板后,使用 kubectl apply 应用该模板,且 Policy Controller 负责提取它。请务必检查限制条件模板的 status 字段,以确保在将其实例化时没有出现错误。成功提取后,status 字段应显示 created: true,并且 status 字段中记录的 observedGeneration 应该等于 metadata.generation 字段。

提取模板后,您可以按照创建限制条件中的说明为其应用限制条件。

移除限制条件模板

如需移除限制条件模板,请完成以下步骤:

  1. 确认您要保留的限制条件没有使用限制条件模板:

    kubectl get TEMPLATE_NAME
    

    如果限制条件模板的名称与集群中的其他对象之间存在命名冲突,请改为使用以下命令:

    kubectl get TEMPLATE_NAME.constraints.gatekeeper.sh
    
  2. 移除限制条件模板:

    kubectl delete constrainttemplate CONSTRAINT_TEMPLATE_NAME
    

删除限制条件模板后,将无法再创建引用它的限制条件。

后续步骤