要深度审计容器运行时非法系统调用,需结合 docker 27 原生 containerd/runc-audit 插件、falco ebpf 实时拦截及日志关联分析:启用 runc-audit 替代默认 runc 捕获 namespace 切换、capset 等逃逸行为;用 falco 规则检测 execve、openat 等高危 syscall 并输出完整上下文;通过 container_id 和时间戳对齐 daemon 日志、runc-audit 日志与 falco 日志,实现逃逸链全还原;统一 journald 驱动并归档至 loki/elk,保留 ≥180 天,对 critical 事件自动告警与容器冻结。

要深度审计容器运行时的非法系统调用,不能只依赖 Docker daemon 默认日志——它不记录容器内进程发起的 execve、openat、mmap、setns 等底层系统调用。真正有效的审计需向上穿透到 containerd/runc 层,并向下对接内核事件源。核心思路是:让非法调用“可识别、可归属、可上下文还原”。
用 Docker 27 原生日志审计捕获逃逸级系统调用
Docker 27(基于 containerd 1.7+ + runc-audit)首次将命名空间切换、capabilities 变更、敏感挂载等行为直接注入审计流,无需手动配置 auditd 规则。
- 编辑
/etc/containerd/config.toml,启用审计运行时插件:[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] SystemdCgroup = true BinaryName = "runc-audit" # 替换默认 runc RuntimeRoot = "/run/runc"
- 重启 containerd:
sudo systemctl restart containerd - 验证是否生效:
sudo auditctl -l | grep -E "(containerd|runc)" - 合法调用如普通
ls会生成type=CONTAINER_EVENT msg=... context=namespace_transition;而攻击者执行unshare -r /bin/sh则触发type=CONTAINER_ESCAPE_ATTEMPT severity=HIGH context=escape_attempt container_id=abc123
该机制自动携带 container_id、pod_name、sandbox_id 和调用进程的 uid/gid,避免传统 auditd 中容器与宿主机进程日志混杂的问题。
结合 Falco 实时拦截高风险 syscall 行为
Docker 守护进程日志不覆盖容器内部行为,Falco 弥补这一缺口,通过 eBPF 拦截并结构化输出可疑调用:
- 检测提权类调用:
- rule: CapsetInContainer condition: kevt and container and syscall = capset and proc.uid = 0 output: Capability set attempted in container (user=%user.name container=%container.info cmdline=%proc.cmdline) priority: CRITICAL
- 捕获异常文件访问:
- rule: ReadShadowInContainer condition: open_read and container and fd.name contains "/etc/shadow" output: Attempt to read /etc/shadow in container %container.id
- 所有告警自带
proc.cmdline、user.name、k8s.pod.name(若在 K8s 环境),可直接关联到具体工作负载。
关联守护进程日志与容器内 syscall 日志
单看某一方日志都会断链。例如 docker exec -u 0 nginx sh:
- daemon 日志(journald)记录:
UID=1001, cmd=docker exec -u 0 nginx sh→ 知道“谁在何时发起特权 exec” - runc-audit 日志记录:
container_id=xyz, syscall=setns, ns_type=CLONE_NEWUSER, effective_uid=0→ 知道“容器内是否完成 UID 命名空间切换” - Falco 日志记录:
syscall=execve, proc.name=sh, user.name=root, container.image=nginx:alpine→ 知道“最终执行了什么 shell”
三者通过 container_id 和时间戳对齐,就能还原完整逃逸链:用户发起特权 exec → 容器内成功进入 newuser ns → 启动交互式 shell → 尝试读取宿主机敏感文件。
强制日志结构化与长期归档
避免日志被覆盖或解析失败:
- 统一使用
journald驱动,配置/etc/docker/daemon.json:{ "log-driver": "journald", "log-opts": { "tag": "docker-daemon-{{.Name}}-{{.ID}}" } } - 所有 audit 日志(
/var/log/audit/audit.log)和 journal 日志均通过rsyslog或Promtail推送至 Loki 或 ELK,保留 ≥180 天 - 对
type=CONTAINER_ESCAPE_ATTEMPT和priority=CRITICAL的 Falco 事件启用Alertmanager即时通知,并自动冻结对应容器(调用docker pauseAPI)
不复杂但容易忽略











