
核心要点(TL;DR)
- 容器逃逸的本质是突破命名空间与Capabilities边界,最终在宿主机提权。
- 特权容器、CAP_SYS_ADMIN、挂载docker.sock与宿主机根目录是最高频逃逸入口。
- eBPF可在内核态无侵入监控进程、文件与网络行为,适合做运行时逃逸检测。
- 加固优先级:去特权与降Capabilities > seccomp/AppArmor > eBPF审计告警。
很多团队把容器当成「轻量虚拟机」,默认它自带隔离,直到某天发现容器里能读到宿主机的 /etc/shadow,或者一个被入侵的 Pod 直接改写了节点上的 kubelet 配置。容器逃逸不是单一漏洞,而是一连串配置错误的叠加结果;而传统基于主机的入侵检测看不到容器内的短生命周期进程。本文从可执行的排查命令出发,讲清逃逸路径、加固顺序,以及如何用 eBPF 做运行时行为监控。
容器逃逸到底在突破什么边界
容器依赖 Linux 的 namespace 做视图隔离、cgroups 做资源限制、Capabilities 做权限切分。逃逸的本质是让容器内进程获得超出预期的能力,进而操作宿主机内核或文件系统。常见落点有三类:
- 权限边界:特权容器、
CAP_SYS_ADMIN、CAP_SYS_PTRACE等危险能力。 - 文件边界:挂载
docker.sock、宿主机根目录、/proc或/sys。 - 内核边界:利用内核漏洞或错误配置的 runtime 完成提权。
前两类不需要任何 CVE,靠一条 docker run --privileged 就能实现,因此基线加固永远优先于漏洞修补。
先排查:五条命令定位高危容器
在节点上依次执行,输出结果即为待整改清单。
# 1. 列出特权容器
docker ps -q | xargs docker inspect \
--format '{{.Name}} privileged={{.HostConfig.Privileged}}'
# 2. 查看容器挂载的宿主机路径
docker ps -q | xargs docker inspect \
--format '{{.Name}} {{range .Mounts}}{{.Source}}->{{.Destination}} {{end}}'
# 3. 检查是否挂载了 docker.sock
docker ps -q | xargs docker inspect \
--format '{{.Name}} {{range .Mounts}}{{.Source}}{{end}}' | grep docker.sock
# 4. 查看容器内有效能力位
docker exec grep CapEff /proc/1/status
capsh --decode=0000003fffffffff
# 5. 检查是否共享宿主机 PID/网络命名空间
docker ps -q | xargs docker inspect \
--format '{{.Name}} pid={{.HostConfig.PidMode}} net={{.HostConfig.NetworkMode}}'Kubernetes 环境可用 kubectl get pod -A -o json 配合 jq 过滤 securityContext.privileged 与 hostPath 字段,批量导出风险工作负载。
分步加固:从去特权到最小能力集
第一步:去掉特权与多余能力
容器默认能力集已包含 CHOWN、NET_RAW 等,但 SYS_ADMIN 必须显式添加。加固时采用白名单:
# docker run 示例
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE \
--security-opt=no-new-privileges myapp:latest
# Kubernetes 示例
securityContext:
allowPrivilegeEscalation: false
privileged: false
capabilities:
drop: ["ALL"]
add: ["NET_BIND_SERVICE"]
readOnlyRootFilesystem: true第二步:收紧挂载与命名空间
禁止挂载 /var/run/docker.sock;必须共享宿主机目录时,用只读挂载并限定子路径。避免 hostPID: true 与 hostNetwork: true,除非是 CNI 或监控类组件。
第三步:启用 seccomp 与 AppArmor
Kubernetes 1.19 起可直接使用 RuntimeDefault:
securityContext:
seccompProfile:
type: RuntimeDefault先用默认 profile 铺开观察,再按业务系统调用白名单收紧,避免一次性过严导致进程被 kill。
第四步:用 eBPF 做运行时检测
eBPF 在内核态挂载探针,无侵入捕获 execve、openat、connect 等事件,适合发现「容器内提权」「写入敏感路径」「加载内核模块」等逃逸前兆。以 Tetragon 为例:
helm repo add cilium https://helm.cilium.io
helm install tetragon cilium/tetragon -n kube-system
kubectl logs -n kube-system -l app.kubernetes.io/name=tetragon -f重点关注以下行为并配置告警:容器进程调用 mount 挂载宿主机设备、写入 /etc/ 与 /proc/sys、执行 insmod、连接云元数据地址 169.254.169.254。规则先以告警模式运行,噪声稳定后再考虑阻断。
加固项对比与优先级清单
| 加固项 | 防护类型 | 实施成本 | 优先级 |
|---|---|---|---|
| 去特权、降 Capabilities | 预防 | 低 | P0 |
| 禁止敏感挂载与 hostPath | 预防 | 低 | P0 |
| seccomp/AppArmor | 预防 | 中 | P1 |
| eBPF 运行时告警 | 检测 | 中 | P1 |
| 镜像签名与准入控制 | 预防 | 高 | P2 |
若使用托管安全能力,AegisX 的运行时防护模块可基于 eBPF 采集容器行为并内置逃逸规则集,减少自建规则与调参成本,适合没有专职安全团队的小规模集群。
行动建议
- 本周内跑完上述五条排查命令,输出特权容器与敏感挂载清单。
- 对清单逐项整改,先在测试集群验证
allowPrivilegeEscalation: false与cap-drop=ALL对业务的影响。 - 在单节点部署 Tetragon 或 Falco,只开四类高危规则,观察一周告警噪声。
- 把逃逸检测告警接入现有值班通道,并明确「容器内提权」事件的一键隔离流程。
容器安全没有银弹,但顺序很明确:先关掉不该开的口子,再用运行时观测兜住未知行为。配置收敛带来的收益,远大于追逐下一个内核 CVE。
常见问题(FAQ)
容器逃逸检测最该先查什么?
先查特权容器与危险Capabilities。执行docker ps --quiet | xargs docker inspect --format '{{.Name}} {{.HostConfig.Privileged}}'可列出特权容器;再用capsh --print或读取/proc/1/status的CapEff确认能力位。特权容器几乎等于宿主机root,应优先清理,其次检查是否挂载了/var/run/docker.sock与宿主机根目录。
eBPF做运行时防护需要改业务代码吗?
不需要。eBPF程序挂载在内核的tracepoint、kprobe或LSM钩子上,通过观测系统调用与进程行为实现监控,业务容器无侵入。常见做法是用Falco、Tetragon或Tracee加载规则,捕获execve、openat、connect等事件,再按容器ID与命名空间过滤,输出告警到日志或SIEM。
没有内核漏洞也可能被逃逸吗?
会。配置错误比内核漏洞更常见:特权容器、CAP_SYS_ADMIN、挂载docker.sock、hostPath挂载宿主机根目录、共享PID命名空间,都能让容器内进程直接操作宿主机资源。攻击者无需利用CVE即可提权,因此基线加固应优先于漏洞修补。
seccomp和AppArmor还要不要上?
要上,且与eBPF互补。seccomp限制可用系统调用面,AppArmor约束文件与能力访问,属于预防层;eBPF负责观测与告警,属于检测层。建议先以RuntimeDefault的seccomp配置铺开,再按业务白名单收紧,避免一次性过严导致业务中断。
小团队如何低成本落地运行时防护?
先做资产盘点与基线加固,再用单节点部署Tetragon或Falco验证规则,确认告警噪声可接受后逐步扩展。重点规则只需覆盖:容器内提权、写入敏感路径、加载内核模块、连接元数据服务。初期以告警模式运行,稳定后再对高危行为启用阻断。