首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

在 CRI 运行时内验证容器镜像签名

转发官博系列之6月29日文章

作者: Sascha Grunert

译者: Michael Yao (DaoCloud)

Kubernetes 社区自 v1.24 版本开始对基于容器镜像的工件进行签名。在 v1.26 中, 相应的增强特性从  进阶至 ,引入了针对二进制工件的签名。其他项目也采用了类似的方法,为其发布版本提供镜像签名。这意味着这些项目要么使用 GitHub actions 在自己的 CI/CD 流程中创建签名,要么依赖于 Kubernetes 的镜像推广流程, 通过向 k/k8s.io 仓库提交 PR 来自动签名镜像。使用此流程的前提要求是项目必须属于  或  GitHub 组织, 这样能够利用社区基础设施将镜像推送到暂存桶中。

假设一个项目现在生成了已签名的容器镜像工件,那么如何实际验证这些签名呢?你可以按照 Kubernetes 官方文档所述来手动验证。但是这种方式的问题在于完全没有自动化, 应仅用于测试目的。在生产环境中,sigstore policy-controller 这样的工具有助于进行自动化处理。这些工具使用自定义资源定义(CRD)提供了更高级别的 API, 并且利用集成的准入控制器和 Webhook来验证签名。

基于准入控制器的验证的一般使用流程如下:

这种架构的一个主要优点是简单:集群中的单个实例会先验证签名,然后才在节点上的容器运行时中执行镜像拉取操作, 镜像拉取是由 kubelet 触发的。这个优点也带来了分离的问题:应拉取容器镜像的节点不一定是执行准入控制的节点。这意味着如果控制器受到攻击,那么无法在整个集群范围内强制执行策略。

解决此问题的一种方式是直接在与容器运行时接口(CRI)兼容的容器运行时中进行策略评估。这种运行时直接连接到节点上的 kubelet,执行拉取镜像等所有任务。CRI-O 是可用的运行时之一,将在 v1.28 中完全支持容器镜像签名验证。

容器运行时是如何工作的呢?CRI-O 会读取一个名为  的文件, 其中包含了为容器镜像定义的所有规则。例如,你可以定义一个策略, 只允许带有以下标记或摘要的已签名镜像 :

CRI-O 必须被启动才能将策略用作全局的可信源:

CRI-O 现在可以在验证镜像签名的同时拉取镜像。例如,可以使用 (cri-tools) 来完成此操作:

CRI-O 的调试日志也会表明签名已成功验证:

策略中定义的  和  等所有字段都必须匹配, 而  和  是来自上游 fulcio(OIDC PKI) 和 rekor(透明日志) 实例的公钥。

这意味着如果你现在将策略中的  作废,例如更改为 :

然后移除镜像,因为此镜像已存在于本地:

现在当你拉取镜像时,CRI-O 将报错所需的 email 是错的:

你还可以对未签名的镜像进行策略测试。为此,你需要将键  修改为类似 :

如果你现在拉取容器镜像,CRI-O 将报错此镜像不存在签名:

需要强调的是,CRI-O 将签名中的  字段与镜像仓库进行匹配。例如,如果你要验证镜像 , 则相应的  须是 :

Kubernetes 社区引入了  作为各种镜像仓库的代理镜像。在 kpromo v4.0.2 版本发布之前,镜像已使用实际镜像签名而不是使用  签名:

将  更改为  使最终用户更容易验证签名, 因为他们不需要知道所使用的底层基础设施的详细信息。设置镜像签名身份的特性已通过  标志添加到 ,并将成为即将发布的版本的一部分。

最近在 Kubernetes 中添加了镜像拉取错误码 , 将从 v1.28 版本开始可用。这个错误码允许最终用户直接从 kubectl CLI 了解镜像拉取失败的原因。例如,如果你使用要求对  进行签名的策略同时运行 CRI-O 和 Kubernetes, 那么 Pod 的定义如下:

将在应用 Pod 清单时造成  错误:

这种整体行为提供了更符合 Kubernetes 原生体验的方式,并且不依赖于在集群中安装的第三方软件。

还有一些特殊情况需要考虑:例如,如果你希望像策略控制器那样允许按命名空间设置策略,怎么办?好消息是,CRI-O 在 v1.28 版本中即将推出这个特性!CRI-O 将支持  /  选项,为命名空间隔离的签名策略的 Pod 定义根路径。这意味着 CRI-O 将查找该路径,并组装一个类似  的策略,在镜像拉取时如果存在则使用该策略。如果(通过沙盒配置) 在镜像拉取时未提供 Pod 命名空间,或者串接的路径不存在,则 CRI-O 的全局策略将用作后备。

另一个需要考虑的特殊情况对于容器运行时中正确的签名验证至关重要:kubelet 仅在磁盘上不存在镜像时才调用容器镜像拉取。这意味着来自 Kubernetes 命名空间 A 的不受限策略可以允许拉取一个镜像,而命名空间 B 则无法强制执行该策略, 因为它已经存在于节点上了。最后,CRI-O 必须在容器创建时验证策略,而不仅仅是在镜像拉取时。这一事实使情况变得更加复杂,因为 CRI 在容器创建时并没有真正传递用户指定的镜像引用, 而是传递已经解析过的镜像 ID 或摘要。对 CRI 进行小改动 有助于解决这个问题。

现在一切都发生在容器运行时中,大家必须维护和定义策略以提供良好的用户体验。策略控制器的 CRD 非常出色,我们可以想象集群中的一个守护进程可以按命名空间为 CRI-O 编写策略。这将使任何额外的回调过时,并将验证镜像签名的责任移交给实际拉取镜像的实例。我已经评估了在纯 Kubernetes 中实现更好的容器镜像签名验证的其他可能途径, 但我没有找到一个很好的原生 API 解决方案。这意味着我相信 CRD 是正确的方法, 但用户仍然需要一个实际有作用的实例。

  • 发表于:
  • 原文链接https://page.om.qq.com/page/OGPWmPIdIuXPfIvD24reVtEA0
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券