Docker底层-User Namespace

复制代码
root@LAPTOP-LU4HDAFV:~# id
uid=0(root) gid=0(root) groups=0(root),987(docker)
root@LAPTOP-LU4HDAFV:~# echo $$
285399
root@LAPTOP-LU4HDAFV:~# cat /proc/$$/uid_map
         0          0 4294967295
root@LAPTOP-LU4HDAFV:~# 

UID/GID 详解

基本概念

  • UID (User ID):用户标识符,Linux 用数字标识用户
  • GID (Group ID):组标识符,Linux 用数字标识用户组

    ┌─────────────────────────────────────────────────────────┐
    │ Linux 用户系统结构 │
    │ │
    │ ┌──────────────────────────────────────────────────┐ │
    │ │ 用户名 (Username) │ │
    │ │ │ │
    │ │ 例如:alice, bob, root │ │
    │ │ (人类可读的名称) │ │
    │ └──────────────────────────────────────────────────┘ │
    │ │ │
    │ │ 映射关系 │
    │ ↓ │
    │ ┌──────────────────────────────────────────────────┐ │
    │ │ UID (User ID) │ │
    │ │ │ │
    │ │ 例如:1000, 1001, 0 │ │
    │ │ (系统内部使用的数字) │ │
    │ └──────────────────────────────────────────────────┘ │
    │ │ │
    │ │ 属于某个组 │
    │ ↓ │
    │ ┌──────────────────────────────────────────────────┐ │
    │ │ GID (Group ID) │ │
    │ │ │ │
    │ │ 例如:1000, 1001, 0 │ │
    │ │ (用户所属组的数字) │ │
    │ └──────────────────────────────────────────────────┘ │
    │ │
    │ 系统实际使用 UID/GID,而不是用户名! │
    └─────────────────────────────────────────────────────────┘

为什么需要 UID/GID?

  1. 性能:数字比较更快
  1. 唯一性:每个用户有唯一 UID
  1. 系统内部:内核使用数字,用户名只是映射

    ┌─────────────────────────────────────────────────────────┐
    │ 用户名 vs UID │
    │ │
    │ 人类视角: │
    whoami │ │ alice │ │ │ │ 系统视角: │ │ id │
    │ uid=1000(alice) gid=1000(alice) │
    │ │
    │ 内核实际使用: │
    │ UID: 1000 ← 内核只认识这个数字 │
    │ GID: 1000 ← 内核只认识这个数字 │
    │ │
    │ 用户名 "alice" 只是方便人类记忆的别名! │
    └─────────────────────────────────────────────────────────┘

User Namespace 工作原理详解

核心概念:UID/GID 映射

User Namespace 通过映射表将 Namespace 内的 UID/GID 映射到主机上的真实 UID/GID。

复制代码
┌─────────────────────────────────────────────────────────┐
│  User Namespace 的 UID/GID 映射机制                     │
│                                                          │
│  ┌──────────────────────────────────────────────────┐  │
│  │ 主机上的真实用户                                  │  │
│  │                                                  │  │
│  │  用户:alice                                     │  │
│  │  UID: 1000  (主机上的真实 UID)                  │  │
│  │  GID: 1000  (主机上的真实 GID)                  │  │
│  │                                                  │  │
│  │  执行命令:                                       │  │
│  │  unshare --user --map-root-user /bin/bash        │  │
│  │         │                                        │  │
│  │         └─────────┐                              │  │
│  └───────────────────┼──────────────────────────────┘  │
│                      │                                  │
│                      │ 创建新的 User Namespace           │
│                      ↓                                  │
│  ┌──────────────────────────────────────────────────┐  │
│  │ User Namespace 内部                               │  │
│  │                                                  │  │
│  │  ┌──────────────────────────────────────────┐   │  │
│  │  │ UID/GID 映射表                          │   │  │
│  │  │                                        │   │  │
│  │  │ Namespace UID  →  主机 UID             │   │  │
│  │  │ ──────────────    ─────────            │   │  │
│  │  │      0        →     1000               │   │  │
│  │  │      1        →     1001               │   │  │
│  │  │      2        →     1002               │   │  │
│  │  │    ...        →     ...                │   │  │
│  │  │   65534       →    106534              │   │  │
│  │  └──────────────────────────────────────────┘   │  │
│  │                                                  │  │
│  │  进程在 Namespace 内看到:                       │  │
│  │  $ id                                            │  │
│  │  uid=0(root) gid=0(root) groups=0(root)         │  │
│  │                                                  │  │
│  │  但实际上映射到主机的 UID 1000!                 │  │
│  └──────────────────────────────────────────────────┘  │
│                                                          │
│  关键:Namespace 内的 root (uid=0) 映射到主机的 UID 1000 │
└─────────────────────────────────────────────────────────┘

为什么不需要 root 权限?

Linux 内核允许普通用户创建 User Namespace(自 Linux 3.8 起),原因:

  1. 安全性:Namespace 内的 root 权限被限制在 Namespace 内
  1. 隔离性:无法影响主机上的其他进程
  1. 映射机制:通过 UID/GID 映射表控制权限

    ┌─────────────────────────────────────────────────────────┐
    │ 权限检查流程 │
    │ │
    │ 进程在 User Namespace 内执行操作: │
    │ │
    │ 1. 访问 Namespace 内的文件 │
    │ ↓ │
    │ 检查:Namespace 内的 UID (0) │
    │ ✓ 允许(在 Namespace 内是 root) │
    │ │
    │ 2. 访问主机上的文件 │
    │ ↓ │
    │ 检查:映射后的主机 UID (1000) │
    │ ✗ 拒绝(主机上不是 root) │
    │ │
    │ 3. 影响主机上的其他进程 │
    │ ↓ │
    │ 检查:映射后的主机 UID (1000) │
    │ ✗ 拒绝(主机上不是 root) │
    │ │
    │ 结论:Namespace 内的 root 权限被限制在 Namespace 内! │
    └─────────────────────────────────────────────────────────┘

    ┌─────────────────────────────────────────────────────────┐
    │ 1. 普通用户执行命令 │
    │ │
    unshare --user --map-root-user /bin/bash │ │ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ 2. 内核创建新的 User Namespace │ │ │ │ │ │ │ │ • 分配新的 Namespace ID │ │ │ │ • 创建新的进程(bash) │ │ │ │ • 设置初始 UID/GID 映射 │ │ │ └──────────────────────────────────────────────────┘ │ │ │ │ │ ↓ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ 3. --map-root-user 自动设置映射表 │ │ │ │ │ │ │ │ /proc/self/uid_map: │ │ │ │ 0 <当前用户UID> 1 │ │ │ │ │ │ │ │ /proc/self/gid_map: │ │ │ │ 0 <当前用户GID> 1 │ │ │ └──────────────────────────────────────────────────┘ │ │ │ │ │ ↓ │ │ ┌──────────────────────────────────────────────────┐ │ │ │ 4. 进程在 Namespace 内运行 │ │ │ │ │ │ │ │ id │ │
    │ │ uid=0(root) gid=0(root) │ │
    │ │ │ │
    │ │ 但实际权限检查时: │ │
    │ │ • Namespace 内操作 → 使用 UID 0 │ │
    │ │ • 主机操作 → 使用映射后的 UID 1000 │ │
    │ └──────────────────────────────────────────────────┘ │
    │ │ │
    │ ↓ │
    │ ┌──────────────────────────────────────────────────┐ │
    │ │ 5. 权限检查机制 │ │
    │ │ │ │
    │ │ 访问 Namespace 内资源: │ │
    │ │ ✓ 使用 Namespace UID (0) → 有 root 权限 │ │
    │ │ │ │
    │ │ 访问主机资源: │ │
    │ │ ✗ 使用主机 UID (1000) → 只有普通用户权限 │ │
    │ └──────────────────────────────────────────────────┘ │
    └─────────────────────────────────────────────────────────┘

相关推荐
oscar99933 分钟前
构建敏捷团队的DevOps测试策略:速度与可靠性的平衡艺术
运维·测试·devops
青衫客3634 分钟前
浅谈Kubernetes在systemd cgroup模式下的Slice/Scope组织结构
云原生·容器·kubernetes
王九思1 小时前
Podman 介绍
docker·云原生·kubernetes·podman
星辰&与海1 小时前
Proxmox导入虚拟机后进入dracut紧急模式
运维
Serverless社区2 小时前
进阶指南:BrowserUse + Agentrun Sandbox 最佳实践指南
运维·阿里云·云原生·serverless·函数计算
Maggie_ssss_supp2 小时前
Linux-MySQL权限管理
linux·运维·mysql
石像鬼₧魂石2 小时前
Kali Linux 内网渗透:深度工程实施手册
linux·运维·服务器
运维螺丝钉3 小时前
docker安装应用
运维·docker·容器
以太浮标4 小时前
华为eNSP模拟器综合实验之- 路由表RIB和转发表FIB的关联解析
运维·网络·华为·信息与通信
optimistic_chen4 小时前
【Docker入门】cgroups 资源控制
linux·运维·ubuntu·docker·容器·cgroup