必须同时启用DOCKER_CONTENT_TRUST=1环境变量和仓库端Notary/Cosign签名服务,配置daemon.json强制验证,并使用明确tag签名,否则验证形同虚设。

要在 Docker 中真正实现镜像仓库的签名验证并保障部署安全,不能只靠“开了 Content Trust”就认为万事大吉。核心是构建一条从密钥生成、签名绑定、服务端托管到客户端强制校验的完整信任链——任一环节缺失,验证就形同虚设。
明确启用方式:环境变量 + 服务端支持缺一不可
Docker 客户端默认完全不检查签名。必须显式启用:
- 临时启用:DOCKER_CONTENT_TRUST=1 docker pull nginx:alpine
- 长期启用:将 export DOCKER_CONTENT_TRUST=1 写入 ~/.bashrc 或 ~/.zshrc,再执行 source 生效
- 仅设变量还不够——目标仓库必须提供签名元数据服务。Docker Hub 默认支持;私有仓库(如 Harbor)需额外部署 Notary Server 或启用 Cosign 兼容模式,否则拉取时会报 no trust data available
为私有仓库配置可信签名后端
以 Harbor 为例,仅开启 UI 上的「内容信任」开关远远不够,必须完成三步集成:
- 在 Harbor 后端启用 Notary 服务(v2 推荐),或配置为对接外部 Cosign + Rekor 服务
- 确保 Harbor 的 signature.verification_cert 指向你用于验证签名的公钥(如 cosign.pub),且该公钥已由可信根签发
- 若使用自签名证书(如 notary.example.com),须将 CA 证书复制到每个 Docker 主机的 /etc/docker/certs.d/notary.example.com:4443/ca.crt,否则连接 Notary 时直接失败,报 x509: certificate signed by unknown authority
签名操作要绑定具体 tag,避免 latest 陷阱
签名不是对镜像“打标签”,而是对镜像 manifest 的 SHA256 摘要加密。这意味着:
- 必须用明确 tag 推送:docker push my-registry.local/app:v1.2.0(✅)
- 禁止用 latest 这类动态 tag:docker push my-registry.local/app:latest(❌)——签名无法稳定绑定,后续拉取可能命中未签名的旧层
- 首次推送某仓库时,Docker 会自动生成 root key 和 targets key;若团队协作,需提前用 docker trust signer add --key pubkey.pem myorg/app 将公钥导入信任列表
运行时强制拦截:让验证下沉到 daemon 层
仅靠客户端变量仍存在绕过风险(比如有人临时 unset)。更可靠的方式是配置 Docker daemon 直接拦截:
- 编辑 /etc/docker/daemon.json,加入:
{ "content-trust": { "mode": "enforced", "verification": { "enabled": true, "policy": "strict" } } }
- 重启 daemon:sudo systemctl restart docker
- 此后所有 docker pull 和 docker run 都隐式触发签名验证,未签名或签名失效的镜像会立即报错:failed to verify signature: no valid signature found











