本文档采用自动化机器翻译技术翻译。 尽管我们力求提供准确的译文,但不对翻译内容的完整性、准确性或可靠性作出任何保证。 若出现任何内容不一致情况,请以原始 英文 版本为准,且原始英文版本为权威文本。

这是尚未发布的文档。 Admission Controller 1.34-dev.

将Gatekeeper策略迁移到SUSE Security Admission Controller

本指南向您展示如何将现有的Gatekeeper策略转换为SUSE Security Admission Controller策略。此过程涉及两个主要步骤: . 将Rego程序编译为WebAssembly(Wasm)模块。 . 将WebAssembly模块分发为Admission Controller策略。

Rego策略教程涵盖了将Rego代码编译为WebAssembly模块的大部分构建过程。本指南专注于逐步提取Gatekeeper自定义资源定义(CRD),并将其迁移为功能性Admission Controller策略。它使用一个基本的Gatekeeper演示策略。

先决条件

  • opa:您使用此工具将代码构建为wasm。本指南是使用`v1.5.1`版本编写的。

  • kwctl:您用来准备和运行Admission Controller WebAssembly模块的工具。

  • bats:用于运行端到端测试的工具。如果您决定编写这种类型的测试

  • yq:用于从yaml文件中提取数据的工具。

在迁移您的策略之前

在开始迁移Gatekeeper策略的过程中,请考虑使用Admission Controller目录中已有的策略。其中一些策略是公开可用的OPA和Gatekeeper策略,已迁移到Admission Controller。

此外,请查看我们的比较的文档,对比Admission Controller和Gatekeeper。

第 1 步:初始化您的Admission Controller策略项目

首先,使用Admission Controller Gatekeeper 模板来创建 一个基本的策略项目结构。这提供了用于构建和测试您策略的Makefile目标。在您从模板创建策略代码后,运行Makefile命令以检查策略构建和测试是否成功:

$ make policy.wasm test
opa build -t wasm -e policy/violation -o bundle.tar.gz policy.rego
tar xvf bundle.tar.gz /policy.wasm
tar: Removing leading `/' from member names
/policy.wasm
rm bundle.tar.gz
touch policy.wasm # opa creates the bundle with unix epoch timestamp, fix it
opa test *.rego
PASS: 2/2

第 2 步:迁移Gatekeeper策略代码

现在,开始迁移Gatekeeper策略。这涉及将一个`ConstraintTemplate`及其相关的`Constraint`资源转换为一个Admission Controller策略。在Admission Controller上下文中,将`ConstraintTemplate`视为核心策略代码,而`Constraint`实例则转换为在Admission Controller中运行的策略实例。

首先,将您的`ConstraintTemplate`中的Rego代码复制到`policy.rego`文件中,该文件由Admission Controller模板生成。在这个例子中,您应该使用来自Gatekeeper储存库的以下基本演示策略

Gatekeeper策略yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8srequiredlabels
spec:
  crd:
    spec:
      names:
        kind: K8sRequiredLabels
      validation:
        # Schema for the `+parameters+` field
        openAPIV3Schema:
          type: object
          properties:
            labels:
              type: array
              items:
                type: 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])
        }

将Rego代码片段从`rego`字段复制到您的`policy.rego`文件中:

cat gatekeeper/demo/basic/templates/k8srequiredlabels_template.yaml | yq ".spec.targets[0].rego" > policy.rego

为Admission Controller调整Rego代码

您需要确保Rego代码中使用的`package`名称是`policy`。 这是Admission Controller Gatekeeper模板在许多地方期望的值。

如果您不更改它,构建策略和运行其端到端测试时将会出现错误。

例如,我们正在转换的演示策略定义在`k8srequiredlabels`包中,这个值必须更改为`policy`。

`policy.rego`文件的内容应如下所示:

package policy

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])
}

在此更改后尝试构建代码可能会显示新的编译错误:

opa build -t wasm -e policy/violation -o bundle.tar.gz policy.rego
error: load error: 2 errors occurred during loading:
policy.rego:3: rego_parse_error: `+if+` keyword is required before rule body
policy.rego:3: rego_parse_error: `+contains+` keyword is required for partial set rules
make: *** [Makefile:4: policy.wasm] Error 1

策略作者必须修复这些错误,以允许`opa` CLI成功构建代码。具体的更改可能会根据`opa`版本和原始策略代码而有所不同。由于我们正在迁移一个在OPA v1之前的Rego策略,我们需要更新代码以符合v1标准。最终的`policy.rego`代码如下:

package policy

violation contains {"msg": msg, "details": {"missing_labels": missing}} if {
  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])
}

调整代码后,构建策略:

$ make policy.wasm
opa build -t wasm -e policy/violation -o bundle.tar.gz policy.rego
tar xvf bundle.tar.gz /policy.wasm
tar: Removing leading `/' from member names
/policy.wasm
rm bundle.tar.gz
touch policy.wasm # opa creates the bundle with unix epoch timestamp, fix it

有关如何构建Gatekeeper策略的更多信息,请参阅我们的教程

Rego策略代码与OPA v1.0.0的兼容性

随着OPA(开放政策代理)v1.0.0在2024年12月的发布,引入了关于Rego策略语法的重大更改。

之前,`if`对于所有规则定义和`contains`对于多值规则是可选的;现在,它们是强制性的。此更改影响大多数旧策略。

以下是您需要了解的内容摘要:

  • OPA v1.0.0语法:OPA v1.0.0强制要求对所有规则定义使用`if`,并对多值规则使用`contains`。不遵循此语法的策略将会失效。

  • 向后兼容性:如果您需要构建不使用新v1.0.0语法的旧策略,您必须在`opa build`命令中提供`--v0-compatible`标志。

  • Gatekeeper集成:Gatekeeper在其v3.19.0发布中将其OPA依赖项更新为v1.0.0。

  • Gatekeeper模板中的Rego版本:Gatekeeper假设使用`v0`语法,除非模板在`code.engine: Rego`下的`source`字段中明确指定`version: "v1"`。

有关如何处理`v0`和`v1`版本的Rego的更多详细信息,请参见Gatekeeper文档中本节

这对您意味着:

  • 如果 Gatekeeper CR 没有指定 Rego 版本,则意味着将使用 v0。您必须使用 OPA_V0_COMPATIBLE=true make 命令构建策略。

  • 如果 Gatekeeper CR 明确指定了 version: "v1",您必须在不设置任何环境变量的情况下构建策略。

第三步:更新并运行测试

虽然强烈推荐,但策略作者可能会跳过为策略的初始版本创建测试。如果这适用于您,您需要禁用用于运行测试的 Makefile 目标。您不能完全去除这些目标,因为默认的 CI 作业期望它们被定义。相反,您应该用 "无操作" 操作替换调用 opabats 的命令。例如,您可以使用 echo 命令打印出为什么不运行测试的解释。

Admission Controller Gatekeeper 模板包括 Rego 单元测试和使用 Bats 和 kwctl 的端到端 (e2e) 测试。如果您计划包含测试,则两个集合都需要根据您的策略进行调整。

如果您的 Gatekeeper 策略已经有 Rego 测试,您可以将它们复制到 policy_test.rego 文件中。当您执行 make test 命令时,这些测试会自动运行。

请记住,您在 policy_test.rego 中编写的任何 Rego 测试都受到 Rego 策略代码和 OPA v1.0.0 兼容性 部分中详细说明的相同兼容性问题的影响。

您在本指南中迁移的策略没有测试;我们需要自己添加它们。因此,我们将用一些基本测试更新 policy_test.rego 测试文件:

package policy

review_required_labels := {
    "parameters": {"labels": ["test"]},
    "review": {"object": {"metadata": {"labels": {"test": "value"}}}},
}

review_missing_labels := {
    "parameters": {"labels": ["test"]},
    "review": {"object": {"metadata": {"labels": {"other": "value"}}}},
}

test_accept if {
    r = review_required_labels
    res = violation with input as r
    count(res) = 0
}

test_reject if {
    r = review_missing_labels
    res = violation with input as r
    count(res) = 1
}

现在,运行 make test 应该验证您的策略:

$ make policy.wasm test
opa build -t wasm -e policy/violation -o bundle.tar.gz policy.rego
tar xvf bundle.tar.gz /policy.wasm
tar: Removing leading `/' from member names
/policy.wasm
rm bundle.tar.gz
touch policy.wasm # opa creates the bundle with unix epoch timestamp, fix it
opa test *.rego
PASS: 2/2

接下来,更新 e2e 测试文件 (e2e.bats):

#!/usr/bin/env bats

@test "accept because required label is present" {
  run kwctl run -e gatekeeper annotated-policy.wasm --settings-path test_data/settings.json --request-path test_data/accept_deploy_request.json

  # this prints the output when one the checks below fails
  echo "output = ${output}"

  # request accepted
  [ "$status" -eq 0 ]
  [ $(expr "$output" : '.*allowed.*true') -ne 0 ]
}

@test "reject because required label is missing" {
run kwctl run -e gatekeeper annotated-policy.wasm --settings-path test_data/settings.json --request-path test_data/reject_deploy_request.json

  # this prints the output when one the checks below fails
  echo "output = ${output}"

  # request rejected
  [ "$status" -eq 0 ]
  [ $(expr "$output" : '.*allowed.*false') -ne 0 ]
  [ $(expr "$output" : '.*message.*you must provide labels: \[test\]') -ne 0 ]
}

您需要创建 test_data/settings.jsontest_data/accept_deploy_request.jsontest_data/reject_deploy_request.json 文件以支持这些测试。

test_data/settings.json
{
  "labels": ["test"]
}

我们不会在这里包含 accept_deploy_request.jsonreject_deploy_request.json 的完整内容,因为 AdmissionRequest JSON 可能会很长,我们希望保持本指南的简洁。但是,您可以使用 kwctl scaffold 命令生成这些文件。本指南的关键在于,一个请求应该缺少所需的标签,而另一个请求应该定义该标签。

检查 e2e 测试是否通过:

$ make e2e-tests
bats e2e.bats
e2e.bats
  ✓ accept because required label is present
  ✓ reject because required label is missing

策略参数(例如,本示例中的标签)源自策略设置。这使您能够以不同的参数/设置部署多个相同策略的实例,类似于约束在 Gatekeeper 中的功能。

第四步:准备 metadata.yml 以供分发

现在您有了一个功能性策略,请准备 metadata.yml 文件以供分发。该文件定义了带有策略描述、作者、许可证和其他基本信息的注释。至关重要的是,它定义了 rules,指定策略可以验证哪些资源和动词。该信息驱动 kwctl scaffold 命令生成用于在您的集群中部署策略的清单。

Gatekeeper 的 Constraints CRDs,它们是在`ConstraintTemplates`中定义的策略实例,指定了策略实例评估哪些资源。 因此,如果您有现有的`Constraints`应用了`ConstraintTemplate`,它们为您在`metadata.yml`文件中应定义的资源提供了良好的参考。例如,在之前使用的Gatekeeper示例中,从`k8srequiredlabelsConstraintTemplate`创建的`K8sRequiredLabelsConstraint`适用于`Namespaces`:

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

基于此,更新您的`metadata.yml`的`rules`部分,以包括一个新的`rule`,用于在`CREATE`和`UPDATE`操作期间验证`namespaces`:

rules:
  - apiGroups: ["apps"]
    apiVersions: ["v1"]
    resources: ["deployments"]
    operations: ["CREATE", "UPDATE"]
  - apiGroups: [""]
    apiVersions: ["v1"]
    resources: ["namespaces"]
    operations: ["CREATE", "UPDATE"]
mutating: false
contextAware: false
executionMode: gatekeeper
backgroundAudit: true
annotations:
  io.artifacthub.displayName: Policy Name
  io.artifacthub.resources: Pod
  io.artifacthub.keywords: pod, cool policy, kubewarden
  io.kubewarden.policy.ociUrl: ghcr.io/yourorg/policies/policy-name
  io.kubewarden.policy.title: policy-name
  io.kubewarden.policy.version: 0.0.1-unreleased
  io.kubewarden.policy.description: Short description
  io.kubewarden.policy.author: "Author name <author-email@example.com>"
  io.kubewarden.policy.url: https://github.com/yourorg/policy-name
  io.kubewarden.policy.source: https://github.com/yourorg/policy-name
  io.kubewarden.policy.license: Apache-2.0
  io.kubewarden.policy.severity: medium
  io.kubewarden.policy.category: Resource validation

现在,您的策略已准备好分发和部署。请参考教程中的发布策略部分,了解如何将其推送到远程注册表。

您可以使用`kwctl`搭建策略清单:

$ kwctl scaffold manifest --type ClusterAdmissionPolicy annotated-policy.wasm
apiVersion: policies.kubewarden.io/v1
kind: ClusterAdmissionPolicy
metadata:
  annotations:
    io.kubewarden.policy.category: Resource validation
    io.kubewarden.policy.severity: medium
  name: policy-name
spec:
  module: file:///home/jvanz/SUSE/mygatekeeperpolicy/annotated-policy.wasm
  settings: {}
  rules:
  - apiGroups:
    - apps
    apiVersions:
    - v1
    resources:
    - deployments
    operations:
    - CREATE
    - UPDATE
  - apiGroups:
    - ''
    apiVersions:
    - v1
    resources:
    - namespaces
    operations:
    - CREATE
    - UPDATE
  mutating: false

定义策略设置

该策略具有参数,Gatekeeper在`Constraint`中定义这些参数。您需要更新生成的`settings`策略清单中的Admission Controller部分,以包含这些必需的参数。在以下示例中,除了定义设置外,您还可以从OCI注册表测试该策略:

apiVersion: policies.kubewarden.io/v1
kind: ClusterAdmissionPolicy
metadata:
  annotations:
    io.kubewarden.policy.category: Resource validation
    io.kubewarden.policy.severity: medium
  name: policy-name
spec:
  module: registry://ghcr.io/jvanz/policies/mygatekeeperpolicy:latest
  settings:
    labels:
      - "gatekeeper"
  rules:
    - apiGroups:
        - apps
      apiVersions:
        - v1
      resources:
        - deployments
      operations:
        - CREATE
        - UPDATE
    - apiGroups:
        - ""
      apiVersions:
        - v1
      resources:
        - namespaces
      operations:
        - CREATE
        - UPDATE
  mutating: false

尝试部署缺少必需`gatekeeper`标签的名称空间:

kubectl apply -f - <<EOF
apiVersion: v1
kind: Namespace
metadata:
  name: your-namespace-name
  labels:
    purpose: demo
EOF
Error from server: error when creating "STDIN": admission webhook "clusterwide-policy-name.kubewarden.admission" denied the request: you must provide labels: [gatekeeper]

以及另一个带有必需标签的名称空间:

kubectl apply -f - <<EOF
apiVersion: v1
kind: Namespace
metadata:
  name: your-namespace-name
  labels:
    purpose: demo
    gatekeeper: test
EOF

namespace/your-namespace-name created