linux设备白名单(deviceallow)本质是cgroups devices控制器的规则机制,通过“默认拒绝、显式允许”实现内核级设备访问控制,需结合最小化--device挂载、capability裁剪和devices.allow规则分层落实。

Linux设备白名单(DeviceAllow)本质是 cgroups devices 控制器的规则机制,它不依赖 Docker CLI 原生参数,而是通过内核级设备访问控制实现“默认拒绝、显式允许”。要精准限制容器硬件触达范围,关键不是堆砌参数,而是分层落实:挂载最小设备集 + 剥离高危能力 + 用 devices.allow 精确放行。
只挂载真正需要的设备节点
这是最直接有效的第一道防线。Docker 默认不挂载任何宿主机设备(如 /dev/sda、/dev/video0、/dev/kvm),必须显式声明才可见、才可访问。
- 语法格式:docker run --device :[:r|:w|:rw]
- 只读挂载更安全:例如摄像头仅需读取,用 --device /dev/video0:/dev/video0:r;即使进程有 root 权限,也无法写入或调用 ioctl 控制参数
- 避免宽泛挂载:严禁使用 --device /dev:/dev:rwm 或 --privileged,这等于放弃设备隔离
- 不挂载 = 不可见:没加 --device 的设备,容器内 ls /dev 下根本不会出现对应节点,连 open() 都会报 ENOENT
剥离 capability 阻断设备操作权
挂载只是让设备文件存在,能否操作还取决于进程权限。很多硬件操作(如 mknod 创建设备、mount 绑定、修改 /sys/class/ 下属性)需特定 capability 支持。
- 默认清空所有能力:--cap-drop=ALL,再按需添加(如仅 --cap-add=NET_BIND_SERVICE)
- 重点禁用:--cap-drop=SYS_ADMIN(防止创建设备、挂载、修改 cgroup)、--cap-drop=SYS_RAWIO(防止直接 I/O 访问内存或端口)
- 配合安全选项:--security-opt=no-new-privileges:true,阻止容器内二进制通过 setuid 提权后绕过设备限制
用 devices.allow 实现内核级白名单
当需批量控制(如允许多个 tty 设备但禁止所有块设备),或运行时动态调整策略时,devices.allow 是核心手段。它工作在 cgroups v2 层,Docker 20.10+ 默认启用 systemd cgroup manager 后自动生效。
- 规则格式:c 4:64 rwm 表示主设备号 4(tty)、次设备号 64(如 /dev/ttyS0),允许读、写、mknod
- 通配更灵活:c 188:* rmw 允许全部 USB 串口设备(主号 188),b *:* r 仅允许读所有块设备(不包括写和 mknod)
- 禁止某设备:先清除默认全通规则 echo a > /sys/fs/cgroup/devices.devices.deny,再逐条添加允许项;或直接 echo 'b 8:16 w' > /sys/fs/cgroup/devices.devices.deny 禁止对 /dev/sdb 写入
- Docker 中传入规则:--device-cgroup-rule='c 1:3 rwm'(允许 /dev/null)、--device-cgroup-rule='b *:* r'(只读所有块设备)——注意该参数需宿主机 cgroups v2 支持且 Docker daemon 配置正确
验证与兜底防护
配置完不能只靠“应该可以”,必须验证实际效果。
- 进容器检查:ls -l /dev 确认只有预期设备存在;cat /proc/self/cgroup | grep devices 查看当前 cgroup 路径;cat /sys/fs/cgroup/devices/devices.list 查看已生效的 allow/deny 规则
- 尝试越权操作:dd if=/dev/zero of=/dev/sda bs=1 count=1 应报 Permission denied;mknod /tmp/test c 1 3 应报 Operation not permitted(若已 drop SYS_ADMIN 且未在 devices.allow 中放行)
- 生产环境兜底:--read-only 挂载根文件系统,防止容器内恶意重建 /dev 下节点;卸载宿主机非必要驱动(如 sudo rmmod nvidia_uvm)从源头移除设备节点











