K8s 安全进阶:基于 OPA Gatekeeper 实现细粒度的镜像拉取控制
在企业级的 Kubernetes (K8s) 集群管理中,镜像安全是供应链安全的第一道防线。如果允许开发者随意从公共镜像仓库(如 Docker Hub)拉取镜像,可能会引入包含漏洞的包、恶意脚本,甚至因为镜像版本混乱导致生产事故。
本文将详细探讨如何利用 OPA (Open Policy Agent) Gatekeeper 这一工业级标准工具,通过“策略即代码”(Policy as Code)的方式,为 K8s 集群构建一套细粒度的镜像拉取控制体系。
一、 为什么选择 OPA Gatekeeper?
传统的 K8s 准入控制主要依赖内置的 ImagePolicyWebhook 或早期的 PodSecurityPolicy(已废弃)。而 OPA Gatekeeper 的优势在于:
- 灵活性:使用声明式语言 Rego,可以编写极其复杂的逻辑。
- 可扩展性:支持自定义资源定义 (CRD),策略逻辑与配置分离。
- 审计功能:不仅能拦截违规请求,还能定期审计存量资源。
二、 核心架构简述
Gatekeeper 作为 Kubernetes 的一个 Validating Admission Webhook 运行。当用户尝试创建 Pod 时,API Server 会将请求发送给 Gatekeeper,Gatekeeper 根据预定义的策略(Constraint)进行校验,决定是 Allow 还是 Deny。
三、 实战:限制镜像来源与标签
我们要实现两个核心目标:
- 仓库限制:只允许从公司内部私有仓库(如
harbor.example.com)拉取镜像。 - 标签控制:严禁在生产环境使用
:latest标签,强制要求具体版本号。
1. 安装 Gatekeeper
首先,在集群中部署 Gatekeeper 服务:
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/master/deploy/gatekeeper.yaml
2. 定义策略模板 (ConstraintTemplate)
ConstraintTemplate 定义了 Rego 逻辑。它像是一个函数,定义了“如何校验”。
创建一个名为 k8s-image-policy-template.yaml 的文件:
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8simagepolicy
spec:
crd:
spec:
names:
kind: K8sImagePolicy
validation:
openAPIV3Schema:
type: object
properties:
allowedPrefixes:
type: array
items: { type: string }
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8simagepolicy
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
satisfied := [good | prefix := input.parameters.allowedPrefixes; startswith(container.image, prefix)]
not any(satisfied)
msg := sprintf("镜像 <%v> 不在许可名单内,请使用内网仓库镜像", [container.image])
}
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
endswith(container.image, ":latest")
msg := sprintf("镜像 <%v> 禁止使用 :latest 标签", [container.image])
}
逻辑解释:
- 第一个
violation块利用startswith函数检查镜像前缀是否在allowedPrefixes列表中。 - 第二个
violation块利用endswith检查镜像名是否以:latest结尾。
3. 实例化约束 (Constraint)
有了模板后,我们需要传入具体的参数。例如,指定合法的仓库地址。
创建 k8s-image-constraint.yaml:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sImagePolicy
metadata:
name: image-must-be-from-harbor
spec:
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
parameters:
allowedPrefixes:
- "harbor.example.com/"
- "k8s.gcr.io/" # 视情况保留系统镜像库
四、 策略测试与验证
场景 A:尝试拉取 Docker Hub 镜像
kubectl run test-nginx --image=nginx:1.21
结果:请求会被拒绝,报错:admission webhook "validation.gatekeeper.sh" denied the request: 镜像 <nginx:1.21> 不在许可名单内...
场景 B:使用私有仓库但带了 latest 标签
kubectl run test-harbor --image=harbor.example.com/base/nginx:latest
结果:请求被拒绝,报错:镜像 <...> 禁止使用 :latest 标签。
场景 C:合规请求
kubectl run test-ok --image=harbor.example.com/base/nginx:v1.21
结果:Pod 正常创建。
五、 进阶建议:Dry Run 与平滑过渡
在生产环境直接开启拦截(Deny)具有较大风险,可能导致现有的自动化流水线中断。Gatekeeper 提供了 enforcementAction 参数:
- dryrun:只在日志和 Constraint 的 Status 中记录违规行为,不进行实际拦截。建议在策略上线初期使用,观察是否有漏掉的合法镜像。
- warn:返回警告信息给用户,但允许请求通过。
spec:
enforcementAction: dryrun # 或者 warn
六、 总结
通过 OPA Gatekeeper,我们将镜像拉取策略从“口头约束”转变为“代码强制”。这种细粒度的控制不仅提升了 K8s 集群的安全水位,还规范了开发者的部署习惯。
在实际应用中,建议将 Rego 策略文件纳入 GitOps 工作流,通过 CI/CD 自动同步到集群,实现策略的版本化管理。此外,除了镜像控制,你还可以扩展出 CPU/Memory 限制、Ingress 域名检测、特权容器禁用等更多安全策略。