一篇文章了解容器安全 | Linux Namespace 进程编号隔离(2/7) 云原生安全学习之容器安全 | Linux Namespace 进程编号隔离2/7如果说网络隔离是各走一路那么进程编号隔离是各开一栋楼。但这栋楼不是真的从地基上切出来的内核还是那一整块内核物理层面进程表也还是那一张全局进程表。PID Namespace 只是给容器包了一层包装纸——容器里查进程看到的是包装纸上的本地进程表被包装的小内核的表宿主机查进程看到的是包装纸背后的全局进程表。物理上它们还是粘在一起的只是权限等级的不同决定能看到的。为什么需要进程编号隔离容器不是独立的内核也不是单独的电脑。容器本质上就是宿主机上的一组普通进程和宿主机共享同一个 Linux 内核。内核里有一张全局进程表所有进程都在上面如果没有这层包装容器里的ps一查直接看到全局表——宿主机的 sshd、systemd、其他容器的进程全暴露在它的视野里PID Namespace 就是这张包装纸它给容器伪造了一张本地进程表让容器只能查自己的户口本。容器查的是包装纸内的视图宿主机查的是包装纸外的全局视图——内核没切只是视角切了但这里要分清PID Namespace 解决的是信息暴露问题不是权限控制问题。它让容器看不到外面的进程但不代表容器不能操作外面的进程。真正的进程间访问控制靠的是 capabilities、seccomp、AppArmor 这些机制此文章不包括这些进程编号隔离空间的本质Docker/K8s默认给每个容器独立的 PID Namespace这是基础设施的基线配置不是可选项。PID Namespace 能隔离容器与外面空间宿主机、其他 Namespace的进程视图但它不能隔离同一个空间内部的进程。同一个 PID Namespace 内的进程互相可见、可发信号、可 ptrace。Namespace 隔离的是内外不是内部成员之间。容器内的PID 1是用户指定的进程比如 nginx、bash而宿主机上这个进程有一个真实的全局 PID。容器以为自己独占 PID 1实际上宿主机内核知道它的真实编号。这是视图隔离的典型特征——各看各的但底层是同一个事实。双重视角同一进程两个世界假设 LiQiu 容器正在运行容器内的 bash 进程同时存在于两个视角中容器内部视角LiQiu 里执行 ps auxUSER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 4628 3840 pts/0 Ss 16:20 0:00 bash root 8 0.0 0.0 8900 5120 pts/0 R 16:21 0:00 ps auxPID 1是你的 bash你觉得这是整个世界你看不到宿主机的 systemd、sshd你看不到其他容器的进程如果 LiQiu2 和你在同一个 PID Namespace你还能看到 LiQiu2 的进程宿主机视角宿主机上执行 ps aux | grep bashUSER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 2847 0.0 0.0 4628 3840 ? Ss 16:20 0:00 bash同一个 bash 进程在宿主机上是PID 2847例子宿主机能看到全局进程表包括 LiQiu 的 bash、LiQiu2 的 bash、systemd、sshd全部一览无遗宿主机知道 LiQiu 里的 “PID 1” 其实是全局的 PID 2847各看各的底层同一个事实真正的隔离需要什么PID Namespace 是楼的框架但它只切分了进程编号的命名空间。ps命令实际读的是/proc文件系统——这是窗户。如果/proc还是宿主机的全局 proc → 容器透过窗户看到了外面的世界如果/proc被重新挂载为当前 Namespace 的本地 proc → 窗户封死只能看到楼里--mount-proc参数就是封窗户的动作。PID Namespace 加上重新挂载 proc才是完整的进程编号隔离。缺少任何一步隔离就有缝隙配置结果独立 PID Namespace 重新挂载 proc各开一栋楼完全隔离独立 PID Namespace忘记挂载 proc楼分开了窗户没封ps还能看到外面多个容器共享同一个 PID Namespace同一栋楼楼道互通互相杀伤另外要注意即使 Namespace 和 proc 都配好了如果容器拿到了CAP_SYS_PTRACE权限或者有 seccomp 配置漏洞攻击者仍然可能突破视图隔离。PID Namespace 只是一层包装纸不是安全边界。下面是图片部分实验两个容器共享一个 PID Namespace实验目的验证同一个 PID Namespace 内的进程互相可见但看不到宿主机进程。实验环境Debian 13 LinuxDocker 已安装。步骤 1创建第一个容器 LiQiu不指定 PID Namespacedockerrun-it--nameLiQiu--rmubuntu:22.04bash在 LiQiu 容器内执行psaux预期结果只能看到 LiQiu 容器内的进程PID 1 是 bash看不到宿主机进程。步骤 2创建第二个容器 LiQiu2共享 LiQiu 的 PID Namespace新开一个终端执行dockerrun-it--nameLiQiu2--pidcontainer:LiQiu--rmubuntu:22.04bash在 LiQiu2 容器内执行psaux预期结果能看到 LiQiu 和 LiQiu2 两个容器的所有进程。LiQiu 的 bash 是 PID 1LiQiu2 的 bash 是另一个 PID比如 PID 8。两个容器在同一栋楼楼道互通。步骤 3在 LiQiu2 中向 LiQiu 的进程发信号在 LiQiu2 容器内执行kill-91预期结果LiQiu 容器被强制终止因为共享 PID NamespaceLiQiu2 能看到 LiQiu 的进程并能发信号。同一栋楼互相杀伤。步骤 4验证看不到宿主机进程在 LiQiu2 容器内执行psaux|grepsystemd预期结果看不到宿主机的 systemd 进程。包装纸封住了外面的视野但同一包装纸内的进程互相透明。步骤 5清理dockerstop LiQiu LiQiu2实验结论场景能否看到对方进程能否操作对方进程独立 PID Namespace默认❌❌受 capabilities 限制共享 PID Namespace✅✅同一空间内无额外隔离宿主机进程❌❌视图隔离生效核心理解PID Namespace 是包装纸不是切割机。内核没切只是视角切了。同一包装纸内的进程互相透明不同包装纸之间的进程互相隔离——但隔离的是视图不是权限。隔离不是绝对安全文章只是了解了这个东西的存在