3. 容器运行时安全:容器隔离机制与逃逸防护策略

容器运行时安全是云原生安全基线的核心防线。本章聚焦于容器隔离的底层机制(Namespace / Cgroups)、强制访问控制模块(Seccomp / AppArmor / SELinux)的基础配置,以及容器逃逸的防护策略。理解这些机制并正确配置初始策略组,是构建安全容器环境的前提。

3.1 容器隔离机制:Namespace 与 Cgroups

容器通过 Linux 内核的两大特性实现资源隔离与限制:Namespace 负责“隔离视图”,Cgroups 负责“限制资源”。两者协同工作,为容器提供轻量级的虚拟化环境。

3.1.1 Namespace:进程视图隔离

Namespace 将全局系统资源(如进程 ID、网络栈、挂载点)封装到独立的命名空间中,使容器内的进程只能看到自己的资源视图。关键 Namespace 类型如下:

Namespace 类型 隔离资源 安全意义
PID 进程 ID 编号 容器内无法看到宿主机或其他容器的进程
Network 网络设备、IP 地址、路由表 容器拥有独立的网络栈,避免网络攻击横向扩散
Mount 文件系统挂载点 容器只能访问自己的文件系统视图
UTS 主机名与域名 容器拥有独立的主机名
IPC 进程间通信资源(信号量、消息队列) 防止跨容器 IPC 干扰
User 用户 ID 与组 ID 容器内 root 用户映射为宿主机非特权用户
Cgroup Cgroup 视图 容器无法查看宿主机 Cgroup 信息
安全基线建议: 默认情况下 Docker 会启用所有 Namespace。在 Kubernetes 中,Pod 的 shareProcessNamespace 字段应保持默认 false,避免容器间共享 PID 命名空间。

3.1.2 Cgroups:资源限制与审计

Cgroups(Control Groups)用于限制、记录和隔离进程组的物理资源(CPU、内存、磁盘 I/O、网络带宽)。在安全层面,Cgroups 主要防止“资源耗尽型”攻击(如 Fork Bomb、内存泄漏)。

  • CPU 限制: 通过 cpu.shares 和 cpu.cfs_quota_us 防止单个容器抢占所有 CPU 时间。
  • 内存限制: 通过 memory.limit_in_bytes 设置硬限制,超出则触发 OOM Kill。
  • 进程数限制: 通过 pids.max 限制容器内最大进程数,防止 Fork Bomb 攻击。
  • 设备白名单: 通过 devices.allow 控制容器对宿主机设备的访问。
# 示例:通过 cgconfig 配置容器内存限制(单位:字节)
group container-demo {
  memory {
    memory.limit_in_bytes = 536870912;  # 512MB
    memory.memsw.limit_in_bytes = 1073741824;  # 内存+交换 1GB
  }
  pids {
    pids.max = 100;  # 最大 100 个进程
  }
}
常见误区: 仅依赖 Cgroups 无法阻止容器逃逸。Cgroups 限制的是资源使用量,而非系统调用权限。必须与 Seccomp、AppArmor 等强制访问控制机制配合使用。

3.2 强制访问控制:Seccomp / AppArmor / SELinux

Namespace 和 Cgroups 提供了基础隔离,但无法阻止容器内进程发起危险系统调用(如 mount、ptrace、open_by_handle_at)。强制访问控制模块在系统调用层和文件访问层提供细粒度安全策略。

3.2.1 Seccomp:系统调用过滤

Seccomp(Secure Computing Mode)允许容器运行时定义系统调用白名单或黑名单。Docker 默认提供 default 配置文件,阻止约 44 个危险系统调用。

Seccomp 模式 行为 适用场景
SCMP_ACT_ALLOW 允许系统调用 白名单模式中的允许项
SCMP_ACT_ERRNO 拒绝并返回错误(如 EPERM) 阻止危险系统调用
SCMP_ACT_KILL 立即终止进程 检测到恶意行为时强制终止
SCMP_ACT_TRAP 触发 SIGSYS 信号 调试与审计场景
# 自定义 Seccomp 配置文件示例:仅允许基本系统调用
{
  "defaultAction": "SCMP_ACT_ERRNO",
  "architectures": ["SCMP_ARCH_X86_64"],
  "syscalls": [
    {
      "names": ["read", "write", "open", "close", "mmap", "munmap", "exit", "exit_group"],
      "action": "SCMP_ACT_ALLOW"
    }
  ]
}
基线配置: 在 Kubernetes 中,通过 securityContext.seccompProfile 字段为 Pod 指定 Seccomp 配置。生产环境建议使用 RuntimeDefault 或自定义严格白名单。

3.2.2 AppArmor:路径与网络访问控制

AppArmor 使用“路径匹配”模式,通过加载配置文件(profile)限制程序对文件系统、网络和 Linux 能力的访问。Docker 默认提供 docker-default 配置文件。

# AppArmor 配置文件示例:限制容器只能读取 /data 目录
#include <tunables/global>

profile container-restricted flags=(attach_disconnected,mediate_deleted) {
  #include <abstractions/base>

  # 允许读取 /data 目录
  /data/** r,

  # 拒绝写入 /etc 和 /proc
  /etc/** wlx,
  /proc/** wlx,

  # 拒绝网络访问
  network,
  deny network tcp,
  deny network udp,
}

3.2.3 SELinux:标签化强制访问控制

SELinux 通过安全上下文(Security Context)为进程、文件、设备等主体和客体打标签,基于策略规则控制访问。在容器场景中,SELinux 为每个容器分配唯一的 MCS(Multi-Category Security)标签,实现容器间隔离。

  • 类型强制(TE): 定义进程类型(如 container_t)与文件类型(如 container_file_t)的访问规则。
  • 多类别安全(MCS): 为每个容器分配随机类别标签(如 s0:c1,c2),防止容器间相互访问文件。
  • 布尔值策略: 通过 getsebool 和 setsebool 动态调整策略(如 container_use_devices)。
# 查看容器 SELinux 上下文
docker inspect --format='{{.ProcessLabel}}' <container_id>
# 输出示例:system_u:system_r:container_t:s0:c1,c2

# 启用 SELinux 的 Docker 配置(/etc/docker/daemon.json)
{
  "selinux-enabled": true
}
三选一还是组合使用? Seccomp、AppArmor 和 SELinux 并非互斥。推荐组合策略:Seccomp 过滤系统调用 + AppArmor 控制文件/网络访问 + SELinux 提供标签级隔离。在 Kubernetes 中,可通过 securityContext 同时配置三者。

3.3 容器逃逸防护策略

容器逃逸是指攻击者突破容器隔离边界,获得宿主机或集群其他节点的访问权限。逃逸路径通常分为三类:内核漏洞利用、配置缺陷、能力滥用。

3.3.1 常见逃逸路径与防护矩阵

逃逸路径 攻击原理 防护策略
内核漏洞(如 CVE-2022-0847) 利用内核提权漏洞突破 Namespace 及时更新内核、启用 Seccomp 阻止漏洞利用链
挂载宿主机敏感目录 挂载 /proc、/sys、/dev 后修改内核参数 禁止挂载宿主机 /proc、/sys;使用只读挂载
Docker Socket 暴露 容器内访问 /var/run/docker.sock 创建特权容器 禁止挂载 Docker Socket;使用非 root 用户运行容器
Capability 滥用 赋予 SYS_ADMIN、SYS_PTRACE 等危险 Capability 遵循最小 Capability 原则;默认删除所有 Capability 再按需添加
特权容器(--privileged) 容器拥有所有 Capability 并访问所有设备 禁止使用特权容器;使用 securityContext.privileged: false
User Namespace 未启用 容器内 root 等于宿主机 root 启用 User Namespace 重映射(--userns-remap)

3.3.2 逃逸防护策略清单

  1. 最小权限原则: 删除所有 Capability(--cap-drop=ALL),仅按需添加(如 --cap-add=NET_BIND_SERVICE)。
  2. 只读根文件系统: 设置 readOnlyRootFilesystem: true,防止攻击者写入恶意文件。
  3. 禁止特权升级: 设置 allowPrivilegeEscalation: false,阻止 setuid 提权。
  4. 非 root 用户运行: 在 Dockerfile 中指定 USER 指令,或在 Pod 中设置 runAsNonRoot: true。
  5. 启用 Seccomp 严格模式: 使用自定义 Seccomp 配置文件,阻止 mount、ptrace、open_by_handle_at 等逃逸关键系统调用。
  6. AppArmor/SELinux 强制策略: 加载自定义配置文件,限制容器对宿主机文件系统和网络的访问。
  7. 禁用主机网络与 PID 命名空间: 避免使用 hostNetwork: true 和 hostPID: true。
  8. 运行时安全监控: 部署 Falco 或 Tracee 等运行时安全工具,实时检测异常系统调用和文件访问。
关键警示: 容器逃逸防护不是单一配置能解决的。必须将 Namespace/Cgroups 隔离、Seccomp/AppArmor/SELinux 强制访问控制、最小权限策略和运行时监控组合成纵深防御体系。任何单一环节的缺失都可能成为逃逸突破口。

3.4 容器运行时安全纵深防御架构

下图展示了容器运行时安全的纵深防御架构,从内核层到应用层形成多层防护。

容器运行时安全纵深防御架构 第1层:内核隔离(Namespace + Cgroups) PID / Network / Mount / User Namespace 隔离进程视图 Cgroups 限制 CPU / 内存 / 进程数 / 设备访问 第2层:系统调用过滤(Seccomp) 白名单模式:仅允许 read / write / mmap 等基础系统调用 阻止 mount / ptrace / open_by_handle_at 等逃逸关键调用 第3层:强制访问控制(AppArmor / SELinux) AppArmor:路径匹配限制文件/网络访问 SELinux:MCS 标签实现容器间文件隔离 第4层:最小权限策略 删除所有 Capability → 按需添加;只读根文件系统;非 root 用户运行 禁止特权升级;禁用 hostNetwork / hostPID 第5层:运行时监控(Falco / Tracee) 纵深防御 缺一不可

3.5 初始策略组配置清单

以下为容器运行时安全的初始策略组配置清单,适用于 Kubernetes 环境:

策略项 推荐配置 配置位置
Seccomp 配置 seccompProfile.type: RuntimeDefault Pod SecurityContext
AppArmor 配置 container.apparmor.security.beta.kubernetes.io/<container>: runtime/default Pod 注解
SELinux 配置 seLinuxOptions.type: container_t Pod SecurityContext
Capability 限制 capabilities.drop: ["ALL"] Container SecurityContext
特权模式 privileged: false Container SecurityContext
特权升级 allowPrivilegeEscalation: false Container SecurityContext
只读根文件系统 readOnlyRootFilesystem: true Container SecurityContext
非 root 用户 runAsNonRoot: true Pod SecurityContext
User Namespace hostUsers: false(K8s v1.27+) Pod Spec
主机网络/主机 PID hostNetwork: false、hostPID: false Pod Spec
基线验证命令: 使用 kube-bench 或 kubectl audit 定期检查集群中 Pod 的安全上下文配置是否符合基线。例如:kubectl get pods -o json | jq '.items[].spec.containers[].securityContext'