Files
docker_practice/18_security/18.1_kernel_ns.md
T
yeasy ef2625531d style: 含中文的括号统一为全角(336 处 / 110 文件)
全书此前是真·五五开:含中文的括号 336 处半角 : 336 处全角,而且**在同一文件
内混用**——`18_security/18.1_kernel_ns.md` 第 11/17/20 行写 `(如 runC)`,
第 31 行写 `(用户命名空间映射)`。这不是体例问题,是它自己跟自己不一致。

集群里其余 13 本都一边倒(llm_internals 5 : 1049、oc_guide 2 : 713、
forward_deployed_engineering_guide 0 : 108),blockchain_guide 已在 2026-08-05
按同一方向统一过 97 处,故取全角,而非另立新规。全角括号前后不留空格,
原先 `概念 (镜像、容器、仓库) 和` 两侧的空格一并收掉。

**纯拉丁内容的半角括号一个没动**——`新建一个层 (Layer)`、`项目 (project)`
保持原样:改动前后「半角且内容纯拉丁」的数量都是 **1163**,而「半角且含中文」
从 **336 变成 0**。

其余验证:改动前后各自抹掉全部空白与圆括号后**逐字节相同**(两侧均 19559 字符);
左右括号总数改动前后都是 399 : 399,证明没有吞括号也没有配错对。
`check_project_rules` 202/202、`check_emphasis` 202/202、37 tests OK、
根 `format_checker` 与 `validate_codeblocks` 干净、`git diff --check` 干净。
2026-08-24 13:13:23 -07:00

84 lines
4.8 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 18.1 内核命名空间
命名空间 (Namespace) 是 Linux 容器隔离的基础,它确保了容器内的进程无法直接干扰主机或其他容器。虽然在本书第 12 章中我们已经从底层实现的角度介绍了 Namespace,但在本节中,我们将重点探讨其 **安全意义** 及相关配置。
### 18.1.1 隔离的安全本质
Docker 守护进程在启动容器时,会在后台为容器创建一套独立的命名空间。命名空间提供了最基础也是最直接的隔离:
- **PID Namespace**:防止容器内的进程查看或终止宿主机或其他容器的进程。恶意攻击者即使在容器内获得了 root 权限,也无法通过 `kill` 命令影响宿主机上的关键服务。
- **NET Namespace**:每个容器都有自己独立的网络栈。如果没有显式地进行端口映射或将容器连接到同一网络,容器之间无法网络互通,从而限制了横向移动的能力。
- **MNT Namespace**:为容器提供独立的文件系统视图。这可以防止容器不经意或恶意地修改宿主机的重要系统文件(如 `/etc/passwd`)。
### 18.1.2 命名空间不是绝对安全的护城河
尽管命名空间提供了很好的隔离性,但我们必须认识到:**所有的容器依然共享同一个宿主机的 Linux 内核**。
这意味着,一旦宿主机的内核存在提权漏洞(如著名的 Dirty COW 漏洞),攻击者有可能通过突破 Namespace 的限制,直接在内核层面执行恶意代码,从而实现“容器逃逸”。
> [!WARNING]
> 为了缓解内核漏洞带来的威胁,生产环境务必保持宿主机 Linux 内核的及时修补与更新,或者借助诸如 gVisor、Kata Containers 等提供了独立内核的安全容器技术。同时,需要及时修补容器运行时(如 runC)的漏洞。2025 年 11 月披露的一系列 runC 容器逃逸漏洞(CVE-2025-31133、CVE-2025-52565、CVE-2025-52881)就表明,即使内核保持更新,运行时层的缺陷仍然可能导致容器隔离被突破。
通过命名空间,Docker 也能限制进程从外部环境获取信息。
例如,由于进程环境被隔离,进程在内部通常无法直接感知外部宿主机的进程和挂载命名空间。网络命名空间隔离的是网络栈;默认 bridge 网络通常允许容器主动访问外部网络,限制的是外部直接访问容器服务。若要限制出站访问,需要使用 `none` 网络、防火墙、Kubernetes NetworkPolicy 或运行时策略。
### 18.1.3 用户命名空间与提权防护
在所有的 Namespace 中,**User Namespace** 对安全的影响尤为关键。
在默认情况下,容器内的 `root` 用户(UID=0)就是宿主机上的 `root` 用户。如果攻击者设法突破了容器的其他隔离机制获取了宿主机的访问权限,他将拥有宿主机的最高系统权限。
通过启用 **User Namespace Remapping(用户命名空间映射)**,我们可以将容器内的 `root` 用户映射到宿主机上的一个无特权普通用户。
#### 如何配置 User Namespace
要在 Docker 服务端启用这一特性,需要修改 Docker 的配置文件 `/etc/docker/daemon.json`。
1. **设置映射策略**
编辑配置文件,添加 `userns-remap` 配置项:
```json
{
"userns-remap": "default"
}
```
使用 `default` 值时,Docker 会自动在宿主机上创建一个名为 `dockremap` 的用户和用户组。
2. **验证子 UID 和子 GID 分配**
Docker 会通过 `/etc/subuid` 和 `/etc/subgid` 文件为 `dockremap` 分配一个高位的 UID 范围:
```bash
$ cat /etc/subuid
dockremap:165536:65536
```
这意味着:容器内的 UID `0`(root 用户)在宿主机上实际被映射成了 UID `165536`。如果是容器内的 UID `1`,对应宿主机的 `165537`,以此类推。
3. **重启 Docker 守护进程**
```bash
$ sudo systemctl restart docker
```
#### 验证映射效果
我们可以运行一个简单的容器并执行 `sleep` 命令,同时在宿主机上观察进程的所有者:
```bash
## 在容器内以 root 身份运行
$ docker run -d --name userns_test alpine sleep 3600
## 在宿主机上查看该 sleep 进程
$ ps aux | grep sleep
165536 12345 0.0 0.0 1568 4 ? Ss 14:20 0:00 sleep 3600
```
你会发现,尽管在容器内该进程是由 root 启动的,但在宿主机上,它的属主是 `165536`(一个完全没有特权的用户)。
> [!TIP]
> 启用 User Namespace 会对容器共享宿主机数据卷(Bind Mount)产生权限影响。你需要确保映射后的高位 UID 对宿主机上的挂载目录具有合适的读写权限。
### 18.1.4 总结
内核命名空间从 Linux 2.6.15 版本(2006 年)被引入,十余年间,这些机制的可靠性在诸多大型生产系统中被实践验证。通过合理利用命名空间(尤其是 User Namespace),可以极大地收窄攻击面,显著提升容器部署的安全性。