K8s 安全准入:OPA Gatekeeper 与 Kyverno

学习 K8s安全准入 相关知识

K8s 安全准入:OPA Gatekeeper 与 Kyverno


1. 准入控制机制

请求流程

kubectl apply → 认证 → 授权(RBAC) → 准入控制(MutatingWebhook) → 准入控制(ValidatingWebhook) → etcd 存储
                                              ↓                                    ↓
                                      修改资源定义                             验证资源合法性
                                    (OPA/Kyverno mutating)                  (OPA/Kyverno validating)

两种策略引擎对比

维度OPA GatekeeperKyverno
策略语言Rego(声明式 DSL)YAML(K8s 原生风格)
学习曲线陡峭,需学 Rego平缓,现有 K8s 用户可上手
复杂策略强(Rego 表达力强)
社区成熟度CNCF graduatedCNCF incubating
变更策略mutationmutation(更强)
策略来源ConstraintTemplate + ConstraintClusterPolicy / Policy
适用场景复杂规则、多集群统一策略团队快速落地安全基线

选择建议: 如果团队熟悉 Rego 或已有 OPA 投入 → Gatekeeper。如果想快速落地安全基线,不想学新语言 → Kyverno。


2. Kyverno 实战(推荐入门)

安装

kubectl create namespace kyverno
kubectl apply -f https://github.com/kyverno/kyverno/releases/download/v1.12.0/install.yaml

# 验证
kubectl get pods -n kyverno
kubectl get validatingwebhookconfiguration kyverno-resource-validating-webhook-cfg

基础策略示例

# 禁止 privileged 容器
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: disallow-privileged-containers
spec:
  validationFailureAction: Enforce    # Enforce=强制拒绝, Audit=仅记录
  rules:
    - name: privileged-containers
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "不允许使用特权容器"
        pattern:
          spec:
            containers:
              - securityContext:
                  privileged: false
---
# 要求所有镜像来自受信任仓库
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: restrict-image-registries
spec:
  validationFailureAction: Enforce
  rules:
    - name: validate-registry
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "镜像必须来自公司内部仓库 registry.company.com"
        pattern:
          spec:
            containers:
              - image: "registry.company.com/*"
---
# 禁止使用 latest 标签
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: disallow-latest-tag
spec:
  validationFailureAction: Enforce
  rules:
    - name: require-image-tag
      match:
        any:
          - resources:
              kinds:
                - Pod
      validate:
        message: "禁止使用 latest 标签"
        pattern:
          spec:
            containers:
              - image: "!*:latest"
---
# 自动注入 sidecar(mutation 示例)
apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: inject-istio-sidecar
spec:
  rules:
    - name: inject-sidecar
      match:
        any:
          - resources:
              kinds:
                - Pod
      mutate:
        patchStrategicMerge:
          metadata:
            annotations:
              sidecar.istio.io/inject: "true"

策略生效模式

模式行为适用阶段
Audit记录违规但不阻止灰度测试新策略
Enforce直接拒绝违规请求生产策略

推荐上线流程: Audit 运行 1-2 周 → 检查违规报表 → 修复违规资源 → 改为 Enforce

排查命令

# 查看策略状态
kubectl get clusterpolicy
kubectl describe clusterpolicy disallow-privileged-containers

# 查看违规报告
kubectl get policyreport -A
kubectl describe policyreport -n <namespace> <report-name>

# 查看准入 webhook 日志
kubectl logs -n kyverno -l app.kubernetes.io/name=kyverno --tail=50

3. OPA Gatekeeper 实战

安装

kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/release-3.16/deploy/gatekeeper.yaml

策略结构

Gatekeeper 的策略分两层:

  1. ConstraintTemplate — 定义策略逻辑(Rego 代码)
  2. Constraint — 应用策略的具体参数
# 1. 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.object.kind == "Namespace"
          provided := {label | input.review.object.metadata.labels[label]}
          required := {label | label := input.parameters.labels[_]}
          missing := required - provided
          count(missing) > 0
          msg := sprintf("缺少必填标签: %v", [missing])
        }
---
# 2. Constraint:应用策略,要求所有 namespace 必须有 owner/team 标签
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
  name: ns-must-have-owner
spec:
  match:
    kinds:
      - apiGroups: [""]
        kinds: ["Namespace"]
  parameters:
    labels:
      - "owner"
      - "team"

常用策略模板

# 禁止 hostNetwork
package k8shostnetwork

violation[{"msg": msg}] {
  input.review.object.kind == "Pod"
  input.review.object.spec.hostNetwork
  msg := "禁止使用 hostNetwork"
}

# 限制 container 资源(必须设置 requests 和 limits)
package k8srequiredresources

violation[{"msg": msg}] {
  container := input.review.object.spec.containers[_]
  not container.resources
  msg := sprintf("容器 %v 未设置资源限制", [container.name])
}

violation[{"msg": msg}] {
  container := input.review.object.spec.containers[_]
  container.resources.requests == {}
  msg := sprintf("容器 %v 未设置 resources.requests", [container.name])
}

4. 生产建议与最佳实践

策略上线流程

1. 识别安全基线需求
   └── 哪些必须禁止(特权容器、hostNetwork、latest 标签)
   └── 哪些必须要求(资源限制、readOnlyRootFilesystem、probe)

2. 先 Audit 模式运行 2 周
   └── 收集违规报告
   └── 修复现有违规资源
   └── 根据实际违规调整策略(误报调优)

3. 逐步切换 Enforce
   └── 先低风险策略(禁止 latest 标签)
   └── 再高风险策略(禁止特权容器)
   └── 保留 Exception 通道:用 Kyverno 的 PolicyException 或 Gatekeeper 的 Exemption

4. 持续监控
   └── 监控 Kyverno/Gatekeeper 自身的日志
   └── 定期审查策略报告
   └── 版本升级前验证策略兼容性

常用策略清单

策略Kyverno 实现难度推荐级别
禁止特权容器低(内置规则)必选
禁止 hostNetwork/hostPID必选
限制镜像仓库必选
禁止 latest 标签必选
必须设置资源 requests/limits必选
限制 ingress 域名推荐
必须设置 probe推荐
readOnlyRootFilesystem推荐
限制容器 capabilities高级
限制 egress 网络高级

故障排查

问题排查方向
策略不生效检查 webhook 状态、策略的 match 条件是否正确
误阻断切回 Audit 模式查看详情,调整策略 scope
策略冲突Kyvernor 多个策略针对同一资源时,mutating 按优先级执行
升级后策略报错检查 CRD 版本兼容性,查看 engine 日志