K8s 安全准入:OPA Gatekeeper 与 Kyverno
学习 K8s安全准入 相关知识
K8s 安全准入:OPA Gatekeeper 与 Kyverno
1. 准入控制机制
请求流程
kubectl apply → 认证 → 授权(RBAC) → 准入控制(MutatingWebhook) → 准入控制(ValidatingWebhook) → etcd 存储
↓ ↓
修改资源定义 验证资源合法性
(OPA/Kyverno mutating) (OPA/Kyverno validating)
两种策略引擎对比
| 维度 | OPA Gatekeeper | Kyverno |
|---|---|---|
| 策略语言 | Rego(声明式 DSL) | YAML(K8s 原生风格) |
| 学习曲线 | 陡峭,需学 Rego | 平缓,现有 K8s 用户可上手 |
| 复杂策略 | 强(Rego 表达力强) | 中 |
| 社区成熟度 | CNCF graduated | CNCF incubating |
| 变更策略 | mutation | mutation(更强) |
| 策略来源 | ConstraintTemplate + Constraint | ClusterPolicy / 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 的策略分两层:
- ConstraintTemplate — 定义策略逻辑(Rego 代码)
- 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 日志 |