4. OPA 与 Kubernetes 集成:Admission Controller 机制、OPA Gatekeeper 安装、约束模板与约束
本章深入解析 OPA(Open Policy Agent)与 Kubernetes 集成的核心路径——通过 Admission Controller 机制实现策略即代码。我们将从 Kubernetes 准入控制链入手,逐步讲解 OPA Gatekeeper 的安装部署、约束模板(ConstraintTemplate)与约束(Constraint)的声明式定义,最终构建一个可扩展的策略执行层。
4.1 Kubernetes Admission Controller 机制
Kubernetes API Server 在处理资源请求时,会经过一系列内置与动态准入控制器(Admission Controller)的校验。OPA Gatekeeper 正是以 动态准入 Webhook 的形式嵌入这一链路,在资源持久化之前执行策略检查。
下表对比了两种动态准入 Webhook 在策略场景中的角色:
| Webhook 类型 | 作用时机 | OPA Gatekeeper 使用场景 | 典型操作 |
|---|---|---|---|
| MutatingAdmissionWebhook | 对象验证之前 | 自动注入标签、Sidecar、默认值 | 修改请求对象 |
| ValidatingAdmissionWebhook | 对象验证之后、持久化之前 | 安全策略、合规检查、资源配额校验 | 拒绝或允许请求 |
4.2 OPA Gatekeeper 安装
OPA Gatekeeper 以一组 Kubernetes 原生资源的形式部署,推荐使用 Helm Chart 或直接应用官方 YAML 清单。安装后,集群中会新增以下核心 CRD:
- ConstraintTemplate:定义策略逻辑(Rego 代码)与参数 schema。
- Constraint:实例化约束模板,指定匹配范围与参数。
- Config:配置 Gatekeeper 的同步、排除命名空间等行为。
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm install gatekeeper/gatekeeper --name-template=gatekeeper --namespace=gatekeeper-system --create-namespace
安装完成后,验证关键 Pod 与 CRD 是否就绪:
kubectl get pods -n gatekeeper-system
# 预期输出:gatekeeper-controller-manager-xxx Running
# gatekeeper-audit-xxx Running
kubectl get crd | grep gatekeeper
# 预期输出:constrainttemplates.templates.gatekeeper.sh
# constraints.constraints.gatekeeper.sh
# configs.config.gatekeeper.sh
kube-apiserver 的 --enable-admission-plugins 参数是否包含 MutatingAdmissionWebhook 和 ValidatingAdmissionWebhook。
4.3 约束模板(ConstraintTemplate)
约束模板是 Gatekeeper 策略的核心抽象,它封装了 Rego 策略逻辑和参数声明。一个模板可被多个约束实例化,实现策略复用。
以下是一个约束模板示例,用于强制所有 Pod 必须包含 app 标签:
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}] {
provided := {label | input.review.object.metadata.labels[label]}
required := {label | label := input.parameters.labels[_]}
missing := required - provided
count(missing) > 0
msg := sprintf("缺少必要标签: %v", [missing])
}
| 字段 | 说明 | 示例值 |
|---|---|---|
spec.crd.spec.names.kind |
约束的 CRD 名称,即后续创建约束时使用的 kind |
K8sRequiredLabels |
spec.crd.spec.validation |
定义约束实例可接受的参数 schema(OpenAPI v3) | labels: array of string |
spec.targets[].rego |
Rego 策略代码,violation 规则返回违规消息 |
检查缺失标签 |
input.review 访问 AdmissionReview 对象,input.parameters 获取约束实例传入的参数。推荐在本地使用 opa eval 命令配合测试数据验证 Rego 逻辑。
4.4 约束(Constraint)
约束是约束模板的实例化资源,它指定了策略的生效范围(通过 match 字段)和具体参数。一个约束模板可以对应多个约束,应用于不同的命名空间或资源类型。
基于上述 K8sRequiredLabels 模板,创建一个约束,要求所有命名空间 production 中的 Pod 必须包含 app 和 env 标签:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: pod-must-have-app-env
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
namespaces: ["production"]
parameters:
labels:
- "app"
- "env"
约束的 spec.match 支持丰富的选择器,下表列出常用匹配维度:
| 匹配字段 | 作用 | 示例 |
|---|---|---|
kinds |
按资源类型匹配(支持 apiGroups 和 kinds 数组) | [{apiGroups: [""], kinds: ["Pod"]}] |
namespaces |
按命名空间白名单匹配 | ["production", "staging"] |
excludedNamespaces |
排除特定命名空间 | ["kube-system"] |
labelSelector |
按资源标签选择器匹配 | {matchLabels: {tier: "frontend"}} |
namespaceSelector |
按命名空间标签选择器匹配 | {matchExpressions: [...]} |
violation 消息,便于排查拒绝原因。
4.5 策略生效验证与审计
部署约束后,可以通过创建违反策略的资源来验证 Gatekeeper 是否正常工作:
kubectl run test-pod --image=nginx -n production
# 预期输出:Error from server (Forbidden): admission webhook "validation.gatekeeper.sh" denied the request: [pod-must-have-app-env] 缺少必要标签: {"app", "env"}
Gatekeeper 还内置了 审计(Audit) 功能,定期扫描集群中已有资源,将违反约束的资源记录在约束的 status 字段中:
kubectl get constraint pod-must-have-app-env -o jsonpath='{.status.violations}'
spec.sync.syncOnly 和 spec.auditInterval 调整。审计结果不会自动删除违规资源,仅用于报告和告警触发。