3. Kubernetes Pod 安全上下文配置验证
为什么 Pod 安全上下文是攻击面入口
Pod 的 securityContext 决定了容器进程以什么身份、拥有哪些内核能力、能否访问宿主机命名空间。以下三类配置一旦开启,容器逃逸与横向移动的门槛会显著降低:
privileged: true:容器获得几乎等同宿主机的设备与能力访问权,可直接挂载宿主机磁盘、加载内核模块。hostNetwork: true:Pod 共享宿主机网络命名空间,可监听宿主机端口、嗅探本机流量、访问 127.0.0.1 上的管理接口。hostPID: true:Pod 共享宿主机 PID 命名空间,可看到并可能向宿主机进程发送信号、读取其/proc信息。
本案例的任务是:先部署一个同时包含上述不安全配置的 Pod,用 kubectl 确认它确实被调度运行;再部署 OPA Gatekeeper 约束,验证同样的 Pod 被拒绝,并记录违规详情。
验证环境与前置条件
假设集群已具备以下条件(示例环境,非实测结果):
- Kubernetes 集群可正常
kubectl apply,当前上下文具备创建 Pod 与 CRD 的权限。 - 已安装 OPA Gatekeeper(
gatekeeper-system命名空间下gatekeeper-controller-manager处于 Running)。 - 测试命名空间
sec-test已创建:kubectl create ns sec-test。
若尚未安装 Gatekeeper,可用官方清单安装(版本以实际拉取为准):
kubectl apply -f https://raw.githubusercontent.com/open-policy-agent/gatekeeper/master/deploy/gatekeeper.yaml
kubectl -n gatekeeper-system get pods -w
第一步:部署不安全 Pod 并确认其运行状态
下面的清单同时开启特权模式、hostNetwork、hostPID,并挂载宿主机根目录,用于暴露最典型的危险组合:
cat <<'EOF' | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: insecure-pod
namespace: sec-test
labels:
app: insecure-demo
spec:
hostNetwork: true
hostPID: true
containers:
- name: attacker
image: busybox:1.36
command: ["sleep", "3600"]
securityContext:
privileged: true
runAsUser: 0
allowPrivilegeEscalation: true
volumeMounts:
- name: host-root
mountPath: /host
volumes:
- name: host-root
hostPath:
path: /
EOF
确认调度与运行状态,并读取实际生效的安全上下文字段:
kubectl -n sec-test get pod insecure-pod -o wide
kubectl -n sec-test get pod insecure-pod \
-o jsonpath='{.spec.hostNetwork}{" "}{.spec.hostPID}{" "}{.spec.containers[0].securityContext.privileged}{"\n"}'
# 预期输出:true true true
进入容器验证宿主机可见性(仅用于授权测试环境):
kubectl -n sec-test exec insecure-pod -- ls /host/etc | head
kubectl -n sec-test exec insecure-pod -- ps -ef | head
若能看到宿主机 /etc 内容与宿主机进程列表,说明该 Pod 已具备高危能力,这正是后续策略需要拦截的对象。
第二步:用 Gatekeeper 约束拦截不安全配置
Gatekeeper 的拦截由两部分组成:ConstraintTemplate 定义可复用的 Rego 规则,Constraint 实例化规则并指定作用范围。下面模板同时检查 privileged、hostNetwork、hostPID 与 hostPath 挂载:
cat <<'EOF' | kubectl apply -f -
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sblockunsafepod
spec:
crd:
spec:
names:
kind: K8sBlockUnsafePod
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sblockunsafepod
violation[{"msg": msg}] {
c := input.review.object.spec.containers[_]
c.securityContext.privileged == true
msg := sprintf("container %v uses privileged mode", [c.name])
}
violation[{"msg": msg}] {
input.review.object.spec.hostNetwork == true
msg := "pod uses hostNetwork"
}
violation[{"msg": msg}] {
input.review.object.spec.hostPID == true
msg := "pod uses hostPID"
}
violation[{"msg": msg}] {
v := input.review.object.spec.volumes[_]
v.hostPath
msg := sprintf("volume %v mounts hostPath %v", [v.name, v.hostPath.path])
}
EOF
等待 CRD 建立后创建约束实例,仅作用于 sec-test 命名空间,避免影响系统组件:
cat <<'EOF' | kubectl apply -f -
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sBlockUnsafePod
metadata:
name: block-unsafe-pod
spec:
enforcementAction: deny
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
namespaces: ["sec-test"]
EOF
kubectl get constrainttemplate k8sblockunsafepod
kubectl get k8sblockunsafepod block-unsafe-pod
第三步:验证拦截效果并记录违规详情
先删除已存在的 Pod,再重新提交同一清单,观察是否被拒绝:
kubectl -n sec-test delete pod insecure-pod --ignore-not-found
kubectl apply -f insecure-pod.yaml
预期返回类似错误(具体措辞随 Gatekeeper 版本略有差异):
Error from server (Forbidden): error when creating "insecure-pod.yaml":
admission webhook "validation.gatekeeper.sh" denied the request:
[block-unsafe-pod] container attacker uses privileged mode;
[block-unsafe-pod] pod uses hostNetwork;
[block-unsafe-pod] pod uses hostPID;
[block-unsafe-pod] volume host-root mounts hostPath /
逐条记录违规详情,便于形成审计证据:
kubectl get k8sblockunsafepod block-unsafe-pod -o yaml | \
grep -A 20 "status:"
若需确认策略是否覆盖其他命名空间,可临时把 namespaces 改为 ["*"] 后重放测试,但生产环境应谨慎扩大范围。
结果判读与常见问题
| 观察项 | 策略生效前 | 策略生效后 |
|---|---|---|
kubectl get pod | Running | 不存在(创建被拒) |
hostNetwork/hostPID | true / true | 请求未进入 etcd |
privileged | true | 请求未进入 etcd |
| 错误信息 | 无 | 列出全部违规条目 |
- 若 Pod 仍能创建,先确认 Constraint 的
match.namespaces是否包含sec-test,以及kubectl get constrainttemplate是否已建立。 - 若错误信息为空,检查 Gatekeeper 控制器日志:
kubectl -n gatekeeper-system logs deploy/gatekeeper-controller-manager。 - 若只想告警不阻断,可把
enforcementAction改为warn或dryrun,再观察审计结果。
验证完成后,建议删除测试 Pod 与约束实例,避免影响后续实验:
kubectl -n sec-test delete pod insecure-pod --ignore-not-found、kubectl delete k8sblockunsafepod block-unsafe-pod。