使用Docker Notary签署多平台镜像成功,为何标签未被信任?
问题
我严格遵循某Docker签名Action的步骤对多平台镜像做信任与签名,仅修改了SHA256提取逻辑(原脚本的cut命令无法返回有效SHA256,推测manifest-push输出格式变更),尝试多个推送返回的SHA256值结果一致。
当前环境:Docker 23.0.0,Ubuntu上通过sudo apt-get notary安装Notary包。脚本执行无报错,但最终镜像标签无签名。已知buildx无法帮助签署多平台镜像,仅能推送未签名镜像。
执行脚本如下:
export DOCKER_CONTENT_TRUST=1 # 构建多平台镜像,认证参数已省略;需要Docker 23.0.0 docker build --platform=linux/amd64 --tag mydockerid/test-amd64:$(tag)$(tagSuffix) --file $(Folder)/Dockerfile . docker build --platform=linux/arm64 --tag mydockerid/test-arm64:$(tag)$(tagSuffix) --file $(Folder)/Dockerfile . export DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE='$(SignerKeyPassword)' docker trust key load $(signerKey.secureFilePath) export NOTARY_TARGETS_PASSPHRASE='$(TargetKeyPassword)' export NOTARY_SNAPSHOT_PASSPHRASE='$(SnapshotKeyPassword)' # 签名并推送平台专属镜像——这一步是否必要? docker trust sign mydockerid/test-amd64:$(tag)$(tagSuffix) docker trust sign mydockerid/test-arm64:$(tag)$(tagSuffix) # 从平台镜像清单创建镜像清单列表 docker manifest create mydockerid/test:$(tag)$(tagSuffix) mydockerid/test-amd64:$(tag)$(tagSuffix) mydockerid/test-arm64:$(tag)$(tagSuffix) # 原Action命令无法提取有效SHA # SHA_256=$(docker manifest push mydockerid/test:$(tag)$(tagSuffix) --purge | cut -d ':' -f 2) # 推送清单 MANIFEST=$(docker manifest push mydockerid/test:$(tag)$(tagSuffix) --purge) # 提取推送命令返回的最后一个sha256,这是唯一不对应镜像层的sha256 echo "MANIFEST: ${MANIFEST}" SHA_256=$(echo ${MANIFEST//*:}) echo "SHA_256: $SHA_256" MANIFEST_FROM_REG="$(docker manifest inspect "mydockerid/test:$(tag)$(tagSuffix)" -v)" echo "MANIFEST_FROM_REG: $MANIFEST_FROM_REG" # 参照Action脚本计算字节大小 BYTES_SIZE="$(printf "${MANIFEST_FROM_REG}" | jq -r '.[].Descriptor.size' | uniq)" echo "BYTES_SIZE: $BYTES_SIZE" REF="mydockerid/test" TAG="$(tag)$(tagSuffix)" AUTH_BASIC=$(SignerAuthBasic) ROLE_CLI="" # 检查密钥是否存在 notary key list -d $(DOCKER_CONFIG)/trust/ # 将user:pat编码为base64 export NOTARY_AUTH="$(printf "${AUTH_BASIC}" | base64 -w0)" TRUST_FOLDER="$(DOCKER_CONFIG)/trust/" echo "TRUST_FOLDER: $TRUST_FOLDER" # 发布并签名 notary -d ${TRUST_FOLDER} -s "https://notary.docker.io" addhash "${REF}" "${TAG}" "${BYTES_SIZE}" --sha256 "${SHA_256}" ${ROLE_CLI} --publish --verbose notary -s "https://notary.docker.io" list "${REF}" unset NOTARY_AUTH;
脚本执行无错误,notary ... --publish ...命令返回:
Addition of target "1.1.1234-beta" by sha256 hash to repository "***/test" staged for next publish. Auto-publishing changes to ***/test Successfully published changes for repository ***/test
最后notary ... list命令正常列出镜像标签:
NAME DIGEST SIZE (BYTES) ROLE ---- ------ ------------ ---- 1.0.1234-beta 91e75e43bd.... 637 targets
但执行docker trust inspect --pretty mydockerid/test时显示:
docker trust inspect --pretty mydockerid/test No signatures for mydockerid/test ...
解决方案
1. 修正清单列表的SHA256提取逻辑
你当前提取的SHA256可能不是**多平台清单列表(manifest list)**的正确哈希值。推送时返回的多个哈希中,需要精准定位清单列表本身的哈希,建议直接从docker manifest inspect的输出中提取:
# 获取清单列表的顶层digest SHA_256=$(docker manifest inspect mydockerid/test:$(tag)$(tagSuffix) -v | jq -r '.[].Descriptor.digest' | cut -d ':' -f 2)
2. 指定标签执行docker trust inspect
docker trust inspect --pretty mydockerid/test默认检查latest标签,而你签名的是$(tag)$(tagSuffix)标签,必须明确指定标签才能看到对应签名:
docker trust inspect --pretty mydockerid/test:$(tag)$(tagSuffix)
3. 补全Notary操作的角色参数
执行notary addhash时ROLE_CLI为空,需要指定正确的角色(如--role targets),确保签名关联到有效角色:
notary -d ${TRUST_FOLDER} -s "https://notary.docker.io" addhash "${REF}" "${TAG}" "${BYTES_SIZE}" --sha256 "${SHA_256}" --role targets --publish --verbose
4. 可跳过平台镜像的签名步骤
平台专属镜像的签名并非多平台清单列表签名的必要前提,可以直接跳过这一步,专注于最终清单的签名即可。
验证步骤
完成修改后,按以下流程验证:
- 重新推送并签名多平台清单列表
- 执行
docker trust inspect --pretty mydockerid/test:$(tag)$(tagSuffix)查看签名状态 - 开启
export DOCKER_CONTENT_TRUST=1后执行docker pull mydockerid/test:$(tag)$(tagSuffix),验证Docker是否会自动校验签名
内容的提问来源于stack exchange,提问作者J.R.

