人生第一个P0事故

我们公司前一段时间在过PCI DSS认证,其中有一项要求是要对所有会被部署到生产环境的镜像在部署之前进行签名和验证。由于我管理着公司的私有Harbor,这个事情也就“顺理成章”地由我来做了。

PCI DSS,全称为 Payment Card Industry Data Security Standard(支付卡行业数据安全标准),是由支付卡行业安全标准委员会(PCI SSC, Payment Card Industry Security Standards Council)制定的一套安全标准。PCI DSS 是支付卡行业内一项至关重要的安全标准,旨在通过一系列严格的安全控制措施,保护持卡人的数据安全。

在公司内部牵头PCI DSS认证的同事找到我和我的leader谈这个事情的时候,只有10天左右的时间了,也就是说我们要在10天时间里设计、开发、测试和部署一套用于镜像签名和验证的系统,而且我还不是full-time做这个事情,我本身还有其他工作要做,这为后面的内容埋下了伏笔,也是让我这两个月来倍感压力的源头。

我们团队其他的同事在前期有过一些相关的研究,最后选择了sigstore的方案,也就是使用cosign来做容器镜像签名和验证。

Sigstore 是一个开源项目,旨在为软件供应链提供一种不用密钥的签名解决方案。它的主要目标是简化软件签名和验证的流程,从而提高软件供应链的安全性。Sigstore 由 Linux 基金会下的 OpenSSF(开放软件安全基金会)托管,并得到了多个行业领导者的支持。

Cosign 是 Sigstore 项目中的一个工具,专门用于签名和验证容器镜像。它简化了容器镜像签名的过程,并确保签名和验证的安全性。Cosign 支持多种签名方式,包括传统的私钥签名和无密钥签名(使用 Sigstore)。

由于用户的需求和一些安全原因,我们不能直接让用户使用cosign命令自己去签名和验证,而是要开发一个后端服务,提供一个API给用户,让用户通过调用这个API的形式来做签名和验证。

我最终是用Django + Django rest Framework + K8S 作为infrastructure来开发和运行服务的(下文把这个服务称之为DIS,Docker Image Sign)。

开头提到过,PCI DSS的要求是:对所有会被部署到生产环境的镜像在部署之前进行签名和验证。如果熟悉CICD的话,可能已经意识到问题了。
这意味镜像签名和验证会阻塞CD过程,也就是说如果签名和验证没完成,就不能部署到生产环境。这要求DIS要能365 * 24 在线,并且能撑住并发。然后DIS是我一个人在大三四天内开发出来的,这三天还不是full-time的。

上线后大概5天的时候遇到了第一次事故。

我给运行DIS后端的k8s pod配置的是1核心CPU和1GB内存,这是我们infrastructure同事提供的公共模板,不能自定义,我的想法是,既然不能修改计算资源的配置,就通过增加pod的副本数来提高后端的计算和处理能力,所以我设置了10个pod。
由于时间很赶,上线没做压测,上线之后我又忙于指导用户如何使用DIS,没时间做压测,大概在上线后第5天,遇到了一波异常高的并发。

说是异常高,实际上只有600左右。平常应该只有200左右的并发,因为这个时候还没有大规模推广,只有部分最紧急的项目使用了DIS。多出来的400个并发,是由于一个项目团队CICD配置有点问题,他们每一次合并代码仓库分支的时候都会触发一次CICD,然后对所有的镜像做签名和验证,他们一共有接近400个镜像,但他们真正有变化、需要签名和验证的镜像其实只有两三个。他们合并分支的频率也很高,高峰的时候大概几分钟就会合并一个分支。也就是光这个项目,每几分钟就会送400个请求到DIS来。

我后来去查监控和日志的时候,发现他们这种情况大概持续了半个小时左右,DIS后端就撑不住,挂掉了。

DIS 后端用了10个1C1G的pod也只能做到600个并发的原因是,DIS服务本质上是执行一个cosign的shell命令,执行这个命令本身就需要大约7秒的时间,这是没办法优化的,所以每个请求都需要7秒多的时间才能处理完,很难提升并发。

发现问题后,第一时间重启服务并请infrastructure的同事调整了计算资源,我去联系前文说的那个项目负责人,请他们暂停CICD,过了几分钟服务就恢复了。

事后,我们增加了监控项,比如并发数量,计算资源利用率,日志中特定的报错信息。
是的,在这次出问题之前,DIS都没有任何监控。

DIS上线大概40天左右,再次遇到了事故,并且最后被定性为P0级别。

DIS后端依赖一个叫做rekor的私有服务,这个服务是我们部门的其他同事提供的,因为他们已经有这个服务了,我在了解到这个信息后,就去找他们谈能否共用,他们同意了。

Rekor 是 Sigstore 项目的一个重要组成部分,用于记录不可变地记录软件制品的签名和其他元数据。

这次的事故就是因为rekor在一次变更后,FQDN没有正确地指向其后端服务,DIS后端不能调用其服务。

更重要的是,rekor的owner做变更前没有通知我,他们事后也没有做测试,我完全不知道这件事。
更更重要的是,DIS的监控项不够全面,没有及时发现服务故障。

这次故障持续了17.5个小时才被发现。不巧的是,这期间我们公司最重要的SaaS产品要修复一个线上bug,由于DIS宕机导致这个产品的开发团队不能部署更新程序,直到我们恢复DIS之后他们才能部署。

后来听小道消息说,公司因为这次bug赔偿了大约几十万美金。

事后,我们团队对这次事故做了一次复盘。最终得出的结论是:我们在最开始不应该草率地答应负责PCI的同事在如此短的时间内提供DIS这个服务。 这才是根源。

我很庆幸,公司和领导没有把这次事故归责于我。因为大家考虑了很多因素之后,得出的结论是,我们团队的任何人都没有把握能在那么短的时间内把DIS做的更好。再此要感谢领导。

我自认为我们团队整体上是一个比较负责和积极的团队,正因此,一开始了解到PCI需要有镜像签名和验证的服务的时候,我和我的领导都答应他们尽力提供这个服务。但当时对风险评估不够全面,没意识到DIS会阻塞CD过程,如果当时就意识到这一点的话,一定不会这么草率地答应,即使答应了,也不可能由我一个人parttime地去做,而是会临时召集相当一部分资源来做这个事情。
\

分享一个小故事,在大概15年前,由于我们公司菲律宾的一个同事错误地修改了一个配置项,导致日本铁路停运了几个小时,因为日本铁路的IT使用了我们公司的产品。公司高层举行记者发布会向日本民众道歉,但是最后选择不公开这个员工的信息以保护他,也没有对他采取任何处罚措施。

我想说的是,也许正是由于多年前的那个事故和公司的处理方法,才能让大家积极地去做一些事情,而不会太过于瞻前顾后。

其实,即使没有PCI DSS的要求,我们部门原本也打算再过两个月把DIS当做一个项目去做的。

流水账一样地记录一下工作7年以来的第一个P0事故,以后也能回忆回忆。
希望永远不会再遇到P0事故了。