在 Kubernetes 环境中检查镜像签名的一种方法
Kubernetes 的供应链安全需求中,有一个重要的镜像签署和校验的环节,这个环节可以使用 OPA 结合 Notary 的方式来完成。最近 Linux基金会宣布免费 sigstore 签名服务,以确认软件的来源和真实性,在项目网站闲逛时,发现一个叫做 cosign 的子项目,这是个轻量级的选择,让我非常有兴趣,于是就有了本文。
部署
目前这个工具还没有提供二进制发布,需要克隆源代码,并使用 go 1.5 进行构建,具体方法请参阅项目页面。简单说就是
# git clone https://github.com/sigstore/cosign.git
...
# cd cosign
# go build -o cosign ./cmd/cosign
...
这个工具的最基础功能有三个,分别是生成密钥对、镜像签名和校验签名。
生成密钥对
这个功能是很直白的:
cosign generate-key-pair
Enter password for private key:
Enter again:
Private key written to cosign.key
Public key written to cosign.pub
执行命令之后,输入密码,就会生成密钥对文件,私钥和公钥分别是 consign.key
和 cosign.pub
。
签名
可以使用前边生成的密钥对进行签名,例如我的工具镜像:
cosign sign -key cosign.key dustise/sleep:v0.9.6
Enter password for private key:
Pushing signature to: index.docker.io/dustise/sleep:sha256-92dad62e00d08157a3921b7d7b568a247a8b24e8a067ad5dc20b210d7b1c2ad1.cosign
读者需要注意的一点是,这个功能是对仓库中镜像的哈希码生效的,因此签署过程无需本地镜像的参与,cosign 会直接在镜像仓库中获取对应 tag 的 sha256 内容,签署之后生成一个 OCI 镜像推送到该镜像的原有仓库之中,例如前面为 dustise/sleep:v0.9.6
进行签名,就生成了一个 dustise/sleep:sha256-92da.....1c2ad1.cosign
的镜像。如果被签名镜像在本地不存在,在完成操作之后,使用 docker images
命令查看,会发现被签署镜像和签署生成的镜像都不存在于本地。
另外一个就是,因为这里有 Push 操作,因此这个签署过程通常是有登录镜像库的需求的。
校验
校验过程很简单,使用 verify
指令,指定公钥即可,例如:
cosign verify -key cosign.pub dustise/sleep:v0.9.6
The following checks were performed on each of these signatures:
- The cosign claims were validated
- The signatures were verified against the specified public key
- Any certificates were verified against the Fulcio roots.
...
注意
如果使用 cosign 来进行签署,过程基本上来说还算是愉快的,私钥放置在 CI 之中,而公钥则可以保存在集群里,简单一点的方式,使用客户端定期扫描;复杂的方式,可以实现一个简单的 admission controller 来根据 Selector 对负载进行校验,同样需要注意的是,cosign 只针对远程(镜像库)进行操作,对本地的同 Tag 替换是没什么防御力的,因此这里还要使用 Always Pull 的策略进行弥补(可以使用 Kyverno 或者 Gatekeeper 来强制实施)。