实现多租户云容器沙箱化需协同用户命名空间与子uid/gid映射:为各租户预分配不重叠的独立id范围(如tenant-a:100000:65536),配置/etc/subuid与/subgid,启用docker的userns-remap,绑定专属rootfs并设对应属主,再结合mount/pid/net/uts等命名空间及seccomp过滤,达成进程、网络、文件系统级彻底隔离。

要实现多租户云场景下的容器级服务彻底沙箱化,核心不是“加一层隔离”,而是让每个租户在容器内拥有完整 root 体验的同时,在宿主机上只表现为一个普通、受限、不可越界的用户。这依赖用户命名空间(userns)与子UID/GID映射的协同落地,缺一不可。
为每个租户预分配独立、不重叠的子UID/GID范围
这是沙箱化的根基。不能复用同一段ID,否则租户间权限边界就形同虚设。
- 编辑 /etc/subuid 和 /etc/subgid,每行对应一个租户用户,格式为 用户名:起始ID:数量
- 例如:tenant-a:100000:65536 表示租户 tenant-a 在宿主机上可使用 UID/GID 100000–165535 这 65536 个值
- 下一个租户必须错开:如 tenant-b:165536:65536,确保全局无重叠
- 起始值避开 0–99999(系统保留区),且租户用户需真实存在于 /etc/passwd 中
启用运行时级用户命名空间重映射
仅配 subuid 文件不会自动生效,必须由容器引擎主动触发映射逻辑。
- Docker:在 /etc/docker/daemon.json 中添加 "userns-remap": "tenant-a",然后 systemctl restart docker
- LXD:对容器执行 lxc config set
security.idmap.isolated true ,或全局启用 core.userns.mode=auto - 验证是否生效:进入容器后执行 cat /proc/self/uid_map,应看到类似 0 100000 65536 ——即容器内 UID 0 映射到宿主机 UID 100000
绑定挂载与文件属主同步,堵住文件系统逃逸路径
用户命名空间管进程身份,但不管文件权限。若容器挂载的目录属主仍是 root,那租户仍可能通过 chown/chmod 突破限制。
- 为每个租户准备独立根目录,如 /srv/tenant-a/rootfs,并设基础权限:chmod 700 /srv/tenant-a/rootfs
- 将该目录属主设为映射起始 UID:chown 100000:100000 /srv/tenant-a/rootfs
- 启动容器时显式挂载,禁用默认继承:docker run --volume /srv/tenant-a/rootfs:/mnt:ro ...
- 必要时配合 ACL 进一步屏蔽反向访问:setfacl -m u:tenant-b:--- /srv/tenant-a/rootfs
组合其他命名空间,形成完整隔离平面
单靠 user namespace 不足以防逃逸。它必须和 mount、pid、net、uts 等协同,构成真正“看不见、摸不着、连不上”的沙箱。
- 启动时强制启用关键命名空间:unshare --user --pid --mount --net --uts --fork /bin/bash
- 在新命名空间中立即执行:mount --make-rprivate /,防止挂载传播污染宿主机
- 配合 seccomp 或 AppArmor,禁止 setuid、chown、mount 等高危系统调用,避免绕过映射
- 验证效果:容器内 ps aux 只见自身进程;ip a 看不到宿主机网卡;hostname 修改不影响宿主机











