高级配置选项

注意

此功能适用于 Mac、Linux 和 Windows(Hyper-V)上的 Docker Desktop 4.27(及更高版本)。对于使用 WSL 2 的 Windows,此功能需要 Docker Desktop 4.28 及更高版本。

本页面介绍了启用 ECI 后,ECI 的可选高级配置。

Docker 套接字挂载权限

默认情况下,启用 ECI 后,Docker Desktop 不允许将 Docker Engine 套接字绑定挂载到容器中。

$ docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock docker:cli
docker: Error response from daemon: enhanced container isolation: docker socket mount denied for container with image "docker.io/library/docker"; image is not in the allowed list; if you wish to allow it, configure the docker socket image list in the Docker Desktop settings.

这可以防止恶意容器访问 Docker Engine,因为这种访问可能会使它们执行供应链攻击(例如,将恶意镜像构建和推送至组织的存储库)或类似攻击。

但是,某些合法用例需要容器访问 Docker Engine 套接字。例如,流行的 Testcontainers 框架有时会将 Docker Engine 套接字绑定挂载到容器中以管理它们或执行测试后清理。

从 Docker Desktop 4.27 开始,管理员可以选择配置 ECI 以允许将 Docker Engine 套接字绑定挂载到容器中,但在受控方式下。

这可以通过 admin-settings.json 文件完成,如 设置管理 中所述。例如

{
  "configurationFileVersion": 2,
  "enhancedContainerIsolation": {
    "locked": true,
    "value": true,
    "dockerSocketMount": {
      "imageList": {
        "images": [
          "docker.io/localstack/localstack:*",
          "docker.io/testcontainers/ryuk:*",
          "docker:cli"
        ]
      },
      "commandList": {
        "type": "deny",
        "commands": ["push"]
      }
    }
  }
}

如上所示,有两种配置可用于将 Docker 套接字绑定挂载到容器中:imageListcommandList。这些将在下面介绍。

镜像列表

imageList 是允许绑定挂载 Docker 套接字的容器镜像列表。默认情况下,该列表为空(即,启用 ECI 后,不允许任何容器绑定挂载 Docker 套接字)。但是,管理员可以使用以下两种格式将镜像添加到该列表中。

镜像引用格式描述
<image_name>[:<tag>]镜像名称,带有可选的标签。如果省略标签,则使用 :latest 标签。如果标签是通配符 *,则表示“该镜像的任何标签”。
<image_name>@<digest>镜像名称,带有特定的存储库摘要(例如,由 docker buildx imagetools inspect <image> 报告)。这意味着只有与该名称和摘要匹配的镜像才被允许。

镜像名称遵循标准约定,因此它可以指向任何注册表和存储库。

在上面的示例中,镜像列表配置了三个镜像

"imageList": {
  "images": [
    "docker.io/localstack/localstack:*",
    "docker.io/testcontainers/ryuk:*",
    "docker:cli"
  ]
}

这意味着使用 docker.io/localstack/localstackdocker.io/testcontainers/ryuk 镜像(带任何标签)或 docker:cli 镜像的容器在启用 ECI 后被允许绑定挂载 Docker 套接字。因此,以下操作有效

$ docker run -it -v /var/run/docker.sock:/var/run/docker.sock docker:cli sh
/ #

提示

限制您允许的镜像,如下面 建议 中所述。

通常,使用标签通配符格式(例如,<image-name>:*)指定镜像更轻松,因为这样 imageList 就不需要在使用新版本的镜像时更新。或者,您可以使用不可变标签(例如,:latest),但它并不总是像通配符那样有效,因为例如,Testcontainers 使用的是镜像的特定版本,并不一定是最新版本。

启用 ECI 后,Docker Desktop 会定期从相应的注册表下载允许镜像的镜像摘要并将其存储在内存中。然后,当使用 Docker 套接字绑定挂载启动容器时,Docker Desktop 会检查容器的镜像摘要是否与允许的摘要之一匹配。如果匹配,则允许容器启动,否则将被阻止。

请注意,由于前面段落中提到的摘要比较,无法通过将不允许的镜像重新标记为允许的镜像的名称来绕过 Docker 套接字挂载权限。换句话说,如果用户执行以下操作

$ docker image rm <allowed_image>
$ docker tag <disallowed_image> <allowed_image>
$ docker run -v /var/run/docker.sock:/var/run/docker.sock <allowed_image>

那么标记操作将成功,但 docker run 命令会失败,因为不允许的镜像的镜像摘要将与存储库中允许的镜像的摘要不匹配。

命令列表

commandList 限制了容器在启用 ECI 时通过绑定挂载的 Docker 套接字发出的 Docker 命令。它充当 imageList 的补充安全机制(即,像第二道防线)。

例如,假设 imageList 配置为允许镜像 docker:cli 挂载 Docker 套接字,并且使用它启动了一个容器

$ docker run -it --rm -v /var/run/docker.sock:/var/run/docker.sock sh
/ #

默认情况下,这允许容器通过该 Docker 套接字发出任何命令(例如,将镜像构建并推送至组织的存储库),这通常不可取。

为了提高安全性,可以配置 commandList 来限制容器内的进程可以在绑定挂载的 Docker 套接字上发出的命令。commandList 可以配置为“拒绝”列表(默认)或“允许”列表,具体取决于您的偏好。

列表中的每个命令都由其名称指定,如 docker --help 所报告(例如,“ps”、“build”、“pull”、“push”等)。此外,以下命令通配符允许阻止一组命令

命令通配符描述
"container*"指所有“docker container …” 命令
"image*"指所有“docker image …” 命令
"volume*"指所有“docker volume …” 命令
"network*"指所有“docker network …” 命令
"build*"指所有“docker build …” 命令
"system*"指所有“docker system …” 命令

例如,以下配置会阻止 Docker 套接字上的 buildpush 命令

"commandList": {
  "type": "deny",
  "commands": ["build", "push"]
}

因此,如果在容器内部,您在绑定挂载的 Docker 套接字上发出这两个命令中的任何一个,它们将被阻止。

/ # docker push myimage
Error response from daemon: enhanced container isolation: docker command "/v1.43/images/myimage/push?tag=latest" is blocked; if you wish to allow it, configure the docker socket command list in the Docker Desktop settings or admin-settings.

同样地

/ # curl --unix-socket /var/run/docker.sock -XPOST https://127.0.0.1/v1.43/images/myimage/push?tag=latest
Error response from daemon: enhanced container isolation: docker command "/v1.43/images/myimage/push?tag=latest" is blocked; if you wish to allow it, configure the docker socket command list in the Docker Desktop settings or admin-settings.

请注意,如果 commandList 配置为“允许”列表,那么效果将相反:只有列出的命令才被允许。是否将列表配置为允许列表或拒绝列表取决于用例。

建议

  • 限制允许绑定挂载 Docker 套接字的容器镜像列表(即,imageList)。通常,只允许绝对必要且您信任的镜像。

  • 如果可能,在 imageList 中使用标签通配符格式(例如,<image_name>:*),因为这样可以消除由于镜像标签更改而需要更新 admin-settings.json 文件的需要。

  • commandList 中,阻止您不希望容器执行的命令。例如,对于本地测试(例如,Testcontainers),将 Docker 套接字绑定挂载的容器通常会创建/运行/删除容器、卷和网络,但通常不会构建镜像或将其推送至存储库(尽管有些可能合法地这样做)。允许或阻止哪些命令取决于用例。

    • 请注意,容器通过绑定挂载的 Docker 套接字发出的所有“docker”命令也将以增强型容器隔离的方式执行(即,生成的容器使用 Linux 用户命名空间,敏感系统调用会经过验证,等等)。

注意事项和限制

  • 重新启动 Docker Desktop 后,允许挂载 Docker 套接字的镜像可能会意外地被阻止这样做。当镜像摘要在远程存储库中发生变化时(例如,“:latest”镜像已更新)并且该镜像的本地副本(例如,来自先前的 docker pull)不再与远程存储库中的摘要匹配时,可能会发生这种情况。在这种情况下,请删除本地镜像并再次拉取它(例如,docker rm <image>docker pull <image>)。

  • 无法允许对不在注册表中的镜像进行 Docker 套接字绑定挂载(例如,本地构建但尚未推送到注册表的镜像)。这是因为 Docker Desktop 从注册表中拉取允许镜像的摘要,然后使用它与镜像的本地副本进行比较。

  • commandList 配置适用于所有允许绑定挂载 Docker 套接字的容器。因此,它不能针对每个容器进行不同的配置。

  • 以下命令在 commandList 中尚不支持

不支持的命令描述
composeDocker compose
devDocker 开发环境
extension管理 Docker 扩展
feedback向 Docker 发送反馈
init创建与 Docker 相关的入门文件
manifest管理 Docker 镜像清单
plugins管理插件
sbom查看软件物料清单 (SBOM)
scanDocker Scan
scoutDocker Scout
信任管理 Docker 镜像的信任

注意

当运行“真正的”Docker-in-Docker(即在容器内运行 Docker 引擎)时,Docker 套接字挂载权限不适用。在这种情况下,不会将宿主机 Docker 套接字绑定挂载到容器中,因此容器不会利用宿主机 Docker 引擎的配置和凭据来执行恶意活动。增强型容器隔离功能能够安全地运行 Docker-in-Docker,而无需在 Docker Desktop VM 中为外部容器提供真正的 root 权限。