OPA 与 Gatekeeper 策略执行
核心问题:静态扫描在 CI 中检查,但如何阻止不符合规范的资源直接通过 kubectl apply 进入集群?
准入控制器(Admission Controller)
graph LR
USER["kubectl apply
或 ArgoCD 同步"] AUTHN["认证
(Authentication)"] AUTHZ["授权
(RBAC)"] MUT["Mutating
Webhook
(修改资源)"] VAL["Validating
Webhook
(验证资源)"] ETCD["etcd
(存储)"] USER --> AUTHN --> AUTHZ --> MUT --> VAL --> ETCD VAL -->|拒绝| USER
或 ArgoCD 同步"] AUTHN["认证
(Authentication)"] AUTHZ["授权
(RBAC)"] MUT["Mutating
Webhook
(修改资源)"] VAL["Validating
Webhook
(验证资源)"] ETCD["etcd
(存储)"] USER --> AUTHN --> AUTHZ --> MUT --> VAL --> ETCD VAL -->|拒绝| USER
Gatekeeper 是基于 OPA(Open Policy Agent)的 Kubernetes 准入控制器,在 Validating Webhook 阶段执行自定义策略。
安装 Gatekeeper
# Helm 安装
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm upgrade --install gatekeeper gatekeeper/gatekeeper \
--namespace gatekeeper-system \
--create-namespace \
--version "3.14.0" \
--set replicas=2 \
--set auditInterval=30
两步定义策略
Step 1:ConstraintTemplate(策略模板)
用 Rego 语言定义规则逻辑:
# ConstraintTemplate:要求容器设置 CPU/内存 Limits
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredresourcelimits
spec:
crd:
spec:
names:
kind: K8sRequiredResourceLimits
validation:
openAPIV3Schema:
type: object
properties:
containers:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredresourcelimits
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.resources.limits.cpu
msg := sprintf("容器 '%v' 必须设置 CPU limits", [container.name])
}
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.resources.limits.memory
msg := sprintf("容器 '%v' 必须设置 Memory limits", [container.name])
}
Step 2:Constraint(策略实例)
声明策略应用的范围:
# Constraint:在 production 命名空间强制执行
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredResourceLimits
metadata:
name: production-resource-limits
spec:
match:
kinds:
- apiGroups: ["apps"]
kinds: ["Deployment", "StatefulSet", "DaemonSet"]
namespaces: ["production", "staging"]
enforcementAction: deny # deny | warn | dryrun
常用内置策略
# 安装 Gatekeeper Library(官方策略集合)
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper-library/master/library/general/allowedrepos/template.yaml
要求镜像来自指定仓库
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sallowedrepos
spec:
crd:
spec:
names:
kind: K8sAllowedRepos
validation:
openAPIV3Schema:
type: object
properties:
repos:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sallowedrepos
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not starts_with(container.image, input.parameters.repos[_])
msg := sprintf("镜像 '%v' 不在允许的仓库列表中", [container.image])
}
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
name: allowed-repos
spec:
match:
kinds:
- apiGroups: ["*"]
kinds: ["Pod"]
namespaces: ["production"]
parameters:
repos:
- "registry.example.com/" # 私有仓库
- "bitnami/" # 允许 bitnami 官方镜像
禁止 latest tag
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sDisallowedTags
metadata:
name: no-latest-tag
spec:
match:
kinds:
- apiGroups: ["*"]
kinds: ["Pod"]
enforcementAction: deny
parameters:
tags: ["latest"]
要求必要标签
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredLabels
metadata:
name: required-labels
spec:
match:
kinds:
- apiGroups: ["apps"]
kinds: ["Deployment"]
namespaces: ["production"]
parameters:
labels:
- key: app.kubernetes.io/name
- key: app.kubernetes.io/version
- key: team
Mutating Webhook:自动注入默认值
Gatekeeper 也支持 MutationPolicy(v3.10+)自动为资源添加默认配置:
apiVersion: mutations.gatekeeper.sh/v1
kind: Assign
metadata:
name: assign-default-security-context
spec:
applyTo:
- groups: [""]
kinds: ["Pod"]
versions: ["v1"]
match:
scope: Namespaced
namespaces: ["production"]
location: "spec.securityContext.runAsNonRoot"
parameters:
assign:
value: true # 自动为所有 Pod 设置 runAsNonRoot: true
审计模式:现有资源合规检查
# 查看违规资源列表
kubectl get k8srequiredresourcelimits -o yaml
# 查看所有 Constraint 的违规情况
kubectl get constraints -A
# 查看具体违规
kubectl describe k8srequiredresourcelimits production-resource-limits
# Violations:
# - Message: 容器 'nginx' 必须设置 CPU limits
# Resource: namespace: production, name: nginx-deployment, group: apps, version: v1, kind: Deployment
OPA vs Kyverno 对比
| 维度 | OPA/Gatekeeper | Kyverno |
|---|---|---|
| 策略语言 | Rego(专用) | YAML(K8s 原生风格) |
| 学习曲线 | 高(需学 Rego) | 低(纯 YAML) |
| 功能 | 极强(任意 Rego 表达式) | 足够(常见场景全覆盖) |
| Mutating | 支持(v3.10+) | 强大(Pattern/Overlay) |
| 社区 | 成熟,有大量模板 | 快速增长 |
Kyverno 简化示例(无需学 Rego):
# Kyverno Policy:禁止 latest tag(YAML 风格)
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: "镜像必须指定具体版本 tag,不能使用 :latest"
pattern:
spec:
containers:
- image: "!*:latest"