3. OPA Gatekeeper入门:OPA与Rego语言基础、Gatekeeper架构、安装与部署

在云原生安全策略引擎的版图中,OPA(Open Policy Agent)与 Gatekeeper 的组合是业界最成熟的策略即代码实现方案之一。本章将带你从零掌握 OPA 的核心概念、Rego 策略语言的基本语法,理解 Gatekeeper 在 Kubernetes 集群中的架构定位,并完成完整的安装与部署流程。

3.1 OPA 核心概念与策略即代码

OPA 是一个开源的、通用的策略引擎,它将策略决策与业务逻辑解耦。OPA 不负责执行策略,而是根据输入数据(Input)和策略规则(Policy)输出决策结果(Decision)。

概念 说明 类比
Policy(策略) 用 Rego 语言编写的规则集合,定义“允许”或“拒绝”的条件 交通法规
Input(输入) 策略评估时的外部数据,如 Kubernetes 资源对象的 JSON 表示 当前路况与车辆信息
Data(数据) 策略依赖的静态或动态上下文数据,如白名单、配置基线 地图与限速标志
Decision(决策) 策略评估结果,通常为 allow 或 deny,可附带消息 交警的放行或处罚决定
关键理解: OPA 本身不存储状态,每次决策都是基于输入和数据的纯函数计算。这种设计使其天然适合在 Kubernetes 准入控制场景中做实时校验。

3.2 Rego 语言基础

Rego 是 OPA 的专用声明式查询语言,灵感来源于 Datalog。Rego 的核心是规则(Rule)和查询(Query)。

3.2.1 基本语法结构

package kubernetes.admission

# 规则:拒绝没有设置 resource limits 的 Pod
deny[msg] {
    input.request.kind.kind == "Pod"
    not input.request.object.spec.containers[_].resources.limits
    msg := "容器必须设置 resource limits"
}
  • Package:策略的命名空间,用于组织规则。
  • Rule:deny[msg] 表示当条件满足时,生成一条拒绝消息。
  • Iteration:containers[_] 中的下划线表示遍历所有容器。
  • Negation:not 用于检查某个条件不成立。

3.2.2 常用内置函数与操作符

类别 示例 说明
比较 ==, !=, <, > 与大多数语言一致
集合 count(array), array[_] 获取长度、遍历元素
字符串 startswith(s, prefix), regex.match(pattern, s) 前缀匹配、正则匹配
对象 object.get(obj, key, default) 安全访问嵌套字段
学习建议: Rego 的调试利器是 print() 函数和 opa eval 命令行工具。在编写复杂规则时,先用 opa eval --data policy.rego --input input.json "data.kubernetes.admission" 验证规则逻辑。

3.3 Gatekeeper 架构解析

Gatekeeper 是 OPA 在 Kubernetes 上的原生集成实现,它利用 Kubernetes 的准入 Webhook 机制,在资源创建或更新时触发策略评估。

Gatekeeper 架构组件与请求流程 kubectl / 客户端 Kubernetes API Server Gatekeeper Webhook OPA 策略引擎 ConstraintTemplate Constraint (CRD 实例) 创建/更新资源 准入审查请求 调用 OPA 评估 加载模板 实例化参数 允许/拒绝决策 响应结果 核心组件说明 • ConstraintTemplate:定义 Rego 逻辑模板 • Constraint:CRD 实例,传入具体参数 • Webhook:拦截 API 请求并触发评估

3.3.1 核心组件职责

  • Gatekeeper Webhook:作为 Kubernetes 的 ValidatingAdmissionWebhook 和 MutatingAdmissionWebhook 注册,拦截资源请求。
  • OPA 引擎:嵌入在 Gatekeeper Pod 中,负责执行 Rego 策略评估。
  • ConstraintTemplate:自定义资源(CRD),用于定义可复用的 Rego 策略模板。
  • Constraint:ConstraintTemplate 的实例化对象,通过参数(如 allowedRegistries)定制策略行为。

3.4 安装与部署 Gatekeeper

Gatekeeper 的安装支持 Helm Chart 和 YAML 清单两种方式。以下以 Helm 3 为例进行部署。

3.4.1 前置条件

组件 版本要求 说明
Kubernetes 集群 >= 1.20 需要支持 ValidatingAdmissionWebhook
Helm >= 3.0 推荐使用 Helm 3 进行安装管理
kubectl 与集群版本匹配 用于验证部署状态

3.4.2 使用 Helm 安装 Gatekeeper

# 添加 Gatekeeper Helm 仓库
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts

# 更新仓库
helm repo update

# 安装 Gatekeeper 到 gatekeeper-system 命名空间
helm install gatekeeper/gatekeeper \
  --name-template gatekeeper \
  --namespace gatekeeper-system \
  --create-namespace \
  --set replicas=2 \
  --set auditInterval=60

3.4.3 验证部署状态

# 检查 Pod 运行状态
kubectl get pods -n gatekeeper-system

# 预期输出示例:
# NAME                                             READY   STATUS    RESTARTS   AGE
# gatekeeper-audit-7d8f6b9c6f-abc12                1/1     Running   0          2m
# gatekeeper-controller-manager-6f9c7d8e4f-xyz34   1/1     Running   0          2m
# gatekeeper-controller-manager-6f9c7d8e4f-uvw56   1/1     Running   0          2m

# 检查 Webhook 配置是否注册成功
kubectl get validatingwebhookconfigurations
# 应看到 gatekeeper-validating-webhook-configuration
常见问题: 如果 Gatekeeper Pod 一直处于 CrashLoopBackOff 状态,请检查集群的 PodSecurityPolicy 或 ValidatingAdmissionWebhook 是否被其他组件(如 Kyverno)冲突拦截。建议先排查 Webhook 配置的 failurePolicy 是否为 Ignore。

3.5 部署后的快速验证

安装完成后,可以通过部署一个简单的 ConstraintTemplate 和 Constraint 来验证 Gatekeeper 是否正常工作。

# 1. 创建 ConstraintTemplate:禁止特权容器
cat <<EOF | kubectl apply -f -
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
  name: k8spspprivilegedcontainer
spec:
  crd:
    spec:
      names:
        kind: K8sPSPPrivilegedContainer
  targets:
    - target: admission.k8s.gatekeeper.sh
      rego: |
        package k8spspprivilegedcontainer
        violation[{"msg": msg}] {
          c := input.review.object.spec.containers[_]
          c.securityContext.privileged == true
          msg := sprintf("容器 %v 不允许使用特权模式", [c.name])
        }
EOF

# 2. 创建 Constraint 实例
cat <<EOF | kubectl apply -f -
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sPSPPrivilegedContainer
metadata:
  name: no-privileged-containers
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Pod"]
EOF

# 3. 测试:尝试创建特权 Pod
kubectl run test-privileged --image=nginx --privileged
# 预期输出:Error from server (Forbidden): ... 容器 test-privileged 不允许使用特权模式
验证要点: 如果测试 Pod 被成功拒绝,说明 Gatekeeper 的准入控制链路已打通。此时可以继续编写更复杂的策略,如镜像仓库白名单、资源配额校验等。

3.6 本章小结