Add more content and fix format

This commit is contained in:
Baohua Yang
2026-02-25 21:06:21 -08:00
parent dd449bc84f
commit ecab788013
119 changed files with 566 additions and 496 deletions

View File

@@ -1,18 +1,85 @@
## 18.1 内核命名空间
命名空间 (Namespace) Linux 容器隔离的基础它确保了容器内的进程无法干扰主机或其他容器
命名空间 (Namespace) Linux 容器隔离的基础它确保了容器内的进程无法直接干扰主机或其他容器虽然在本书第 12 章中我们已经从底层实现的角度介绍了 Namespace但在本节中我们将重点探讨其**安全意义**及相关配置
Docker 容器和 LXC 容器很相似所提供的安全特性也差不多当用 `docker run` 启动一个容器时在后台 Docker 为容器创建了一个独立的命名空间和控制组集合
### 18.1.1 隔离的安全本质
命名空间提供了最基础也是最直接的隔离在容器中运行的进程不会被运行在主机上的进程和其它容器发现和作用
Docker 守护进程在启动容器时会在后台为容器创建一套独立的命名空间命名空间提供了最基础也是最直接的隔离
每个容器都有自己独有的网络栈意味着它们不能访问其他容器的 sockets 或接口不过如果主机系统上做了相应的设置容器可以像跟主机交互一样的和其他容器交互当指定公共端口或使用 links 来连接 2 个容器时容器就可以相互通信了 (可以根据配置来限制通信的策略)
- **PID Namespace**防止容器内的进程查看或终止宿主机或其他容器的进程恶意攻击者即使在容器内获得了 root 权限也无法通过 `kill` 命令影响宿主机上的关键服务
- **NET Namespace**每个容器都有自己独立的网络栈如果没有显式地进行端口映射或将容器连接到同一网络容器之间无法网络互通从而限制了横向移动的能力
- **MNT Namespace**为容器提供独立的文件系统视图这可以防止容器不经意或恶意地修改宿主机的重要系统文件 `/etc/passwd`
从网络架构的角度来看所有的容器通过本地主机的网桥接口相互通信就像物理机器通过物理交换机通信一样
### 18.1.2 命名空间不是绝对安全的护城河
那么内核中实现命名空间和私有网络的代码是否足够成熟
尽管命名空间提供了很好的隔离性但我们必须认识到**所有的容器依然共享同一个宿主机的 Linux 内核**
内核命名空间从 2.6.15 版本 (2006 1 月发布) 之后被引入数年间这些机制的可靠性在诸多大型生产系统中被实践验证
这意味着一旦宿主机的内核存在提权漏洞如著名的 Dirty COW 漏洞攻击者有可能通过突破 Namespace 的限制直接在内核层面执行恶意代码从而实现容器逃逸
实际上命名空间的想法和设计提出的时间要更早最初是为了在内核中引入一种机制来实现 [OpenVZ](https://en.wikipedia.org/wiki/OpenVZ) 的特性。
OpenVZ 项目早在 2005 年就发布了其设计和实现都已经十分成熟
> [!WARNING]
> 为了缓解内核漏洞带来的威胁生产环境务必保持宿主机 Linux 内核的及时修补与更新或者借助诸如 gVisorKata Containers 等提供了独立内核的安全容器技术
通过命名空间Docker 也能限制进程从外部环境获取信息
例如由于进程环境被隔离进程在内部其实是无法感知到外部宿主机的存在的它既不能获取其他容器的进程列表也无法通过网络与其他系统进行交互除非经过配置
### 18.1.1 用户命名空间 与提权防护
在所有的 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可以极大地收窄攻击面显著提升容器部署的安全性

View File

@@ -1,9 +1,102 @@
## 18.2 控制组
控制组是 Linux 容器机制的另外一个关键组件负责实现资源的审计和限制
控制组 (Cgroups) Linux 容器机制的另外一个关键组件如果说命名空间 (Namespace) 决定了容器能**看到**什么那么控制组就决定了容器能**使用**多少资源
它提供了很多有用的特性以及确保各个容器可以公平地分享主机的内存CPU磁盘 IO 等资源当然更重要的是控制组确保了当容器内的资源使用产生压力时不会连累主机系统
在安全领域中资源的不可用性本身就是一种安全威胁控制组负责实现资源的审计和限制这对于抵御资源耗尽型攻击如拒绝服务攻击 DoS至关重要
尽管控制组不负责隔离容器之间相互访问处理数据和进程它在防止拒绝服务 (DDOS) 攻击方面是必不可少的尤其是在多用户的平台 (比如公有或私有的 PaaS) 控制组十分重要例如当某些应用程序表现异常的时候可以保证一致地正常运行和性能
### 18.2.1 为什么资源限制关乎安全
控制组机制始于 2006 内核从 2.6.24 版本开始被引入
默认情况下Docker 容器对系统资源的使用是没有限制的一个容器理论上可以使用宿主机所有的 CPU 计算能力吃光所有的内存耗尽所有的系统 PID
想象一下以下场景
- 一个恶意用户向你暴露在公网的应用发起海量并发请求
- 应用程序逻辑中存在内存泄漏漏洞
- 黑客在入侵容器后在里面运行了挖矿木马程序
如果没有 Cgroups 的限制某个容器内的异常行为或恶意攻击将会榨干宿主机的资源导致宿主机上其他健康的容器甚至 Docker 守护进程自身因为 OOMOut Of Memory崩溃或 CPU 饥饿而停止响应
### 18.2.2 核心资源限制实战
为了确保多租户平台如公有或私有的 PaaS 平台的稳定性或者在生产环境防止服务级联故障我们要养成在启动容器时**显式声明资源上限**的习惯
#### 1. 内存限制
限制内存可以防止应用程序因内存泄漏或恶意载荷导致宿主机 OOM
**关键参数**
- `-m, --memory=""`硬限制容器可使用的最大内存量
- `--memory-swap=""`限制容器可使用的内存与 Swap 总量
**实战示例**
限制容器最多只能使用 512MB 内存并且禁用 Swap memory memory-swap 设置成一样的值即可
```bash
$ docker run -d \
--name web_app \
--memory="512m" \
--memory-swap="512m" \
nginx:alpine
```
如果该容器内的应用尝试分配超过 512MB 的内存该进程将会被内核的 OOM Killer 杀掉但绝不会波及到宿主机的其他部分
#### 2. CPU 限制
限制 CPU 可以防止个别计算密集型的容器垄断 CPU 时间片保证系统的调度公平性
**关键参数**
- `--cpus=<value>`指定容器可以使用的 CPU 核心数量可以是小数
- `-c, --cpu-shares=0`软限制设置容器使用 CPU 的相对权重默认是 1024
**实战示例**
限制容器最多使用 1.5 CPU 核心的算力
```bash
$ docker run -d \
--name worker_app \
--cpus="1.5" \
busybox \
md5sum /dev/urandom
```
即使上面的命令是一个死循环的哈希计算进程容器也永远无法吃满双核 CPU 系统的全部算力
#### 3. 进程数限制
进程炸弹Fork Bomb是一种典型的拒绝服务攻击方式它通过不断 `fork()` 新进程来耗尽系统的进程表条目导致系统无法创建任何新任务
**关键参数**
- `--pids-limit=<number>`限制容器内允许创建的最大进程数
**实战示例**
一个常规的 Web 服务进程数通常在几十到上百之间我们可以设定一个合理的上限来防范 Fork 炸弹
```bash
$ docker run -d \
--name app_service \
--pids-limit=100 \
python:alpine python app.py
```
当容器内的进程总数达到 100 任何尝试派生新进程的操作都会失败并返回 `Resource temporarily unavailable`从而挫败相关的攻击行为
### 18.2.3 最佳实践建议
在生产环境中不仅要在单机使用 Docker 命令时设置这些参数更应当在集群编排工具中将资源配额制度化
例如 Kubernetes 强烈建议为每个 Pod 设置 `requests` `limits`
```yaml
resources:
requests:
memory: "256Mi"
cpu: "250m"
limits:
memory: "512Mi"
cpu: "500m"
```
通过 Cgroups 的资源边界控制你可以从根本上切断一条导致整个系统雪崩的脆弱链路这也进一步使得 Docker 以及容器技术成为了现代高可用服务的基础设施首选

View File

@@ -1,20 +1,86 @@
## 18.3 Docker 服务端防护
## 18.3 服务端防护
运行一个容器或应用程序的核心是通过 Docker 服务端Docker 服务的运行目前需要 root 权限因此其安全性十分关键
Docker 守护进程`dockerd`是容器生命周期的核心驱动力默认情况下Docker 服务的运行需要极高的系统特权root 权限因此其安全性关系到整台宿主机的生死存亡
首先确保只有可信的用户才可以访问 Docker 服务Docker 允许用户在主机和容器间共享文件夹同时不需要限制容器的访问权限这就容易让容器突破资源限制例如恶意用户启动容器的时候将主机的根目录 `/` 映射到容器的 `/host` 目录中那么容器理论上就可以对主机的文件系统进行任意修改了这听起来很疯狂但是事实上几乎所有虚拟化系统都允许类似的资源共享而没法禁止用户共享主机根文件系统到虚拟机系统
如果 Docker 守护进程的访问控制没有做好恶意攻击者可以通过 Docker API 轻易地启动一个特权容器并将宿主机的根目录`/`挂载到容器中从而完全接管服务器
这将会造成很严重的安全后果因此当提供容器创建服务时 (例如通过一个 web 服务器)要更加注意进行参数的安全检查防止恶意的用户用特定参数来创建一些破坏性的容器
为了加强对服务端的保护我们需要从访问控制通信加密和权限最小化三个维度进行加固
为了加强对服务端的保护Docker REST API (客户端用来跟服务端通信) 0.5.2 之后使用本地的 Unix 套接字机制替代了原先绑定在 127.0.0.1 上的 TCP 套接字因为后者容易遭受跨站脚本攻击现在用户使用 Unix 权限检查来加强套接字的访问安全
### 18.3.1 限制 API 访问
用户仍可以利用 HTTP 提供 REST API 访问建议使用安全机制确保只有可信的网络或 VPN或证书保护机制 (例如受保护的 stunnel ssl 认证) 下的访问可以进行此外还可以使用 [HTTPS 和证书](https://docs.docker.com/engine/security/https/)来加强保护
Docker 客户端`docker` 命令通过 REST API 与守护进程进行通信
最近改进的 Linux 命名空间机制将可以实现使用非 root 用户来运行全功能的容器这将从根本上解决了容器和主机之间共享文件系统而引起的安全问题
在早期版本中Docker 有时会绑定在 `127.0.0.1` TCP 套接字上但这容易遭遇跨站脚本跨协议攻击现在的发行版默认使用 Unix Domain Socket`/var/run/docker.sock`并依赖文件系统的权限控制
终极目标是改进 2 个重要的安全特性
#### 原则 1决不可将无认证的 TCP 端口暴露在公网
* 将容器的 root 用户[映射到本地主机上的非 root 用户](https://docs.docker.com/engine/security/userns-remap/),减轻容器和主机之间因权限提升而引起的安全问题;
* 允许 Docker 服务端在[ root 权限 (rootless 模式)](https://docs.docker.com/engine/security/rootless/) 下运行,利用安全可靠的子进程来代理执行需要特权权限的操作。这些子进程将只允许在限定范围内进行操作,例如仅仅负责虚拟网络设定或文件系统管理、配置操作等。
这是最常见的 Docker 被入侵抓去挖矿的原因绝不能在没有任何安全控制的情况下强行开启 `-H tcp://0.0.0.0:2375`
最后建议采用专用的服务器来运行 Docker 和相关的管理服务 (例如管理服务比如 ssh 监控和进程监控管理工具 nrpecollectd )其它的业务服务都放到容器中去运行
如果业务确实需要远程访问 Docker 守护进程**必须启用 TLS 认证机制**让客户端和服务端互相进行证书校验
#### 开启 TLS 认证双向加密
利用安全机制确保只有经过授权的主机网络并在强证书保护下进行通信
1. 首先使用 `openssl` 或基于本地 CA 工具生成一套客户端与服务器的证书
2. 配置 Docker 守护进程通常是 `daemon.json` `dockerd` 启动参数指定证书路径
```bash
dockerd \
--tlsverify \
--tlscacert=ca.pem \
--tlscert=server-cert.pem \
--tlskey=server-key.pem \
-H=0.0.0.0:2376
```
3. 客户端想要连接时也必须出示客户端证书
> [!TIP]
> 配置 TLS 生成证书的完整步骤可以查阅 [Docker 官方 TLS 文档](https://docs.docker.com/engine/security/protect-access/)。在现代编排系统(如 Kubernetes通常会有自动化方案管理这些凭据。
### 18.3.2 保护本地 Socket 访问
哪怕不开启网络端口本地的 `/var/run/docker.sock` 也需要谨慎对待
任何被授予该 Socket 读写权限的用户通常被加入 `docker` 用户组等同于拥有了对宿主机的零成本提权途径无需密码的免密 `sudo` 权限
> [!CAUTION]
> 永远不要将不可信的普通用户加入到 `docker` 用户组中同样在容器编排时尽量避免将宿主机的 `/var/run/docker.sock` 直接映射给普通容器使用这种模式被称为 Docker-in-Docker (DinD) Docker-out-of-Docker (DooD)存在极高的越权风险
### 18.3.3 Rootless 模式 (非特权运行)
为了从根本上解决拥有 Docker socket 就是 root的问题Docker 在近年推出了 **Rootless 模式**
Rootless 模式允许在完全局限于非 `root` 用户的环境中运行 Docker 守护进程`dockerd`和容器该模式利用了现代 Linux 内核的 User Namespace 技术和非特权网络命名空间实现
#### 配置运行 Rootless Docker
要在非 root 环境中运行 Docker只需要简单几步
1. 安装必要的依赖通常是 `uidmap` 工具包以便系统支持 `newuidmap` `newgidmap`
```bash
$ sudo apt-get install uidmap
```
2. 切换到一个没有任何 `sudo` 权限的普通用户假设用户名为 `testuser`
```bash
$ su - testuser
```
3. 运行 Docker 官方提供的 Rootless 安装脚本
```bash
$ curl -fsSL https://get.docker.com/rootless | sh
```
4. 配置环境变量指向新创建的私有 socket
```bash
$ export DOCKER_HOST=unix:///run/user/1000/docker.sock
$ docker version
```
安装并暴露相应的配置后该用户的环境将能独立启动属于他自己的 Docker Daemon即使由于某些未知 0-Day 漏洞使得攻击者突破了容器他们也只会受限于 `testuser` 这个非特权用户所在的有限系统环境内
### 18.3.4 结语
保障 Docker 服务端的安全主要是做减法关闭不必要的网络监听点严管 Socket 访问权限而一旦基础系统条件允许**毫不犹豫地在生产环境启用 Rootless 模式**将是一项划算的安全加固选择

View File

@@ -1,30 +1,63 @@
## 18.4 内核能力机制
Docker 利用 Linux 能力机制 (Capabilities) 来限制容器的权限从而提高系统的安全性
传统 Linux 权限模型非常粗放进程分为特权进程 root 用户 `UID 0` 运行非特权进程其他 UID 运行这带来了一个致命问题只要一个后台服务需要一个微小的特权例如绑定低于 1024 的端口就必须被赋予所有的 root 权限一旦该服务被攻陷系统便会全面沦陷
[能力机制 (Capability)](https://man7.org/linux/man-pages/man7/capabilities.7.html) 是 Linux 内核一个强大的特性,可以提供细粒度的权限访问控制
Linux 内核自 2.2 版本起就支持能力机制它将权限划分为更加细粒度的操作能力既可以作用在进程上也可以作用在文件上
为了解决这一问题Linux 引入了 **能力机制Capabilities**它将传统的全能 root 权限划分为几十个细粒度的操作能力
例如一个 Web 服务进程只需要绑定一个低于 1024 的端口的权限并不需要 root 权限那么它只需要被授权 `net_bind_service` 能力即可此外还有很多其他的类似能力来避免进程获取 root 权限
### 18.4.1 容器内置的 Capability 白名单
默认情况下Docker 启动的容器被严格限制只允许使用内核的一部分能力
默认情况下即便一个容器是在以 `root` 用户运行Docker 也只为其内核授予了所有可用能力中的**一小部分白名单能力**
使用能力机制对加强 Docker 容器的安全有很多好处通常在服务器上会运行一堆需要特权权限的进程包括有 sshcronsyslogd硬件管理工具模块 (例如负载模块)网络配置工具等等容器跟这些进程是不同的因为几乎所有的特权进程都由容器以外的支持系统来进行管理
常见的 Linux Capabilities 包含
- `CAP_CHOWN`: 修改文件所有者
- `CAP_NET_BIND_SERVICE`: 绑定特权端口 1024 以下的端口
- `CAP_NET_ADMIN`: 网络管理的最高权限例如调整路由配置设置防火墙规则等
- `CAP_SYS_ADMIN`: 被誉为Linux 内核的特权网管允许各种高危操作挂载磁盘访问敏感设备等
* ssh 访问被主机上 ssh 服务来管理
* cron 通常应该作为用户进程执行权限交给使用它服务的应用来处理
* 日志系统可由 Docker 或第三方服务管理
* 硬件管理无关紧要容器中也就无需执行 udevd 以及类似服务
* 网络管理也都在主机上设置除非特殊需求容器不需要对网络进行配置
为了在**最小特权原则**的指导下加强安全Docker 默认**移除了**大量可能导致容器大范围破坏宿主机的能力例如
* 完全禁止了任何通过 `CAP_SYS_ADMIN` 进行的核心挂载或设备操作
* 禁止修改内核模块
* 禁止直接访问硬件套接字
从上面的例子可以看出大部分情况下容器并不需要 真正的 root 权限容器只需要少数的能力即可为了加强安全容器可以禁用一些没必要的权限
这种非完整 root 用户能保证大部分应用在拥有其所需权限的同时把恶意行为对系统的影响降到最低
* 完全禁止任何 mount 操作
* 禁止直接访问本地主机的套接字
* 禁止访问一些文件系统的操作比如创建新的设备修改文件属性等
* 禁止模块加载
### 18.4.2 实战添加与剥夺能力
这样就算攻击者在容器中取得了 root 权限也不能获得本地主机的较高权限能进行的破坏也有限
当启动一个 Docker 容器时我们可以利用 `--cap-add`增加特权 `--cap-drop`剥夺特权两个参数精细地控制进程环境
默认情况下Docker 采用[白名单](https://github.com/moby/moby/blob/master/oci/caps/defaults.go)机制,禁用必需功能之外的其它权限。
当然用户也可以根据自身需求来为 Docker 容器启用额外的权限
#### 实战场景一构建极限安全的 Web 靶机
假设你正在提供一个公共的 Web 容器你不希望里面的任何恶意脚本修改进程权限或者创建设备节点你可以通过命令先移除**所有**默认能力然后再按需授权该守护进程一个仅仅能绑端口的能力
```bash
$ docker run -d \
--name max_secure_web \
--cap-drop ALL \
--cap-add NET_BIND_SERVICE \
nginx:alpine
```
这里的 `--cap-drop ALL` 是实现特权最小化的最强杀手锏此时即便某黑客利用 0-Day 手段拿到了 Web 服务的容器 root Shell当他试图改变任何不属于他自己的进程配置或者所有权时系统都会报错拒绝访问
#### 实战场景二需要捕获网络数据包的网络实验
假设容器内的主程序是一个网络嗅探器 tshark tcpdump这显然不在 Docker 提供的默认白名单之内因为该程序试图直接操纵底层网卡流量会触发 Permission Denied
此时我们需要给它适当补发缺失的部分核心管理能力
```bash
$ docker run -it --rm \
--name network_sniffer \
--cap-add NET_ADMIN \
--cap-add NET_RAW \
tshark-image /bin/bash
```
我们只授予了所需的网络管理控制NET_ADMIN和侦听底层套接字的权限NET_RAW而免去了赋予整个容器终极杀器 `--privileged` 参数
> [!WARNING]
> 大量开发人员遇到了权限遭到拒绝的错误时往往习惯性图省事添加 `--privileged` 这个核选项但这将把**宿主机上一切特权和所有访问设备完全投射给容器内的根用户**其危险性等价于根本没有做隔离请务必查明进程出错的实际原因精准施加必要的隔离 `CAP_*` 能力
### 18.4.3 总结
利用能力机制Capabilities是进行精细化系统级访问控制的关键一环遵循**白名单剥夺一切不必要权利--cap-drop ALL**的极端配置并不过分这将使得即便程序本身漏洞百出攻击面也被死死压缩在一个几乎毫无后续伸展潜力的受限维度中

View File

@@ -1,13 +1,88 @@
## 18.5 其它安全特性
除了上述机制Linux 内核还提供了一系列安全增强功能可以进一步保护容器环境
除了上述的命名空间控制组以及能力机制Linux 内核与云原生生态还提供了大量安全增强功能它们共同筑成了一道防御纵深的马奇诺防线本节主要介绍强制访问控制系统调用拦截以及自动化的容器漏洞扫描技术
除了能力机制之外还可以利用一些现有的安全机制来增强使用 Docker 的安全性例如 TOMOYOAppArmorSeccompSELinuxGRSEC
### 18.5.1 系统调用过滤
Docker 当前默认只启用了能力机制用户可以采用多种方案来加强 Docker 主机的安全例如
`Seccomp`Secure Computing mode Linux 内核的一个安全机制用于限制进程能够发起的系统调用数量
* 在内核中启用 GRSEC PAX这将增加很多编译和运行时的安全检查通过地址随机化避免恶意探测等并且启用该特性不需要 Docker 进行任何配置
* 使用一些有增强安全特性的容器模板比如带 AppArmor 的模板和 Redhat SELinux 策略的模板这些模板提供了额外的安全特性
* 用户可以自定义访问控制机制来定制安全策略
一个普通的 Linux 内核提供了 300 多个系统调用而一个正常运行的容器化应用例如 Nginx 服务通常只会用到几十个调用这就给攻击者留下了大量的闲置入口点来进行内核层的缓冲区溢出攻击
跟其它添加到 Docker 容器的第三方工具一样 (比如网络拓扑和文件系统共享)有很多类似的机制在不改变 Docker 内核情况下就可以加固现有的容器
Docker 默认启用了 Seccomp 并利用预置的 [默认配置文件](https://github.com/moby/moby/blob/master/profiles/seccomp/default.json) 将可以利用的系统调用缩减到了不足一半(默认禁用了 44 个危险的统调用,比如修改时区或重启系统)
如果你对应用的系统调用特征了如指掌你可以为容器定制专属规则
#### 实战禁用 chmod 系统调用过滤
首先编写一个 `no-chmod.json` 的策略文件
```json
{
"defaultAction": "SCMP_ACT_ALLOW",
"syscalls": [
{
"name": "chmod",
"action": "SCMP_ACT_ERRNO"
}
]
}
```
在启动时告诉 Docker 载入这套过滤配置
```bash
$ docker run --rm -it \
--security-opt seccomp=no-chmod.json \
alpine sh
/ # chmod 777 /etc/passwd
chmod: /etc/passwd: Operation not permitted
```
应用只要被劫持进行越界尝试其操作系统层命令便会立刻吃瘪
### 18.5.2 强制访问控制 (AppArmor / SELinux)
传统的 Linux 模型遵循 DAC自主访问控制这意味着如果一个文件被赋予了全员读写权限`777`普通隔离下任何人便都能修改 **MAC强制访问控制** 技术诸如 `AppArmor` (常用于 Ubuntu/Debian) `SELinux` (常用于 CentOS/RHEL)可以制定比文件所有权更宏观且优先的策略控制模块
在开启了上述机制的机器上
- **AppArmor**: Docker 为所有启动的应用加载了一个默认的 `docker-default` 模板文件如果你的某些异常写行为比如往特殊的内核心脏目录写入配置不在 AppArmor 许可列表之上即使拥有物理 Root写入同样失败
- **SELinux**: 所有的 Docker 操作强制附加特殊上下文标识标签就算把主机的 `/` 绑定给了黑客的某服务黑客对不属于 Docker 可见的标签的文件进行读写尝试亦会被阻止
如果想为某些受信任应用施加特定的外部强化文件策略可以通过如下方法指派规则表
```bash
$ docker run --rm -it \
--security-opt apparmor=custom-nginx-profile \
nginx
```
### 18.5.3 容器镜像漏洞静态扫描
现代防护的防御已经不仅仅在运行阶段而向延伸至了构建与分发时期控制很多安全隐患并不是用户代码中的直接逻辑异常而是打包环境或者引入库的基础 `APT` 安装层面潜伏了开源界众所周知的历史漏洞
#### 使用 Trivy 识别风险
[Trivy](https://github.com/aquasecurity/trivy) 是由 Aqua Security 发行的一款针对容器技术的快速镜像漏洞扫描利器。在分发应用前通过它的扫描可以规避绝大多数风险。
```bash
## 如果使用本地命令行扫描容器镜像
$ trivy image alpine:3.10
2024-03-01T10:05:07.124Z INFO Number of language-specific files: 1
2024-03-01T10:05:07.124Z INFO Detecting vulnerabilities...
alpine:3.10 (alpine 3.10.3)
===========================
Total: 2 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 1, CRITICAL: 0)
+---------+------------------+----------+-------------------+---------------+---------------------------------------+
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
+---------+------------------+----------+-------------------+---------------+---------------------------------------+
| busybox | CVE-2022-28391 | HIGH | 1.30.1-r3 | 1.30.1-r4 | busybox: out-of-bounds read in... |
...
```
只要确保所有上传给私有或公共仓库分发服务的产物先被引入至 CI/CD 流水线如果出现 `HIGH` `CRITICAL` 严重的报错记录强行阻拦部署这本身便是构建环节极其有力的自动化安全大门保障 Trivy 最新的 Docker 版本也已内置支持官方扫描利刃 **Docker Scout**
### 18.5.4 容器核心层基石结语
到这里Docker 为保障宿主和容器界限安全的几个护城河**资源剥离限制** (`Cgroups`) **进程/网络/身份蒙蔽** (`Namespace`)**特权能力回收** (`Capabilities`) 再到**内核强制策略拦截管制** (`Seccomp`/`AppArmor`) 已悉数交代完毕虽然绝没有100% 免疫网络穿刺的防线只要开发者牢记 **权限最小化原则** 容器的堡垒就可以做到令攻击者望洋兴叹

View File

@@ -391,4 +391,4 @@ $ cosign verify --key cosign.pub $IMAGE
- [命名空间](../12_implementation/12.2_namespace.md)隔离机制详解
- [控制组](../12_implementation/12.3_cgroups.md)资源限制详解
- [最佳实践](../appendix/20.1_best_practices.md)Dockerfile 安全配置
- [最佳实践](../appendix/best_practices.md)Dockerfile 安全配置

View File

@@ -1,4 +1,4 @@
## 18.6
## 本章小
Docker 的安全性依赖于多层隔离机制的协同工作同时需要用户遵循最佳实践