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 套接字挂载到容器中,但以受控方式。

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

{
  "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

图片列表

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

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

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

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

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

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

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

提示

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

通常,使用标签通配符格式指定镜像更容易,例如 ,因为每当 image 被使用。或者,您也可以使用不可变标签,例如 , 但它并不总是像通配符那样工作,因为,例如, Testcontainers 使用镜像的特定版本,不一定是最新版本 一。<image-name>:*imageList:latest

启用 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 套接字 挂载权限不仅适用于 中列出的镜像;他们 也适用于从 .imageListimageList

也就是说,如果名为 “myLocalImage” 的本地镜像是从 “myBaseImage” 构建的 (即,有一个带有 的 Dockerfile),那么如果 “myBaseImage” 在 的 ,“myBaseImage” 和 “myLocalImage” 都可以挂载 Docker 套接字。FROM myBaseImageimageList

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

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

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

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

一些注意事项:

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

  • 该设置仅适用于根据 允许的镜像。也就是说,派生的镜像不能存在于远程 存储库,因为如果是这样,您只需在 .allowDerivedImagesimageList

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

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

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

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

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

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

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

命令列表

除了前面几节中描述的内容外,ECI 还可以进一步 限制容器可以通过绑定挂载的 Docker 发出的命令 插座。这是通过 Docker 套接字挂载权限完成的,并且 充当 (即 第二道防线)。imageListcommandListimageList

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

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

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

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

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

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

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

"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

  • 如果可能,请在 (例如, ) 中使用标记通配符格式,因为这样就无需由于 image 标记更改而更新文件。imageList<image_name>:*admin-settings.json

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

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

注意事项和限制

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

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

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

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

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

注意

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