高级配置选项
注意
此功能适用于 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 套接字绑定挂载到容器中:imageList
和 commandList
。这些将在下面介绍。
镜像列表
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/localstack
或 docker.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 套接字上的 build
和 push
命令
"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
中尚不支持
不支持的命令 | 描述 |
---|---|
compose | Docker compose |
dev | Docker 开发环境 |
extension | 管理 Docker 扩展 |
feedback | 向 Docker 发送反馈 |
init | 创建与 Docker 相关的入门文件 |
manifest | 管理 Docker 镜像清单 |
plugins | 管理插件 |
sbom | 查看软件物料清单 (SBOM) |
scan | Docker Scan |
scout | Docker Scout |
信任 | 管理 Docker 镜像的信任 |
注意
当运行“真正的”Docker-in-Docker(即在容器内运行 Docker 引擎)时,Docker 套接字挂载权限不适用。在这种情况下,不会将宿主机 Docker 套接字绑定挂载到容器中,因此容器不会利用宿主机 Docker 引擎的配置和凭据来执行恶意活动。增强型容器隔离功能能够安全地运行 Docker-in-Docker,而无需在 Docker Desktop VM 中为外部容器提供真正的 root 权限。