From ac5ec03ab5a27d5d4beae327612e2a61f63391c0 Mon Sep 17 00:00:00 2001 From: yeasy Date: Fri, 4 Sep 2026 14:52:59 -0700 Subject: [PATCH] =?UTF-8?q?fix(=E5=AE=89=E5=85=A8,=E7=89=88=E6=9C=AC):=20s?= =?UTF-8?q?eccomp=20=E7=A4=BA=E4=BE=8B=E6=98=AF=E5=AE=89=E5=85=A8=E9=99=8D?= =?UTF-8?q?=E7=BA=A7=EF=BC=8C=E5=8F=A6=E4=BF=AE=E4=B8=89=E5=A4=84=E5=87=AD?= =?UTF-8?q?=E6=8D=AE/=E6=9A=B4=E9=9C=B2=E9=9D=A2=E4=B8=8E=E4=B9=9D?= =?UTF-8?q?=E5=A4=84=E7=89=88=E6=9C=AC=E8=BF=87=E6=97=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 安全(四条,前三条都是书自己打自己): - 18.5 的自定义 seccomp 示例用 `"defaultAction": "SCMP_ACT_ALLOW"` 写了一个 blocklist。但 `--security-opt seccomp=` 是**整体替换**默认 profile 而非叠加(官方 seccomp 文档:容器"uses the default profile unless you override it"),而默认 profile 恰恰是 deny-by-default 的 allowlist——本节 第 11 行自己就这么写的。净效果是:挡住了 chmod,却把默认拦下的那 ~44 个 高危调用(unshare / keyctl / add_key / bpf / perf_event_open / init_module / reboot 等)全部放行,**比不加这个参数更危险**,而读者会以为自己加固了。 改为从官方 default.json 派生,并在示例前置醒目警告。 - 7.6 把 `docker run -e DB_PASSWORD=xxx` 标成「✅ 正确」。它只是把泄漏路径 从镜像换到了别处:进 shell history、进宿主机进程 argv(同机任何用户 ps 可见)、并永久固化在 `docker inspect` 的 Config.Env 里。而本书 11.8:102 明写「不要把数据库密码写入 compose.yaml、.env、**命令行** 或 Git」, 16.3:251 也要求「避免把真实口令写入命令历史」。改为标注 -e 的泄漏面, 并给出 --env-file / Compose secrets 的正确做法。 - 6.2 教读者起一个**无认证、无 TLS** 的 registry,且引导把它绑到内网地址、 开 insecure-registries,全节零安全提示。同网段任意主机可匿名 push,即 镜像投毒。而 18.3:17 用最强语气写着「绝不能在没有任何安全控制的情况下 强行开启」。示例改为绑 127.0.0.1,并在两处补上风险说明与指向 6.3 的出口。 - 18.6 的 CI 示例里,Trivy 那条注释写着「务必使用不可变的 commit SHA 引用, 而非可变标签」(引的是 2026-03-19 Trivy Actions 76 个 tag 被劫持事件), 可同一 workflow 里另外九条 uses 全是可变标签,包括持有凭据的 docker/login-action。补一段说明点破这一点。(本仓库自己的 .github/workflows/ 确实全部按 SHA 钉死,已实测确认后才写进书里。) 版本时效(对 GitHub releases / endoflife.date / docs.docker.com 逐条核实): - 5.1 与 6.3 说 `ubuntu:24.04`「是最新 LTS」——最新 LTS 已是 26.04 (2026-04-23 发布);而本书 3.1 早就列出了 26.04,属书内不一致。更糟的是 5.1 建议可替换为 `ubuntu:20.04`,而 3.1:33 正警告 20.04 已不在支持列表。 - 3.1 的支持列表里的 Ubuntu 25.10 已被 Docker 官方安装文档移除(该版本本身 也已于 2026-07-01 EOL),删去。 - 4.6 拿 `alpine:3.20` 当"锁定版本以确保可重现性"的范例,而 3.20 已于 2026-04 EOL;改为 3.24。 - 3.2 的「Debian Bullseye 11 将于 2026 年 8 月底结束长期支持」时态已过期。 - kind v0.31.0 → v0.33.0(落后两个小版本);etcd v3.5.29 → v3.5.33。 - 10_buildx/README 推荐「Docker v28 及以上」,而紧接着的段落就在用 「自 Docker Engine 29 起」立论;改为 v29。 --- 03_install/3.1_ubuntu.md | 1 - 03_install/3.2_debian.md | 2 +- 04_image/4.6_other.md | 2 +- 05_container/5.1_run.md | 2 +- 06_repository/6.2_registry.md | 9 ++++++++- 06_repository/6.3_registry_auth.md | 2 +- 07_dockerfile/7.6_env.md | 8 +++++++- 10_buildx/README.md | 2 +- 14_kubernetes_setup/14.4_kind.md | 6 +++--- 15_etcd/15.2_install.md | 14 ++++++------- 15_etcd/15.3_cluster.md | 8 ++++---- 18_security/18.5_other_feature.md | 32 +++++++++++++++++++----------- 18_security/18.6_image_security.md | 6 ++++++ 13 files changed, 60 insertions(+), 34 deletions(-) diff --git a/03_install/3.1_ubuntu.md b/03_install/3.1_ubuntu.md index ad8fdf6..bf2aa1e 100644 --- a/03_install/3.1_ubuntu.md +++ b/03_install/3.1_ubuntu.md @@ -25,7 +25,6 @@ Ubuntu 是 Docker 最常用的运行环境之一。本节将介绍如何在 Ubun * Ubuntu Resolute Raccoon 26.04 (LTS) -* Ubuntu Questing Quokka 25.10 * Ubuntu Noble 24.04 (LTS) * Ubuntu Jammy 22.04 (LTS) diff --git a/03_install/3.2_debian.md b/03_install/3.2_debian.md index b092162..3a658a1 100644 --- a/03_install/3.2_debian.md +++ b/03_install/3.2_debian.md @@ -20,7 +20,7 @@ Docker 支持以下版本的 [Debian](https://www.debian.org/intro/about) 操作 * Debian Bookworm 12(oldstable,全面支持至 2026 年 6 月 10 日,LTS 至 2028 年 6 月 30 日) * Debian Bullseye 11(oldoldstable,LTS 支持至 2026 年 8 月 31 日) -> **注意**:Debian Bullseye 11 将于 2026 年 8 月底结束长期支持。建议新部署使用 Bookworm 12 或 Trixie 13。 +> **注意**:Debian Bullseye 11 已于 2026 年 8 月 31 日结束长期支持。建议新部署使用 Bookworm 12 或 Trixie 13。 #### 卸载旧版本 diff --git a/04_image/4.6_other.md b/04_image/4.6_other.md index 480db60..a8aefe8 100644 --- a/04_image/4.6_other.md +++ b/04_image/4.6_other.md @@ -53,7 +53,7 @@ REPOSITORY TAG IMAGE ID CREATED alpine latest baa5d63471ea 5 weeks ago 4.803 MB ``` -> **版本提示**:`alpine:latest` 为最新版本的 Alpine Linux。如果需要特定版本号(如 `alpine:3.20`),可以明确指定以确保可重现性。 +> **版本提示**:`alpine:latest` 为最新版本的 Alpine Linux。如果需要特定版本号(如 `alpine:3.24`),可以明确指定以确保可重现性;注意选一个仍在维护的版本,`alpine:3.20` 已于 2026-04 结束支持。 保存镜像的命令为: ```bash diff --git a/05_container/5.1_run.md b/05_container/5.1_run.md index 717e11b..2f9b002 100644 --- a/05_container/5.1_run.md +++ b/05_container/5.1_run.md @@ -29,7 +29,7 @@ Hello world ``` 这与直接执行 `/bin/echo 'Hello world'` 几乎没有区别,但实际上已经启动了一个完整的 Ubuntu 容器来执行这条命令。 -> **版本说明**:示例使用 `ubuntu:24.04`,这是最新 LTS 版本。如需其他版本,可替换为 `ubuntu:22.04`、`ubuntu:20.04` 等。 +> **版本说明**:示例使用 `ubuntu:24.04`,这是仍受 Docker 支持的 LTS 版本(当前最新 LTS 为 26.04)。如需其他版本,可替换为 `ubuntu:26.04`、`ubuntu:22.04` 等;不要用已不在支持列表中的 `ubuntu:20.04`(见 3.1 节)。 #### 交互式容器 diff --git a/06_repository/6.2_registry.md b/06_repository/6.2_registry.md index 9a9be89..e6184a4 100644 --- a/06_repository/6.2_registry.md +++ b/06_repository/6.2_registry.md @@ -15,9 +15,14 @@ 你可以使用官方 `registry` 镜像来运行。 ```bash -$ docker run -d -p 5000:5000 --restart=always --name registry registry:2 +$ docker run -d -p 127.0.0.1:5000:5000 --restart=always --name registry registry:2 ``` +> **注意**:这样启动的 registry **没有任何认证、也没有 TLS**,因此这里刻意绑定到 +> `127.0.0.1`,仅供本机实验。不要直接把它绑到 `0.0.0.0` 或内网地址——那等于允许同网段 +> 任意主机匿名推送镜像(镜像投毒:覆盖你的 `latest` 标签,下游全部拉到攻击者的镜像)。 +> 需要多机访问请直接用 [6.3 节](6.3_registry_auth.md) 的 TLS + 认证方案。 + > **版本说明**:使用 `registry:2` 表示 Docker Registry 2.x 兼容示例。Distribution 3.x 已发布稳定版本;不要直接把本章 v2 配置原样套到 v3 生产环境,升级前应阅读迁移说明并做兼容测试。旧版本 Registry 1.x 已停止维护,不建议使用。 这将使用官方的 `registry` 镜像来启动私有仓库。默认情况下,仓库会被创建在容器的 `/var/lib/registry` 目录下。你可以通过 `-v` 参数来将镜像文件存放在本地的指定路径。例如下面的例子将上传的镜像放到本地的 `/opt/data/registry` 目录。 @@ -96,6 +101,8 @@ REPOSITORY TAG IMAGE ID CREAT 这是因为 Docker 默认不允许非 `HTTPS` 方式推送镜像。我们可以通过 Docker 的配置选项来取消这个限制,或者查看下一节配置能够通过 `HTTPS` 访问的私有仓库。 +> **警告**:下面的 `insecure-registries` 会关闭该地址的 TLS 校验,推送和拉取都是明文、可被中间人篡改;再叠加上 registry 默认无认证,等于把「任意主机可匿名投毒」的仓库开在内网。**仅限隔离的实验网络**,生产一律走 [6.3 节](6.3_registry_auth.md) 的 TLS + 认证。 + #### Linux 默认情况下,Docker 强制使用 HTTPS 协议推送镜像。如果您搭建的私有仓库是 HTTP 协议,需要进行如下配置。 diff --git a/06_repository/6.3_registry_auth.md b/06_repository/6.3_registry_auth.md index ff4b13f..f95dcf1 100644 --- a/06_repository/6.3_registry_auth.md +++ b/06_repository/6.3_registry_auth.md @@ -201,7 +201,7 @@ $ docker image rm docker.domain.com/username/ubuntu:24.04 $ docker pull docker.domain.com/username/ubuntu:24.04 ``` -> **版本说明**:示例使用 `ubuntu:24.04`,这是最新 LTS 版本。推送到私有仓库时保持了原有的版本标签,建议生产环境明确指定镜像版本号。 +> **版本说明**:示例使用 `ubuntu:24.04`,这是仍受 Docker 支持的 LTS 版本(当前最新 LTS 为 26.04)。推送到私有仓库时保持了原有的版本标签,建议生产环境明确指定镜像版本号。 如果我们退出登录,尝试推送镜像。 ```bash diff --git a/07_dockerfile/7.6_env.md b/07_dockerfile/7.6_env.md index 0fcb656..023d004 100644 --- a/07_dockerfile/7.6_env.md +++ b/07_dockerfile/7.6_env.md @@ -182,10 +182,16 @@ RUN apt-get install nginx=1.30 ENV DB_PASSWORD=secret123 -## ✅ 正确:运行时传入 +## ⚠️ 好一些但仍会泄漏:-e 会进入 shell history、宿主机进程 argv(同机任何用户 ps 可见), +## 并永久固化在 docker inspect 的 Config.Env 里 ## docker run -e DB_PASSWORD=xxx myimage +## ✅ 正确:用文件传入,不进命令行 + +## docker run --env-file ./db.env myimage # 文件权限设为 600 +## 或使用 Compose secrets / *_FILE 约定,见 11.8 节 + ... ``` diff --git a/10_buildx/README.md b/10_buildx/README.md index cb40ee1..f6c5394 100644 --- a/10_buildx/README.md +++ b/10_buildx/README.md @@ -2,7 +2,7 @@ Docker Buildx 是一个 docker CLI 插件,其扩展了 docker 命令,支持 [Moby BuildKit](10.1_buildkit.md) 提供的功能。提供了与 docker build 相同的用户体验,并增加了许多新功能。 -> Buildx 需要 Docker v23.0+(该版本起 BuildKit 成为默认构建引擎)。推荐使用 Docker v28 及以上版本以获得最完整的 Buildx 功能支持。 +> Buildx 需要 Docker v23.0+(该版本起 BuildKit 成为默认构建引擎)。推荐使用 Docker v29 及以上版本以获得最完整的 Buildx 功能支持。 ## 本章内容 diff --git a/14_kubernetes_setup/14.4_kind.md b/14_kubernetes_setup/14.4_kind.md index 679709c..0c50849 100644 --- a/14_kubernetes_setup/14.4_kind.md +++ b/14_kubernetes_setup/14.4_kind.md @@ -2,7 +2,7 @@ [Kind](https://kind.sigs.k8s.io/) (Kubernetes in Docker) 是一个使用 Docker 容器作为节点运行本地 Kubernetes 集群的工具。主要用于测试 Kubernetes 本身,也非常适合本地开发和 CI 环境。 -> **版本说明**:本文档基于 Kind v0.31.0 编写。Kind 会根据下载时的默认行为自动拉取对应的 Kubernetes 版本。建议定期更新 Kind 到最新版本以获得最新的 Kubernetes 支持。详见 [Kind Releases](https://github.com/kubernetes-sigs/kind/releases)。 +> **版本说明**:本文档基于 Kind v0.33.0 编写。Kind 会根据下载时的默认行为自动拉取对应的 Kubernetes 版本。建议定期更新 Kind 到最新版本以获得最新的 Kubernetes 支持。详见 [Kind Releases](https://github.com/kubernetes-sigs/kind/releases)。 ### 14.4.1 为什么选择 Kind @@ -29,10 +29,10 @@ brew install kind ```bash # Linux AMD64 -# 注意:v0.31.0 为编写本文档时的最新版本,请根据需要替换为当前版本 +# 注意:v0.33.0 为编写本文档时的最新版本,请根据需要替换为当前版本 # 参见 https://github.com/kubernetes-sigs/kind/releases -curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.31.0/kind-linux-amd64 +curl -Lo ./kind https://kind.sigs.k8s.io/dl/v0.33.0/kind-linux-amd64 chmod +x ./kind sudo mv ./kind /usr/local/bin/kind ``` diff --git a/15_etcd/15.2_install.md b/15_etcd/15.2_install.md index 84462b2..3424701 100644 --- a/15_etcd/15.2_install.md +++ b/15_etcd/15.2_install.md @@ -13,13 +13,13 @@ 例如,使用 `curl` 工具下载压缩包,并解压。 ```bash -# 下载 etcd v3.5.29 版本(请访问 https://github.com/etcd-io/etcd/releases 获取最新版本) -$ curl -L https://github.com/etcd-io/etcd/releases/download/v3.5.29/etcd-v3.5.29-linux-amd64.tar.gz -o etcd-v3.5.29-linux-amd64.tar.gz +# 下载 etcd v3.5.33 版本(请访问 https://github.com/etcd-io/etcd/releases 获取最新版本) +$ curl -L https://github.com/etcd-io/etcd/releases/download/v3.5.33/etcd-v3.5.33-linux-amd64.tar.gz -o etcd-v3.5.33-linux-amd64.tar.gz ## 国内用户可选择就近的网络加速方式(以可用镜像站为准) -$ tar xzvf etcd-v3.5.29-linux-amd64.tar.gz -$ cd etcd-v3.5.29-linux-amd64 +$ tar xzvf etcd-v3.5.33-linux-amd64.tar.gz +$ cd etcd-v3.5.33-linux-amd64 ``` 解压后,可以看到文件包括 @@ -61,15 +61,15 @@ hello world 镜像名称为 `quay.io/coreos/etcd`,可以通过下面的命令启动单机实验用 `etcd` 服务,并只把 `2379` 和 `2380` 映射到宿主机回环地址。 -> **版本说明:** 示例中使用 `v3.5.29` 标签。请访问 [etcd 官方发布页](https://github.com/etcd-io/etcd/releases) 获取最新可用版本标签。 +> **版本说明:** 示例中使用 `v3.5.33` 标签。请访问 [etcd 官方发布页](https://github.com/etcd-io/etcd/releases) 获取最新可用版本标签。 ```bash $ docker run \ -p 127.0.0.1:2379:2379 \ -p 127.0.0.1:2380:2380 \ --mount type=bind,source=/tmp/etcd-data.tmp,destination=/etcd-data \ ---name etcd-gcr-v3.5.29 \ -quay.io/coreos/etcd:v3.5.29 \ +--name etcd-gcr-v3.5.33 \ +quay.io/coreos/etcd:v3.5.33 \ /usr/local/bin/etcd \ --name s1 \ --data-dir /etcd-data \ diff --git a/15_etcd/15.3_cluster.md b/15_etcd/15.3_cluster.md index fbb86a8..7f49ba3 100644 --- a/15_etcd/15.3_cluster.md +++ b/15_etcd/15.3_cluster.md @@ -1,6 +1,6 @@ ## 15.3 集群 -> **版本说明:** 本节示例使用 etcd v3.5.29。请访问 [etcd 官方发布页](https://github.com/etcd-io/etcd/releases) 获取最新版本信息。 +> **版本说明:** 本节示例使用 etcd v3.5.33。请访问 [etcd 官方发布页](https://github.com/etcd-io/etcd/releases) 获取最新版本信息。 下面我们使用 [Docker Compose](../11_compose/README.md) 模拟启动一个 3 节点的 `etcd` 集群。 @@ -10,7 +10,7 @@ services: node1: - image: quay.io/coreos/etcd:v3.5.29 + image: quay.io/coreos/etcd:v3.5.33 volumes: - node1-data:/etcd-data expose: @@ -42,7 +42,7 @@ services: - docker-etcd node2: - image: quay.io/coreos/etcd:v3.5.29 + image: quay.io/coreos/etcd:v3.5.33 volumes: - node2-data:/etcd-data networks: @@ -74,7 +74,7 @@ services: - docker-etcd node3: - image: quay.io/coreos/etcd:v3.5.29 + image: quay.io/coreos/etcd:v3.5.33 volumes: - node3-data:/etcd-data networks: diff --git a/18_security/18.5_other_feature.md b/18_security/18.5_other_feature.md index 175fecf..7639b59 100644 --- a/18_security/18.5_other_feature.md +++ b/18_security/18.5_other_feature.md @@ -14,18 +14,25 @@ Docker 默认启用了 Seccomp,并使用预置的 [默认配置文件](https:/ #### 实战:禁用 chmod 系统调用过滤 -首先,编写一个 `no-chmod.json` 的策略文件: -```json -{ - "defaultAction": "SCMP_ACT_ALLOW", - "syscalls": [ - { - "name": "chmod", - "action": "SCMP_ACT_ERRNO" - } - ] -} +> **务必先读**:`--security-opt seccomp=` 是**整体替换**默认 profile,不是在默认之上叠加。 +> 如果自己写一个 `"defaultAction": "SCMP_ACT_ALLOW"` 的 blocklist,等于把上面那份 +> deny-by-default 的官方 allowlist 整个丢掉——你挡住了 `chmod`,却把默认被拦下的那 +> ~44 个高危调用(`unshare`、`keyctl`、`add_key`、`bpf`、`perf_event_open`、 +> `init_module`、`reboot` 等)全部放行,**净效果比不加这个参数还危险**。 +> 正确做法是**以官方默认 profile 为基线派生**。 + +先取官方默认 profile,再在它之上把 `chmod` 改成拒绝: + +```bash +$ curl -fsSL -o default.json \ + https://raw.githubusercontent.com/moby/moby/master/profiles/seccomp/default.json + +## 在 default.json 中找到包含 "chmod" 的那条 syscalls 记录,把它从 allow 列表中移除; +## 或追加一条更靠前的显式拒绝规则: +## { "names": ["chmod", "fchmod", "fchmodat"], "action": "SCMP_ACT_ERRNO" } +$ cp default.json no-chmod.json && "$EDITOR" no-chmod.json ``` + 在启动时告诉 Docker 载入这套过滤配置: ```bash @@ -36,7 +43,8 @@ $ docker run --rm -it \ / # chmod 777 /etc/passwd chmod: /etc/passwd: Operation not permitted ``` -应用只要被劫持进行越界尝试,其操作系统层命令便会立刻吃瘪。 +应用只要被劫持进行越界尝试,其操作系统层命令便会立刻吃瘪——同时默认 profile 原有的 +~44 项拦截仍然生效。 ### 18.5.2 强制访问控制:AppArmor / SELinux diff --git a/18_security/18.6_image_security.md b/18_security/18.6_image_security.md index b502faf..8008095 100644 --- a/18_security/18.6_image_security.md +++ b/18_security/18.6_image_security.md @@ -418,6 +418,12 @@ jobs: security-events: write id-token: write + # 注意:本示例其余 action 为便于阅读使用了可变标签(@v7 等),这与下面 Trivy 那条 + # 注释里「务必使用不可变 commit SHA」的要求并不一致——真正部署时**每一条 uses 都应 + # 钉死 40 位 commit SHA**,尤其是持有凭据的 docker/login-action 与能推镜像的 + # docker/build-push-action:标签一旦被劫持,攻击者拿到的就是本 job 的 + # packages: write 与 id-token: write 权限,可以推送恶意镜像并为其签名。 + # 本书仓库自己的 .github/workflows/ 即全部按 SHA 钉死,可作为参照。 steps: - name: Checkout code uses: actions/checkout@v7