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 引擎的访问权限,因为 此类访问可能允许他们执行供应链攻击。例如,build 和 将恶意镜像推送到组织的存储库或类似存储库中。

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

管理员可以选择将 ECI 配置为允许 bind 将 Docker Engine 套接字挂载到容器中,但以受控方式。

这可以通过 Docker Socket 挂载权限部分的admin-settings.json文件。例如:

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

提示

现在,您还可以在 Docker Admin Console 中配置这些设置。

如上所示,有两种配置可用于绑定挂载 Docker 套接字到容器中:imageListcommandList.这些是 如下所述。

图片列表

imageList是允许绑定挂载 Docker 套接字。默认情况下,列表为空,不允许任何容器 bind-mount Docker 套接字。但是,管理员可以添加 images 添加到列表中,使用以下格式之一:

镜像参考格式描述
<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/ryukimage(带有任何标签)或docker:cli镜像,允许在启用 ECI 时绑定挂载 Docker 套接字。因此 以下工作:

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

提示

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

通常,使用标签通配符格式指定镜像会更容易,例如<image-name>:*,因为imageList不需要在新版本的 image 被使用。或者,您也可以使用不可变标签,例如: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>

则 tag作成功,但docker run命令失败 因为不允许的镜像的镜像摘要与允许的 的。

派生镜像的 Docker 套接字挂载权限

在 Docker Desktop 版本 4.34.0 中引入

如上一节所述,管理员可以配置容器列表 镜像,允许通过imageList.

这适用于大多数情况,但并非总是如此,因为它需要预先了解 应允许挂载 Docker 套接字的镜像的名称。 一些容器工具,例如 Paketo buildpacks、 构建需要 Docker 套接字绑定挂载的临时本地镜像。由于 这些短暂的镜像是未知的,因此imageList是不够的。

为了解决这个问题,从 Docker Desktop 版本 4.34 开始,Docker 套接字 挂载权限不仅适用于imageList;他们 也适用于从imageList.

也就是说,如果名为 “myLocalImage” 的本地镜像是从 “myBaseImage” 构建的 (即,具有FROM myBaseImage),则如果 “myBaseImage” 位于 这imageList,则 “myBaseImage” 和 “myLocalImage” 都可以挂载 Docker 套接字。

例如,要使 Paketo buildpack 能够与 Docker Desktop 和 ECI 一起使用, 只需将以下镜像添加到imageList:

"imageList": {
  "images": [
    "paketobuildpacks/builder:base"
  ],
  "allowDerivedImages": true
}

当 buildpack 运行时,它将创建一个派生自paketobuildpacks/builder:base并将 Docker 套接字挂载到它上面。ECI 将 允许这样做,因为它会注意到短暂镜像是从 允许的图片。

默认情况下,该行为处于禁用状态,并且必须通过设置"allowDerivedImages": true如上所示。一般来说,建议 除非您知道此设置是必需的,否则请禁用此设置。

一些注意事项:

  • 设置"allowedDerivedImages" :true会影响 容器最多额外增加 1 秒,因为 Docker Desktop 需要执行 对容器镜像进行更多检查。

  • allowDerivedImages设置仅适用于仅本地镜像 允许的镜像。也就是说,派生的镜像不能存在于远程 repository 中,因为如果是这样,您只需在imageList.

  • 要使派生镜像检查正常工作,父镜像(即imageList) 必须存在于本地(即,必须已被显式拉取 来自存储库)。这通常不是问题,因为需要这个的工具 功能(例如 Paketo buildpacks)将对父镜像进行预拉取。

  • 仅适用于 Docker Desktop 版本 4.34 和 4.35:该allowDerivedImages设置 适用于imageList使用显式标记指定(例如<name>:<tag>).它不适用于使用标记通配符指定的镜像 (例如,<name>:*) 中。在 Docker Desktop 4.36 和 稍后,此警告不再适用,这意味着allowDerivedImages设置适用于指定且带或不带通配符标签的镜像。这 可以更轻松地管理 ECI Docker 套接字镜像列表。

允许所有容器挂载 Docker 套接字

在 Docker Desktop 版本 4.36 及更高版本中,可以配置镜像 list 以允许任何容器挂载 Docker 套接字。您可以通过向"*"imageList:

"imageList": {
  "images": [
    "*"
  ]
}

这会告诉 Docker Desktop 允许所有容器挂载 Docker 套接字 这增加了灵活性,但降低了安全性。它还改进了容器 使用增强型容器隔离时的启动时间。

建议您仅在明确列出 允许的容器镜像不够灵活。

命令列表

除了imageList在前面的章节中,ECI 可以进一步 限制容器可以通过绑定挂载的 Docker 发出的命令 插座。这是通过 Docker 套接字挂载权限完成的commandList和 充当imageList(即,像 第二道防线)。

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

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

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

为了提高安全性,commandList可以配置为限制 容器内部的进程可以在 Bind-mounted Docker 套接字。这commandList可以配置为 “deny” 列表(默认)或 一个 “允许” 列表,具体取决于您的偏好。

列表中的每个命令都由其名称指定,如docker --help(例如,“ps”、“build”、“pull”、“push” 等)此外,以下内容 命令通配符可以阻止整组命令:

命令通配符描述
“容器*”指所有 “docker container ...”命令
“镜像*”指所有 “docker image ...”命令
“卷*”指所有 “docker volume ...”命令
“网络 * ”指所有 “docker network ...”命令
“构建*”指所有 “docker build ...”命令
“系统*”指所有 “docker system ...”命令

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

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

因此,如果在容器内,您对 bind 挂载的 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 http://localhost/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 套接字通常会创建/运行/删除容器, 卷和网络,但通常不会构建镜像或将它们推送到 repositories (尽管有些可能会合法地这样做)。允许哪些命令或 阻止取决于用例。

    • 请注意,容器通过 bind-mounted Docker 套接字也将在增强的容器隔离(即 生成的容器使用 Linux 用户命名空间的敏感系统 电话经过审查,等等。

注意事项和限制

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

  • 不允许在容器上使用 Docker 套接字绑定挂载 仅限本地的镜像(即不在注册表中的镜像),除非它们派生自允许的镜像,或者您允许所有容器挂载 Docker 套接字。 这是因为 Docker Desktop 从以下位置提取允许的镜像的摘要 注册表,然后使用它与 镜像。

  • commandList配置适用于所有允许 bind-mount Docker 套接字。因此,不能根据 容器。

  • 以下命令在commandList:

不支持的命令描述
composeDocker Compose
dev开发环境
extension管理 Docker 扩展
feedback向 Docker 发送反馈
init创建与 Docker 相关的启动文件
manifest管理 Docker 镜像清单
plugin管理插件
sbom查看软件物料清单 (SBOM)
scoutDocker Scout
trust管理对 Docker 镜像的信任

注意

运行 “true” 时,Docker 套接字挂载权限不适用 Docker-in-Docker(即,在容器内运行 Docker 引擎时)。在 在这种情况下,没有将主机的 Docker 套接字绑定到 容器,因此容器没有利用该配置的风险 以及主机的 Docker Engine 的凭证来执行恶意活动。 增强的容器隔离能够安全地运行 Docker-in-Docker, 无需在 Docker Desktop 中为外部容器提供真正的 root 权限 虚拟机。