停止信任容器注册表,验证镜像签名
作者:Wojciech Kocjan / Tyson Kamp / 产品,用例
2022年10月18日
导航到
简介
InfluxData的主要产品之一是InfluxDB Cloud。它是一个云原生、SaaS平台,以无服务器、可扩展的方式访问InfluxDB。InfluxDB Cloud可在所有主要的公共云中获取。
InfluxDB Cloud从头开始设计以支持自动扩展和处理不同类型的工作负载。在底层,InfluxDB Cloud是一个基于Kubernetes的应用程序,由一串微服务组成,在多云、多区域设置中运行。
该应用程序包括一个使用持久卷和云原生对象存储(如AWS云上的S3)进行持久化的存储层。它使用Kafka和Zookeeper进行队列传入数据,并使用管理SQL数据库存储其他数据。该应用程序还包括约50个无状态微服务,执行各种操作,如写入和查询时序数据,以及定期运行任务。
在InfluxDB的云原生提供中,我们识别出一个特定的安全问题。应用程序在第三方注册表中存储了成千上万的容器,然后部署到我们的集群中。我们如何知道在拉取/运行时使用的容器与CI/CD管道中使用的容器是相同的?如果第三方注册表被破坏怎么办?
要求容器镜像签名
根据基于云的系统标准风险所有权模型,实体(公司等)对其提供的供应链和组件的安全性负责,无论其组成部分提供商或服务/系统供应商。 “这不是我们的问题”是不被接受的。
在考虑如何减轻对容器注册表的完全破坏时,一个相对直接的想法浮现在脑海中。推送镜像后,远程注册表会返回一个摘要,这有助于识别镜像并验证其完整性。一种缓解解决方案的选项是创建一个数据库,记录应用在推送容器后立即获得的摘要。如果你信任哈希和标准加密工具,并且可以接受存储此类信息的数据库,那么这种方法可以大致处理镜像的真实性和完整性。但这种方法也带来了额外的挑战。你需要确保所有容器镜像的消费者都能及时访问摘要数据库。
第二种,更吸引人的选项是在容器推送时为每个容器镜像创建一个签名,并使可以轻松验证签名的公钥列表易于获取。毕竟,公钥并不敏感。公钥列表很重要(想想重放攻击),但稍后再详细说明。
对于Influx的兴趣,我们考虑当我们可以验证所有相关的OCI容器镜像(打算在InfluxData管理的集群上运行)都来自InfluxData——无论是某个时间点还是从起始点——并且没有被篡改(真实性和完整性)时,风险得到了缓解。签名使我们能够检测任何篡改,因此它们对于这种缓解策略非常有吸引力。稍后我们将更深入地探讨供应链的自动完整性和真实性管理,但我们正在采取“小步子”的方法。
架构和镜像
我们主要使用内部编写的代码和集成构建InfluxDB Cloud。我们使用CI系统构建代码,使用CD系统部署它。这确保我们可以尽快构建和部署应用程序代码的任何更改。
我们还使用了来自InfluxData的多个开源组件,例如Telegraf或Telegraf-operator,以及第三方组件,例如Kafka和HashiCorp Vault。InfluxDB Cloud团队并不——在某些情况下也不愿意——在内部构建或控制这些第三方镜像。尽管如此,团队有能力和选择接受特定的镜像——最好是它们的SHA摘要——并签名这些镜像。我们将在下一节中更详细地描述我们将签名保存在单独的位置。
我们想要的是频繁地创建签名密钥和签名,并使公钥验证密钥易于获取。这种方法比跟踪摘要和担心一致性更简单、更可扩展。InfluxData目前在三个云提供商上管理大量生产集群,我们认为这个容器签名想法应该具有很好的可扩展性。
添加数字签名
在项目的早期阶段,团队考察了两个GitHub仓库:Connaisseur和SigStore项目policy-controller。Connaisseur被证明在概念验证阶段非常快速设置且易于配置。而Policy-controller的配置耗时更长且更复杂,但我们接受了这种权衡,因为可配置性往往会导致复杂性。团队最终通过自动化ClusterImagePolicy的创建和重新应用,使Policy-controller工作。接下来,他们自动化了测试环境的搭建,并创建了一个Bash脚本来进行签名验证的正面和负面测试。
Connaisseur在其开发上似乎更加成熟,但它并不是像SigStore那样的针对供应链风险的更大系统的一部分。此外,Connaisseur是用Python编写的,似乎活跃开发度和参与度较低。考虑到policy-controller/SigStore在解决供应链风险需求方面的完整性,其活跃的开发(尽管还不成熟),以及它是用Golang(与InfluxDB相同)编写的,InfluxData选择了policy-controller。
对于创建签名密钥对和执行签名创建和验证,我们选择了cosign。这是一个简单选择。它正是这项工作的正确工具。
我们还想让密钥对轮换变得容易,自动化作业会轮换签名密钥对以创建和验证签名。我们还在调整轮换频率,但目标是每周至少轮换一次,一天不超过几次。我们将签名密钥对存储在HashiCorp Vault中,并且它们永远不会离开它,利用Vault执行签名过程。
一个安全且可信的端点,在内部网络中可用,提供了非敏感的公钥。所有消费图像并定期进行验证的集群都会拉取最新的公钥集合并相应地更新其本地配置。如果集群无法使用来自可信端点的公钥列表验证签名,则集群不会加载图像。
这使InfluxData能够在创建短暂的生命周期密钥对和签名的同时,也使消费图像的集群能够验证容器图像的签名。
对于我们的所有内部代码,CI系统自动为所有已审查、批准并打算在生产环境中运行的代码签名。我们将在与图像相同的位置存储这些容器图像的数字签名。
对于开源和第三方图像,我们在外部引用容器图像,并将InfluxDB Cloud的签名保存在我们控制的专用图像注册表中。这样,InfluxDB Cloud可以引用上游图像,但在我们的图像注册表中创建和维护签名。Sigstore cosign和policy-controller完全支持这种做法。
作为InfluxDB Cloud元数据的一部分,管理基础设施的团队会列出所有允许运行的开放源代码和第三方图像。该列表包括特定的图像及其SHA摘要。所有这些图像都会定期签名,签名将由InfluxData写入OCI注册表控制器。这使我们的Kubernetes集群在验证签名时可以运行图像,即使图像本身位于上游注册表中。
这种设置在必要时更新不属于InfluxDB Cloud代码的应用程序时,会创建一些额外的负担。任何更新都需要获取更新的上游图像列表,并在执行任何更新之前确保它们已签名。然而,这也有优点,因为它确保了审查图像更改成为更新外部组件的审查过程的一部分。
在InfluxData定义了上述方法和流程之后,签名和验证的部署和启用开始。这首先是通过对图像子集进行签名开始的,然后是在单个Kubernetes集群中部署策略控制器并验证这些图像。
在经历了初步的挑战之后,一旦在一个集群中验证正确工作,我们就启用了其他集群的策略控制器,并更新了我们的检查以包括所有图像。
InfluxData使用GitOps管理其基础设施,因此启用生产环境意味着启用策略控制器、更新图像验证策略的逻辑,并保持有效公钥列表的更新。
一旦所有这些设置在额外的Kubernetes集群上运行,InfluxDB Cloud工作负载就可以验证它们的容器图像。
以下是我们的基础设施设置的示意图
InfluxDB Cloud容器信任
处理安全事件
当发生安全事件时,我们特别关注使密钥轮换尽可能简单。此解决方案是许多在事件场景中需要关注的问题之一,因此我们抓住了任何可能的机会来简化流程。
配置项尽可能少,我们将架构尽可能简化。文档由多个团队提供输入,并且直到那些对实现知之甚少的人能够遵循创建的重置系统说明,文档才被认为可用。这包括
-
轮换安全控制工件,例如从CI系统到图像签名端点的认证密钥
-
生成用于数字签名容器图像的新密钥对
-
为所有容器图像创建新签名
-
加快可能受损害的密钥对(导致旧签名无效)的弃用
我们可以在几小时内恢复整个系统,包括在所有集群中重新部署新签名的容器图像。
结语
在设计此系统时,我们考虑的主要威胁向量之一是重放攻击。在这种场景中,重放攻击是指具有已知漏洞的软件组件能够重新安装到系统中的能力。例如,如果攻击者发现一组容器图像中存在严重漏洞,他们可以从注册表中获取这些图像及其签名,以尝试在以后重新引入它们(以及漏洞)。
InfluxData的解决方案频繁轮换签名密钥,使得重新引入已知漏洞的图像在实际上是不切实际的。签名有效的窗口时间太小,对攻击者来说没有实际用途,因为签名的有效寿命最多只有几天或几周。
该解决方案仅使用公开可用的加密解决方案和最先进的加密标准。InfluxData不创建自己的安全组件,而是在快速CICD GitOps框架中部署知名组件和控制。InfluxData相信这种模式固有的强度。
Influx Container Trust解决方案仅依赖于Kubernetes和SigStore组件。该解决方案对容器注册表和云提供商无关,并在Influx管理的任何K8s集群中运行。因此,Influx域之间的采用无缝。
尽管显然没有“一刀切”的解决方案,InfluxData致力于以最符合其需求的方式减轻注册表被破坏的威胁。该方法与其他群体(企业、政府等)的需求重叠,并有望为解决此类风险以及采用此威胁缓解解决方案提供一些思路。InfluxData部署团队成员Wojciech Kocjan和Tyson Kamp将于2022年10月25日星期二在美国密歇根州底特律举行的SigStoreCon上发表演讲,以进一步阐述这篇博客文章。欢迎参加或联系他们获取更多信息。