Privileged 权限:你的容器真的需要吗?

Privileged 权限:你的容器真的需要吗?
Privileged 权限你的容器真的需要吗实验环境Ubuntu 24.04 / 内核 6.8.0-106-generic / Cgroup v2 / Docker 29.1.3 / 华为云 FlexusX 8C16G8vCPU/16G。全程仅做「只读读取宿主文件」「挂载内存盘」等安全演示未对宿主做任何写破坏演示完即卸载/退出。docker run --privileged是运维中最常见的「图省事」写法网络不通加 --privileged权限不够加 --privilegedmount 失败还是 --privileged。它确实「一加就好」但代价是把整台宿主机的钥匙交给了容器。本文用一组对照实验把 --privileged 到底给了什么、危险在哪、以及最小权限怎么给一次讲清。1. 引子一个「加 privileged 就好」的事故某次排查容器里配静态路由失败同事甩手一句「加--privileged试试」——命令一贴路由配通了但容器同时也拿到了宿主全部设备的读写权。如果这容器镜像来源不可控或者跑的是第三方代码这就是一条现成的逃逸路径。关键认知–privileged 不是「多一点权限」而是「放弃容器边界」。下面用实验证明。2. 复现一普通容器里哪些操作被拒新建一个普通容器无任何特权参数尝试三件「敏感操作」# (1) 创建网络接口 - 需要 CAP_NET_ADMIN$dockerrun--rmbusyboxiplinkadddummy0typedummy ip: RTNETLINK answers: Operation not permitted# (2) 挂载文件系统 - 需要 CAP_SYS_ADMIN$dockerrun--rmbusyboxsh-cmount -t tmpfs tmpfs /mntmount: permission denied(are you root?)# busybox 的通用提示本质是缺 CAP_SYS_ADMIN# (3) 修改系统时间 - 需要 CAP_SYS_TIME$dockerrun--rmbusyboxsh-cdate -s\2020-01-01 00:00:00\date: cantsetdate: Operation not permitted三类操作分别对应CAP_NET_ADMIN/CAP_SYS_ADMIN/CAP_SYS_TIME普通容器默认都没有于是被内核干净地拒绝。这是预期且正确的行为——容器不该能改宿主时间、不该能挂宿主文件系统。3. 复现二–privileged 一把梭全部放行同一个容器只加--privileged$dockerrun--privileged--rmbusyboxsh-c ip link add dummy0 type dummy echo LINK_ADD_OK mount -t tmpfs tmpfs /mnt echo MOUNT_OK date -s\2020-01-01 00:00:00\/dev/null 21 echo DATE_SET_OK ip link del dummy0 2/dev/null; umount /mnt 2/dev/nullLINK_ADD_OK MOUNT_OK DATE_SET_OK一句话–privileged 把 ip/mount/date 全放开了。它等价于「给全部 capability 关闭 seccomp 关闭 AppArmor 共享所有宿主设备」。 convenient但也意味着容器此时几乎和宿主机 root 平起平坐。4. 复现三–privileged 的危险——看得见宿主磁盘4.1 /dev 可见性对比$echo-n普通容器可见 /dev 条目数: ;dockerrun--rmbusyboxsh-cls /dev | wc -l普通容器可见 /dev 条目数:15$echo-n特权容器可见 /dev 条目数: ;dockerrun--rm--privilegedbusyboxsh-cls /dev | wc -l特权容器可见 /dev 条目数:186$dockerrun--rm--privilegedbusyboxls/dev/vda* /dev/vda /dev/vda1# 宿主的 root 磁盘设备普通容器里根本看不到普通容器只看到 15 个经过过滤的设备节点特权容器直接看到宿主的整块系统盘/dev/vda1。4.2 逃逸演示挂载宿主根盘、读到 /etc/shadow最直白的逃逸只读挂载、仅读取不破坏宿主# 方式A特权 卷挂载把宿主根目录挂进容器$dockerrun--privileged--rm-v/:/host busyboxsh-c head -2 /host/etc/shadow ls -d /host/rootroot:$6$U1lmc3ta$/fRHfNApxwF6bxTMA7LRzWXuKx9jIavlRafFOHIYpW.AINDkf9OESrN.ZTkVIw0PLqkvYA002fgL5SfbBYoHA.:20657:0:99999:7::: daemon:*:19836:0:99999:7::: /host/root# 宿主的 /root 目录在容器里完全可见可写容器里直接读到了宿主的/etc/shadow并看到了宿主/root。一旦镜像或应用代码不可信这就是完整的「容器→宿主」逃逸能改宿主/etc/shadow、能写宿主crontab、能植入持久化后门。真实攻击链往往更简单特权容器 nsenter -t 1 -m -u -n -i sh直接进宿主 PID 1 的命名空间或挂载宿主磁盘后改/etc/cron.d。本文只演示读取点到为止。5. 原理剖析–privileged 到底改了什么容器「权限」由三层独立机制共同决定–privileged 把这三层全部打开5.1 Capabilities能力位图Linux 把传统 root 的「超级权」拆成 ~40 个细粒度 capability。进程的有效能力写在/proc/pid/status的CapEff字段十六进制位图。# 普通容器$dockerrun--rmbusyboxsh-cgrep CapEff /proc/self/statusCapEff: 00000000a80425fb# 特权容器$dockerrun--rm--privilegedbusyboxsh-cgrep CapEff /proc/self/statusCapEff: 000001ffffffffff# 全部位为 1 拥有所有 capability# 解码普通容器的位图看 Docker 默认给了哪些$NHEX00000000a80425fb $ capsh--decode$NHEX0x00000000a80425fbcap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill, cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw, cap_sys_chroot,cap_mknod,cap_audit_write,cap_setfcap对比宿主自身root 全开$ capsh--print|head-2Current:ep Boundingsetcap_chown,cap_dac_override,...,cap_bpf,cap_checkpoint_restore# 全 40 项$grepCapEff /proc/self/status CapEff: 000001ffffffffff结论普通容器只拿了 14 个相对安全的默认 capability–privileged 一次性补齐到全部。问题就出在「补齐的全集」里包含cap_sys_admin、cap_sys_ptrace、cap_sys_module等高危项——它们单独任何一个都足以威胁宿主。5.2 seccomp系统调用过滤Docker 默认给每个容器套一个 seccomp 白名单禁止一批危险 syscall如mount、ptrace、kexec_load、bpf部分等即使进程有对应 capability 也会被拦。验证# 只给 CAP_SYS_ADMIN但默认 seccomp 仍拦 mount$dockerrun --cap-add SYS_ADMIN--rmbusyboxsh-cmkdir -p /mnt; mount -t tmpfs tmpfs /mntmount: mounting tmpfs on /mnt failed: Permission denied# 仍然不行# 关掉 seccomp 还是不行 —— 因为还有 AppArmor$dockerrun --cap-add SYS_ADMIN --security-optseccompunconfined--rmbusyboxsh-c...mount:... Permission denied# 三个闸门全开mount 才成功$dockerrun --cap-add SYS_ADMIN --security-optseccompunconfined\--security-optapparmorunconfined--rmbusyboxsh-cmkdir -p /mnt; mount -t tmpfs tmpfs /mnt echo MOUNT_YESMOUNT_YES这条链路是本文最重要的结论capability 是「必要不充分」条件seccomp 和 AppArmor 是另外两道独立闸门。--privileged同时关掉三道全 capability seccompunconfined apparmorunconfined所以「什么都能干」。5.3 AppArmorMAC 强制访问控制Ubuntu 上 Docker 默认套docker-defaultAppArmor profile它对 mount、文件写等做了 deny 规则。上面实验已证明即便给了 SYS_ADMIN 且关了 seccomp只要 AppArmor 还在mount仍被拒——必须--security-opt apparmorunconfined才放行。6. 方案最小权限Least Privilege怎么给核心原则不要 --privileged只通过--cap-add给恰好够用的那一项 capability并保持 seccomp/AppArmor 默认开启。6.1 实战只给 NET_ADMIN$echo-n仅加 NET_ADMIN 能否 ip link add: $dockerrun --cap-add NET_ADMIN--rmbusyboxsh-cip link add dummy0 type dummy echo YES || echo NOYES# 网络管理权限到位操作成功$echo-n仅加 NET_ADMIN 能否 mount(应仍不行): $dockerrun --cap-add NET_ADMIN--rmbusyboxsh-cmkdir -p /mnt; mount -t tmpfs tmpfs /mnt 21 echo YES || echo NONO# mount 依然被拒 —— 因为没给 SYS_ADMIN也没放开 seccomp/AppArmor只加NET_ADMIN容器能管网络但依然无法挂载、看不到宿主磁盘——这正是「够用就好」的状态。6.2 Docker 默认 capability 与常见场景对照表需求场景所需 capabilityDocker 默认就有怎么给绑定 80/443 等特权端口cap_net_bind_service✅ 默认有无需额外操作ping/ 原始套接字cap_net_raw✅ 默认有无需额外操作chown改文件属主cap_chown✅ 默认有无需额外操作chrootcap_sys_chroot✅ 默认有无需额外操作创建/删除网络接口、iptablescap_net_admin❌--cap-add NET_ADMIN改系统时间cap_sys_time❌--cap-add SYS_TIME加载内核模块cap_sys_module❌--cap-add SYS_MODULE极危险慎用挂载文件系统cap_sys_admin 放开 seccomp AppArmor❌见下尽量避开改文件能力位cap_setfcap✅ 默认有无需额外操作关于「挂载」绝大多数「容器里要 mount」的需求正确解法不是给 SYS_ADMIN而是需要宿主机目录 → 用-v /host/path:/container/path卷挂载宿主机侧控制好权限需要特殊文件系统 → 在宿主侧挂好再 bind 进容器实在要在容器内 mount如某些 CSI 插件才考虑cap_sys_admin 自定义 seccomp/AppArmor且必须配合只读、非特权镜像、受信任代码。6.3 排查清单判断一个容器「权限是否过大」docker inspect c --format {{.HostConfig.Privileged}}是否 true —— 是则立即告警。docker inspect c --format {{.HostConfig.CapAdd}}看额外加了哪些 cap逐个核对是否必需。docker inspect c --format {{.HostConfig.SecurityOpt}}看 seccomp/AppArmor 是否被 unconfined。进容器grep CapEff /proc/self/status拿到位图capsh --decodehex解码确认没有sys_admin/sys_module/sys_ptrace等高危项。检查是否挂了宿主根或敏感目录-v /:/x、-v /etc:/x。7. 总结普通容器里ip link add/mount/date -s被拒是因为缺对应 capabilityNET_ADMIN / SYS_ADMIN / SYS_TIME。--privileged一次性给全部 capability 关闭 seccomp 关闭 AppArmor 共享宿主所有设备容器因此能看到宿主磁盘/dev/vda1、能挂载并读到宿主/etc/shadow——典型的逃逸路径。权限是三层闸门capabilities必要不充分、seccomp拦危险 syscall、AppArmorMAC 限制。三者任一在mount 等高危操作仍会被挡–privileged 把三者全开。正确做法绝不 --privileged用--cap-add 单一cap给最小权限挂载需求优先用卷挂载而非 SYS_ADMIN。排查靠docker inspect的 Privileged/CapAdd/SecurityOpt 字段以及容器内CapEff位图解码。8. 思考题你的 CICD 里有没有--privileged的容器列出它们「到底需要哪一项能力」能否改成--cap-add既然 seccomp 默认就拦了mount为什么很多「提权」文章仍强调「禁止 --privileged」它的额外风险如cap_sys_ptracensenter是什么cap_sys_admin被称为「小特权」它单独就能做哪些危害宿主的事不止 mount如果业务真的必须容器内 mount如存储插件你认为「SYS_ADMIN 自定义 seccomp 非特权镜像 只读根文件系统」这套组合比 --privileged 安全在哪下一篇《容器中不用 root 运行程序》—— 我们将实测 root 容器在挂载目录上制造的属主混乱并演示 DockerfileUSER、UID 映射与userns-remap三种「降权」方案。

最新新闻

日新闻

周新闻

月新闻