4. ConstraintTemplate 入门:CRD 结构、Rego 模板编写基础、模板参数化
ConstraintTemplate(约束模板)是 Gatekeeper 的核心扩展点,它定义了策略的“形状”和“逻辑”。本章将深入剖析 ConstraintTemplate 的 CRD 结构、Rego 模板编写基础以及如何通过参数化实现模板复用。
4.1 ConstraintTemplate CRD 结构解析
ConstraintTemplate 本身是一个 Kubernetes 自定义资源(CRD),其 API 版本为 templates.gatekeeper.sh/v1。一个完整的 ConstraintTemplate 由三个主要部分组成:metadata、spec.crd.spec 和 spec.targets。
| 字段路径 | 类型 | 说明 |
|---|---|---|
metadata.name |
string | 模板名称,必须与后续创建的 Constraint 的 constraintType 一致。 |
spec.crd.spec.names.kind |
string | 定义由此模板生成的 Constraint 的 Kind 名称。 |
spec.crd.spec.validation.openAPIV3Schema |
object | 定义 Constraint 实例的 spec.parameters 字段的 JSON Schema 结构,用于参数校验。 |
spec.targets[].target |
string | 目标系统,通常为 admission.k8s.gatekeeper.sh。 |
spec.targets[].rego |
string | Rego 策略代码,包含 violation 规则。 |
spec.targets[].libs |
[]string | 可选的 Rego 库代码,用于在多个模板间共享函数。 |
spec.crd.spec 定义了 Constraint 实例的“参数接口”,并通过 spec.targets[].rego 提供了策略执行逻辑。
4.2 Rego 模板编写基础
Rego 是 Gatekeeper 的策略语言,其核心是 violation 规则。当 violation 规则返回 true 时,表示请求违反策略。
4.2.1 基本 Rego 模板结构
package mypackage
violation[{"msg": msg}] {
# 条件判断
input.review.object.metadata.name == "forbidden-name"
msg := "资源名称不允许为 forbidden-name"
}
- package:定义 Rego 包名,建议与模板名称对应。
- violation:一个集合规则,每个满足条件的条目生成一个包含
msg字段的对象。 - input:Gatekeeper 注入的全局变量,包含
review(AdmissionReview 对象)和parameters(用户传入的参数)。
4.2.2 访问请求数据
Rego 通过 input 对象访问 Kubernetes 资源请求的详细信息:
| 表达式 | 说明 |
|---|---|
input.review.object |
被审查的 Kubernetes 资源对象。 |
input.review.oldObject |
更新操作中的旧对象。 |
input.review.operation |
操作类型,如 CREATE、UPDATE。 |
input.parameters |
用户在 Constraint 实例中定义的参数。 |
4.3 模板参数化
参数化允许同一个 ConstraintTemplate 通过不同的参数配置实现不同的策略行为,避免为每个细微差异创建新模板。
4.3.1 定义参数 Schema
在 spec.crd.spec.validation.openAPIV3Schema 中定义参数结构:
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
openAPIV3Schema:
type: object
properties:
labels:
type: array
items:
type: string
4.3.2 在 Rego 中使用参数
通过 input.parameters 访问用户传入的参数:
package k8srequiredlabels
violation[{"msg": msg}] {
input.review.operation == "CREATE"
label := input.parameters.labels[_]
not input.review.object.metadata.labels[label]
msg := sprintf("必须包含标签: %v", [label])
}
4.4 ConstraintTemplate 与 Constraint 的关系
下图展示了 ConstraintTemplate 如何通过参数化生成不同的 Constraint 实例:
4.5 完整示例:带参数的标签检查模板
以下是一个完整的 ConstraintTemplate 示例,它检查资源是否包含指定的标签:
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredlabels
spec:
crd:
spec:
names:
kind: K8sRequiredLabels
validation:
openAPIV3Schema:
type: object
properties:
labels:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredlabels
violation[{"msg": msg}] {
input.review.operation == "CREATE"
label := input.parameters.labels[_]
not input.review.object.metadata.labels[label]
msg := sprintf("必须包含标签: %v", [label])
}
openAPIV3Schema 中明确定义参数类型和约束,Gatekeeper 会自动校验用户传入的参数是否符合 Schema 定义,避免运行时错误。
4.6 参数化与 Rego 数据查询
参数化不仅限于简单的列表或字符串,还可以结合 Rego 的数据查询功能实现更复杂的策略。例如,从 ConfigMap 中读取允许的镜像列表:
package allowedimages
violation[{"msg": msg}] {
image := input.review.object.spec.containers[_].image
not data.allowedimages.images[image]
msg := sprintf("镜像 %v 不在允许列表中", [image])
}
这种方式将策略逻辑与配置数据分离,通过更新 ConfigMap 即可动态调整策略行为,无需修改 ConstraintTemplate 或重新部署。
4.7 本章小结
- CRD 结构:ConstraintTemplate 包含
spec.crd.spec(定义参数接口)和spec.targets(定义 Rego 逻辑)。 - Rego 基础:
violation规则是策略的核心,通过input访问请求数据和参数。 - 参数化:通过
openAPIV3Schema定义参数结构,在 Rego 中使用input.parameters引用参数,实现模板复用。 - 数据查询:Rego 支持通过
data关键字查询集群中的其他资源,实现动态策略。