如何在使用docker pull(启用Docker Content Trust)时固定公共根密钥

51次阅读
没有评论

问题描述

想知道如何在执行docker pull时(启用Docker Content Trust),如果镜像没有使用他提供的公共密钥或下级密钥进行有效签名,该如何使其失败。
用户发现,实际上,Docker Content Trust在首次下载镜像时会默默地下载并信任(TOFU)根密钥。
用户的docker应用程序是一个CI流程,将使用debian:stable-latest docker镜像在临时云实例中构建应用程序的发布版本。由于用于构建应用程序的服务器是临时的,DCT实际上为用户提供了零安全性,并且在每次执行构建过程时都会容易受到docker镜像有效载荷的中间人攻击。
因此,用户需要固定Debian用于签署其docker镜像的公共根密钥。所以问题是:
1. 如何下载Debian用于签署其docker镜像的公共根密钥?
2. 如何告诉docker pull使用上述密钥,并在镜像不包含来自该密钥或下级密钥的有效签名时失败?

解决方案

请注意以下操作注意版本差异及修改前做好备份。

方案1

要固定debian的公共根密钥,可以执行以下操作:
1. 使用以下命令创建一个名为root.json的文件,并将其保存在$HOME/.docker/trust/tuf/docker.io/library/debian/metadata目录下:

sudo su -
mkdir -p /root/.docker/trust/tuf/docker.io/library/debian/metadata
chown -R root:root /root/.docker
chmod -R 0700 /root/.docker
echo '{"signed":{"_type":"Root","consistent_snapshot":false,"expires":"2025-08-07T20:55:22.677722315-07:00","keys":{"5717dcd81d9fb5b73aa15f2d887a6a0de543829ab9b2d411acce9219c2f8ba3a":{"keytype":"ecdsa","keyval":{"private":null,"public":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEsslGF2xHOYztrocb2OsRF2zth16v170QiLAyKdce1nQgOJ34FOk679ClPL9/RNnJukf2JfQXSlVV/qcsvxV2dQ=="}},"575d013f89e3cbbb19e0fb06aa33566c22718318e0c9ffb1ab5cc4291e07bf84":{"keytype":"ecdsa-x509","keyval":{"private":null,"public":"LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUJlVENDQVIrZ0F3SUJBZ0lRWExkUFFHTGJaOE84UXFlTzVuZlBRekFLQmdncWhrak9QUVFEQWpBak1TRXcKSHdZRFZRUURFeGhrYjJOclpYSXVhVzh2YkdsaWNtRnllUzlrWldKcFlXNHdIaGNOTVRVd09ERXhNRE0xTlRJeQpXaGNOTWpVd09EQTRNRE0xTlRJeVdqQWpNU0V3SHdZRFZRUURFeGhrYjJOclpYSXVhVzh2YkdsaWNtRnllUzlrClpXSnBZVzR3V1RBVEJnY3Foa2pPUFFJQkJnZ3Foa2pPUFFNQkJ3TkNBQVE1ZGkxcmxPQjBMQmRNS2N0VFQxYmwKUGd6aXYxOUJDdW9tNEFNL3BUdURtdjBnS0E5S1ptNUVjLy9VQmhSODVCYmR0cTk0cXhQM3IwUjhRc3FQV1Y4SQpvelV3TXpBT0JnTlZIUThCQWY4RUJBTUNBS0F3RXdZRFZSMGxCQXd3Q2dZSUt3WUJCUVVIQXdNd0RBWURWUjBUCkFRSC9CQUl3QURBS0JnZ3Foa2pPUFFRREFnTklBREJGQWlBOUFOZ3dPN2tBdUVIK3U2N25XNlFLWmlMdWd5UVcKaEQ3Vys5WjIza01mTndJaEFJa3RTaW1TdFdRQkFoOG9WOXhjaWNVWWVUN0pyUG82a0RqeHU1YitGZ3MxCi0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K"}},"728c96ff5e9f48d4e66d5a0c3ecabfdd90bee2b5f9f80b950ed9c668db264a70":{"keytype":"ecdsa","keyval":{"private":null,"public":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAENtpBkDJ2oYaAAVdOkP0A6J0XwUkYGuFRk+q8N4WCPu2VnNIuBJkatPCWdEtHfQ9nNYLeanWgG62/UmJnx3E2Yg=="}},"d48327d85f0490827db7c931eedb58d293e1da5fc425ea0cde3e6c13b397ad69":{"keytype":"ecdsa","keyval":{"private":null,"public":"MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEwfs26T/cpjvNTXVJpK7Wv8oDOnNKL78AT3Y1QD356OIAggwPupX2LQjZU6CVzCjm+pkJIO4clu9Q2n540gKuzQ=="}}},"roles":{"root":{"keyids":["575d013f89e3cbbb19e0fb06aa33566c22718318e0c9ffb1ab5cc4291e07bf84"],"threshold":1},"snapshot":{"keyids":["d48327d85f0490827db7c931eedb58d293e1da5fc425ea0cde3e6c13b397ad69"],"threshold":1},"targets":{"keyids":["5717dcd81d9fb5b73aa15f2d887a6a0de543829ab9b2d411acce9219c2f8ba3a"],"threshold":1},"timestamp":{"keyids":["728c96ff5e9f48d4e66d5a0c3ecabfdd90bee2b5f9f80b950ed9c668db264a70"],"threshold":1}},"version":1},"signatures":[{"keyid":"575d013f89e3cbbb19e0fb06aa33566c22718318e0c9ffb1ab5cc4291e07bf84","method":"ecdsa","sig":"3WbX1VXN9E8LRmSG+E4SQlBUNqBNchhwAStWnRWLLyAOoFNBq5xmIgSO3UYYuKyJvL7kbMoONRbn5Vk2p2Wqrg=="}]}' > /root/.docker/trust/tuf/docker.io/library/debian/metadata/root.json
  1. 执行以下命令,将DOCKER_CONTENT_TRUST设置为1,并使用docker pull命令拉取debian:stable-slim镜像:
export DOCKER_CONTENT_TRUST=1
docker pull debian:stable-slim

方案2

使用脚本或工具来管理容器的启动顺序可能会增加复杂性,并且需要确保容器A和容器B之间的依赖关系正确设置。
另一种方法是编写脚本或使用工具来控制容器的运行顺序。你可以使用docker run命令来手动控制容器的启动顺序,或者使用一些第三方工具来管理容器的依赖关系。

示例:

以下是一个简单的bash脚本示例,可以在容器A启动后启动容器B:

#!/bin/bash
# 启动容器A
docker run -d --name container_a your_image_a
# 等待容器A完全启动
while ! docker exec container_a echo "Container A is ready"; do
  sleep 1
done
# 启动容器B
docker run -d --name container_b your_image_b

在这个示例中,我们首先使用docker run命令启动容器A,并将其命名为container_a。然后,使用一个循环来等待容器A完全启动(这里是通过在容器内运行echo命令来测试)。一旦容器A就绪,我们再使用docker run命令启动容器B,并将其命名为container_b

正文完