你有没有遇到过这样的情况:在 Docker 里 run 一个看似正规的 nginx 镜像,结果容器跑起来后偷偷往日志里写加密货币挖矿脚本?或者 CI/CD 流水线突然构建失败,查了半天发现 base 镜像被人替换成带后门的版本?这可不是危言耸听——公开 Registry 上的镜像,谁都能推、谁都能改,光靠镜像名和 tag 根本没法保真。
签名不是“盖章”,是数学验证
容器镜像签名机制,说白了就是给镜像打上一张“数字身份证”。它不依赖仓库管理员的信任背书,而是用非对称加密(比如 ECDSA)让开发者用自己的私钥对镜像 manifest(清单文件)生成签名,别人用对应的公钥就能验出这个镜像从打包到推送,一比特都没被改过。
举个生活化的例子:就像你收到一封带火漆印章的信,但这个印章不是画上去的,而是用你家特制的模具+熔蜡压出来的——收信人拿你公开的模具一比对,蜡形严丝合缝,就说明信没被调包。
实际怎么签?以 cosign 为例
目前最常用的工具是 cosign(Sigstore 项目出品),轻量、开源、支持 OCI 标准。假设你刚构建好一个镜像:
docker build -t ghcr.io/yourname/app:v1.2 .先登录 GitHub Container Registry(或其他支持 OCI 的 registry),再用 cosign 签名:
cosign sign --key cosign.key ghcr.io/yourname/app:v1.2签名会作为独立 artifact 推送到同一 registry 下的 .sig 路径,不改动原镜像。别人拉取时,可以强制校验:
cosign verify --key cosign.pub ghcr.io/yourname/app:v1.2如果输出 Verified OK,且显示签名时间、签名人邮箱(若配置了 identity),那基本可以放心运行。
别只签不验:Docker 和 Kubernetes 怎么落地?
Docker Desktop 本身不自动验签,但可以通过 notary 或配合 containerd 的 image verification 插件启用。更现实的做法是在 CI 流水线里加一步:
# 在部署脚本中加入
if ! cosign verify --key prod.pub $IMAGE_REF; then
echo "签名验证失败,拒绝部署!" >&2
exit 1
fiKubernetes 用户可以用 SLSA 认证策略或 Pod Security Admission 结合 ImagePolicyWebhook 实现集群级拦截——只要镜像没通过指定密钥验证,Pod 就起不来。
小提醒:签名≠万能保险
签名只保证“镜像内容没变”,不保证代码本身安全。比如你签了一个含已知漏洞的 Log4j 镜像,它依然会爆。所以签名要和 SBOM(软件物料清单)、漏洞扫描联动使用,形成完整信任链。
下次 pull 镜像前,不妨多敲一行 cosign verify——这不是多此一举,是你给自己服务器加的一道隐形防盗门。