过期日期 2021 年 4 月 6 日

2021 年 4 月 6 日,我们的一个通配符 TLS 证书在预期之外的情况下过期失效了。证书过期不是一件光彩的事情,但我们觉得向大家分享我们的故事尤为重要;我们希望其他人可以吸取我们的经验教训,以优化他们的系统。如果你或者你的机构在使用证书监测系统,那么也许可以以此为鉴,检查你们系统内的漏洞。

Epic 不少内部服务都使用在本事件中过期的证书——实际上,有过多的服务依赖此证书。虽然我们已尽可能地监视我们证书的过期时间,但我们并没完整地考虑到使用证书的每个区域。在证书过期和续期的时间段之内,发生了一系列预期之外的事件,进一步延长了宕机的时间。在这篇博文之内我们将阐述关于此事件的详情。

包括我们的身份和认证系统在内的核心组件因此被波及,而这些服务又影响了我们整个生态系统内的很多其他服务。以下是被观察到或上报的本事件造成的影响:

  • Epic 账户登陆使用该认证系统的全部产品均告失败,包括且不限于《堡垒之夜》、《Rocket League》、Houseparty、Epic Online Services 以及Epic游戏商城
  • 在线游玩或全部平台服务断线
  • 在 Epic Games 启动器中进行的购买行动失败
  • Epic Games 启动器出现预期之外的行为,包括内容无法加载以及离线模式无法工作等
  • 包括虚幻引擎在内的 Epic Games 相关产品以及销售网站无法连接,或浏览体验变差
  • 多个内部工具问题影响了 Epic 员工解决并处理问题的能力

本博文的目的是向你们阐述发生了什么、我们吸取到的经验教训,以及未来为了避免此类事件发生将要采取的步骤。


到底发生了什么事?


三个重大事件依次发生:

  1. 一个过期失效的证书导致大量内部后端服务间通讯以及内部管理工具宕机
  2. 预期之外的大量额外流量涌向 Epic Games 启动器,扰乱了 Epic Games 启动器的服务以及内容分发功能
  3. 一个包含无效工件与资源的错误版本Epic游戏商城网站因弹性伸缩操作而被部署使用,这影响了使用Epic游戏商城的体验

 

1) 证书失效

4 月 6 日 12:00PM UTC(世界标准时间),一个 TLS 证书过期失效了。该证书被用于 Epic 后端平台中的大量内网通讯。我们在跨服务 API 调用的后端服务和内部管理工具之间使用TLS加密。本证书适用的范围是一个非对外的内部 DNS 区域。 

12:00PM UTC,后端系统的流量因此事件实质上完全停止。六分钟后,于12:06PM UTC,该事件被上报,我们开始了处理流程。虽然我们有服务器警报,我们同时也一直鼓励公司中的任何员工汇报他们看到的任何可能会造成广泛影响的问题。我们的全天候 Live Ops(线上处理)团队 会对每个事件进行分流,并启动事件管理流程。当我们收到第一个内部报告时,我们的事件管理工具和流程就自动创建了一个 Slack 频道,相关的人员和团队随后被邀请或呼叫进入该频道。

于12:12PM UTC,我们确定了一个证书已过期,并相信这极大可能是问题的起因,并启动了证书续期流程。于12:37PM UTC,新的证书被重新发布,而该更新的证书也已实装至我们的后端服务。在接下来的 5 至 15 分钟内,负载系统自动将该更新证书部署到了各个内部端点,这让我们的服务间 HTTPS 调用以及我们的管理界面恢复了正常。

分流该事件的 Live Ops 团队仍旧在管理该事件,与员工们进行沟通,让正确的人参与此事。在12:38PM UTC,我们开启了一个 Zoom 聊天进程,来协调之前通过 Slack 合作的人员。Slack 固然是一款优秀的通讯工具,但在紧急情况下,实时的在线语音或视频效率最高。通过我们的内部工具和流程,我们向内部股东们持续发送关于本事件的更新,以使每个人都能了解最新情况。在这个时点,超过 25 人已直接参与并处理该问题,并有更多的人在持续关注;他们来自各个不同产品的玩家支持、社群、工程以及出品团队。

每分钟对单个微服务的请求次数图, 证书中断时有所下降,完全恢复时有所上升。

 

相关因素


和该内部服务通讯相关的 DNS 区域并未被我们的证书监视服务持续监视,这是我们的疏忽。我们的证书监控服务对整个DNS名称空间进行了密钥关闭,而不仅是对单个端点或证书进行密钥关闭,而且,对这个内部区域的配置缺失。我们现已将该区域移至更新的监视方案,消灭了这个漏洞。在此事件之前,我们也开始了一个项目,以于全球范围内在我们的多个账户上启用并配置 AWS Config(AWS 配置)。这样,我们便可简单地通过增加一个 AWS Config 规则 来启用与证书失效相关的深度防御警告。 

此内部证书的自动续期没有启用,而虽然我们已在年初了解了该问题的存在,解决本问题所需的工作并未被提上优先事项。虽然我们有进行自动续期的适当系统和服务,但在此事件之前,我们并未提前完成迁移到使用这些功能的流程。我们之前过度自信地以为,借助现有的监视系统,我们能保护自己免受证书过期的危险。我们将开始工作,将本证书以及其他证书迁移至自动续期系统。在此期间,我们已经完成了对所有证书的人工审核。

该服务间通配符证书被安装于数百个不同的生产服务中,因此该问题造成了巨大的影响。我们使用 AWS ACM(AWS 证书管理器)来管理该证书,这让我们可以快速续期该证书,并在数分钟内将更新的证书于数百个生产环境服务至上进行实装。但本过期事件与 AWS ACM 并无关系,问题出在我们的证书管理自身。我们将致力于分离我们证书的"爆炸半径",作为该流程的一部分,我们将更新 AWS ACM 的证书使用流程。

 

2) 与Epic Games 启动器服务相关的激增流量

虽说多数服务已于证书续期之后立刻恢复,我们的 Epic Games 启动器服务却仍旧处于实质的宕机状态。

12:46PM UTC,在重新发布证书之后,Epic Games 启动器服务,一个支持Epic Games 启动器客户端的关键后端服务,因激增的请求频率而不堪重负。请求频率激增是由于客户端意外的重试逻辑造成的,只见于出错情境。虽然这几年中我们已为Epic Games 启动器实装了很多弹性操作,在本事件中放大请求的案例却出乎我们的意料。追踪连接 我们的托管主机已到达极限,这导致整个机群的数据包都出现了丢包现象,即使我们的后端应用机群扩展了250%,恢复也变得更加困难。Epic Games 启动器服务因此出现了层叠失败以及完全宕机,为从该问题中恢复,我们需要于后端限制流量,并在逐渐提升我们的连接跟踪上限的同时逐步放开系统的流量限制。

Epic Games 启动器客户端的巨大足迹导致了对后端Epic Games 启动器服务的数千万计的连接,Epic Games 启动器相关组件系统因负载出现降级。我们需要将流量分流到后端,才能解决此问题。虽然在通常情况下,我们为这项服务提供了突发能力,但其并不能负担宕机事件开始时我们观测到的 28 倍流量负载。

显示 Epic Games 启动器后端负载平衡服务收到的每分钟请求数的图表。流量在事件初期上升了 28 倍,并于 15:12 UTC 上升到了通常流量的 40 倍。


虽然我们的请求数量是一般情况下的 28 倍以上,大量的通往 Epic Games 启动器后端服务请求将可用的 连接跟踪 空间消耗殆尽,导致丢包现象,且最终导致后端节点的连接性降低。我们的后台连接负载相比我们的一般负载上升了 3200 倍。而 TCP 连接的增加量远高于请求数量。

显示 Epic Games 启动器后端负载平衡服务 收到的新的每分钟请求数图表。相比普通峰值,连接数量上升了 3200 倍。

 

相关因素


过期的 TLS 证书导致的宕机触发了启动器客户端中预料之外的行为。我们的调查显示客户端中的重试行为使用了线性逻辑,而非我们预期中的指数后退。一个额外的预期外错误还导致了数百万的 Epic Games 启动器客户端持续不断地在收到成功反馈之前进行重试动作。在我们的已安装设备客户群中,这两个错误造成了意外的和不可预见的的调用模式。换言之,我们受到了来自于我们客户端的拒绝服务(DDoS)攻击,为此我们需要在对 Epic Games 启动器进行更新时紧急解决这些错误。 

造成事件这一部分的一个值得注意的因素是最初宕机的时长。宕机的时间越长,更多的客户端就更可能使用有缺陷的重试逻辑持续调用我们的后端架构。如果初始的宕机时间较为短暂,我们便不会累积如此之多的持续重试调用,使系统超载;这次的过长宕机时间让这个问题得以显现。我们将通过改变调用规律来解决此问题。

此外,我们对连接跟踪的警报的认知程度也不足。该警报在Epic Games 启动器服务出现问题时被触发,虽然几个团队都熟悉该警报的意义,警报本身的描述和通知却不够清楚,所以我们当时并不知道该状况会导致主机的任何连接丢包,包括与内部 Redis 集群的连接。因 Redis 集群的连接性降低,这对调查该问题的团队造成了不小的压力。一开始,我们以为缓存系统是部分原因。后来,原因被证明是连接跟踪表因成千上万的连接而爆满,从而导致了丢包问题。在事件后期,我们将连接跟踪上限调整到了每节点 一百万个,但架构中连接跟踪的提升并非瞬时,需要一些时间。我们将持续优化警报系统,让其在遇到大规模的网络问题时,于解决问题之前提供足够清楚的信息。 

增大规模导致了新的节点立刻达到了连接跟踪上限。由于我们的机群连接量过大并出现了丢包问题,我们需要先降低机群的总体流量,并缓慢提升允许的流量。我们首先尝试使用 AWS WAF(网页应用防火墙)来限制网段中的入口流量,但我们的配置无法限制足够的流量。这并不是 AWS WAF 的问题,问题出在我们特定的规则当中。为了节省时间,我们之后使用了 AWS 负载平衡目标权重手段来对流量进行移动,该方案和提升连接跟踪上限相配合,最终成功解决了问题。在此情境下,使用 WAF 延迟了 Epic Games 启动器服务的修复,但这并不是 AWS 的问题。我们将开发一个标准流程,以在这样的关键情况下,使用 AWS WAF、负载平衡器目标权重或其他 AWS 技术来紧急减载流量。

 

3) Epic游戏商城网站中的无效资源

3:12PM UTC,我们在续期了证书并恢复了 Epic Games 启动器服务之后,开始解除客户端请求Epic游戏商城的限制。而因为宕机时间过长,从Epic游戏商城请求内容的客户端数量明显多于正常情况,连接规模也因此扩大。在 3:30PM UTC 左右,我们开始评估余下的影响。

起初,一切看起来都很正常,但很快我们便开始收到关于商城中排版以及页面错误的内部报告,且我们可以验证并还原这些问题。在详细调查之后,我们注意到网页客户端(也就是用户浏览 epicgames.com 与商城互动的方式)正在尝试获取一个并不存在于我们的 CDN 之中的特殊资源ID(asset ID)。我们检查了跨机群部署的容器版本,这些容器版本均一致,但如果是这样的话,为何这些版本一致的应用会返回不同的静态资源值呢? 

这不太对劲。这是本事件中令人迷惑不解的一个部分,而最终我们的很多信号线索(例如部署的版本)被证明是错误信号。我们能够将Epic游戏商城后端连接规模扩张和来自 CDN 的 403 错误关联起来,这让我们开启了通过这些新的副本来进行详细调查的全新途径。通过在新副本中进行本地传输,我们发现返回的是无效内容。我们能够将该问题追溯到一个意外的容器推送到新的 CI/CD 工作流之上,该推送于前一日完成,并与我们从该事件开始时遇到的全部问题完全无关。这些结果令人惊讶,但在发现问题起因之后,我们便可快速滚回容器版本,将无效的副本终结,并解除流量封锁。

这个问题本可能会于这段时间内任意一次连接规模扩大时出现;但由于我们一般在机群中预留了充分的空间,该问题直到因为 Epic Games 启动器的流量导致Epic游戏商城的连接大规模扩大才出现。

 

相关因素


由过期证书导致的宕机问题造成了 Epic Games 启动器的问题,而启动器恢复后,导致了向Epic游戏商城发送的大量请求,而这又造成了Epic游戏商城系统的规模扩大。我们十分开心能够得出以上结论,且这些结论均在我们的预期之内。

从我们的应用机群收到的信号与数据让我们错误地认为我们的机群部署是统一的。为此,我们更改了版本命名格式,以在将来防止此类错误诊断行为。

Epic游戏商城 CI/CD 工作流的一个近期改动中包含了一个无效的配置,导致应用文件集合被意外地更新了。我们通过修改了 CI/CD 工作流,将该意料外的修改回滚而修正了此问题。而之后如果类似的情况再度出现,我们对版本命名的修改也会保护我们免遭影响。


时间线

  • 12:00PM UTC - 内部证书过期失效
  • 12:06PM UTC - 事件被上报,开始事件管理流程
  • 12:15PM UTC - 对客户的第一批信息已准备完成
  • 12:21PM UTC - 多个团队确认多个大规模服务断线
  • 12:25PM UTC - 证书重新发布流程已开始
  • 12:37PM UTC - 确认证书已重新发布
  • 12:46PM UTC - 确认部分服务恢复
  • 12:54PM UTC - 发现 Epic Games 启动器服务有连接跟踪的问题
  • 1:41PM UTC - 重启了 Epic Games 启动器服务节点
  • 3:05PM UTC - 提升了 Epic Games 启动器服务的连接跟踪上限
  • 3:12PM UTC - Epic Games 启动器服务开始恢复
  • 3:34PM UTC - Epic游戏商城网页服务规模扩大
  • 3:59PM UTC - 收到第一批有关Epic游戏商城资源丢失的汇报
  • 4:57PM UTC - 发现Epic游戏商城网页服务版本不匹配
  • 5:22PM UTC - 修正了Epic游戏商城网页服务的版本问题
  • 5:35PM UTC - 服务全面恢复


下一步是什么?

在上面的部分中,我们介绍了导致 4 月 6 日出现意外问题并最终造成宕机的情境。我们在相关因素部分提到了我们要进行的下一步操作,但我们也将在此进行重申。 

这些问题的发生并不是由单一原因而起。各种各样或与技术或管理有关的因素促成了所发生的各种事件。而该宕机事件的规模和长度不仅帮助我们发现了系统中的明显错误——这些我们将会修正——而且还发现了我们的一些内部流程,尤其是证书管理流程中以前未被质疑的想当然假设。 

虽然我们立即行动起来,用较新的证书监控系统解决了这个盲点,并审核所有现有的已知证书;但我们还会更深入地研究我们的证书监控中的任何额外的漏洞,并为未来增加额外的保障,例如为所有基于 AWS ACM 的证书添加 AWS Config 监控。我们还将努力减少任何特定证书的"爆炸半径"。

我们也会进一步关注 Epic Games 启动器客户端的调用规律,并紧急修复由该原因导致的一些错误;同时,我们也会提升面对流量激增加情形的反应能力。由于我们在机群中永久性扩张了连接跟踪表,之后我们应该可以应对类似流量负载而不出现丢包。如果你也维护大规模的机群,并使用数据包过滤机制进行流量过滤,我们提醒你不妨检查一下连接跟踪表上限以及报警系统。同样,我们也很乐意提醒你检查一下你的客户端中的重试逻辑,尤其是在经过长时间的宕机以后该重试逻辑会怎样表现。

对于Epic游戏商城来说,我们已部署了一个修复,其应该可阻止已上线的应用对象被修改,并且作为我们学到的教训的一部分,该修复也同时处理了资源生成方面的一个程序错误。

我们希望该事故报告为你提供了关于 4 月 6 日发生的事件的额外详情。我们也希望这些详细信息能给我们的学习和改进带来启示,并帮助其他人避免类似的问题。


加入我们!

本博文由我们的可靠性工程团队撰写,并得到了 Epic 公司中其他诸多优秀工程团队的帮助。

你对这些类型的问题感兴趣吗?你对游戏以及游戏服务抱有热情吗?Epic 一直在寻找优秀的才能,我们正在全球范围内招聘各种技能的人才。如果你正在寻找我们的空缺职位,请访问 Epic Games 职业门户

本博文是否对你有帮助,或让你觉得足够有趣?请通过向 [email protected] 发送邮件,来让我们了解你的看法。