到期日 2021 年4 月 6 日
於 2021 年 4 月 6 日時,我們的通用 TLS 憑證出乎意料地過期了。憑證過期造成的事故使我們非常錯愕,但我們認為在此分享我們的故事十分重要,也希望其他人能從我們的經驗中汲取教訓,改善其系統。如果您或您的組織正使用憑證監控,這份報告或許是良好的機會,提醒您記得確認系統間的間隔。
過期的憑證廣泛使用在 Epic 的對內服務——事實上,似乎太過廣泛應用了。雖然我們盡全力監控憑證過期的狀況,我們未能完整顧及憑證所應用的每個區塊。在憑證過期並更新後,發生了一系列預期之外的事故,最後演變為服務中斷。在這篇文章中,我們將提供關於上述事故的細節。
受到影響的包含某些核心元件(例如我們的身份辨識和授權系統),還有其他觸及我們整個生態系的服務。目前所知已經收到回報的影響如下:
- Epic 帳號無法登入任何使用此類授權的產品,包括《堡壘之夜》、《Rocket League》、Houseparty、Epic Online Services 或 Epic Games Store
- 所有平台的線上遊戲和服務連線中斷
- Epic Games 啟動器購買項目失敗
- 其他非預期的 Epic Games 啟動器問題,從無法讀取內容到離線模式無法運作
- 無法使用 Epic Games 產品和行銷網站,或功能降級——包括 Unreal Engine 網站
- 許多內部工具問題,影響 Epic 員工解決和管理問題的能力
這則貼文是為了使您能更新入了解發生了什麼事、我們從中學習的教訓,以及我們在未來所採取的步驟。
究竟發生了什麼事?
此次意外中發生了三個主要事故:
- 憑證過期導致大部份內部的後台服務間通訊以及內部管理工具中止運作
- Epic Games 啟動器有預期之外的極大流量,造成 Epic Games 啟動器和內容傳遞功能中止服務
- 錯誤版本的 Epic Games Store 網站使用了無效的構件和斷言,而這個版本被用在自動擴展的程序中,從而損害了 Epic Games Store 的使用體驗
1) 憑證到期

UTC 時間 4 月 6 日 午間 12 點時,TLS 憑證到期。此憑證用於大量 Epic 後台平台的內部通訊。我們在跨服務 API 通訊的後台服務以及內部管理工具之間使用 TLS 加密。此憑證用於非公開的內部 DNS 區域。
UTC 時間午間 12 點,後台系統間的流量迅速中斷。六分鐘後,也就是在 UTC 時間午間 12 點 6 分,我們收到事故回報,啟動事故處理程序。雖然我們有完備的警報,然而我們依然鼓勵公司內的所有人回報任何他們所看到會引起大規模影響的問題。每起事故都會由我們全年無休的 Live Ops 團隊鑑鑒別,由他們啟動事故管理程序。當收到第一起內部回報時,我們的事故管理工具和程序自動建立了 Slack 頻道,相關方也受邀處理或收到通知。
UTC 時間午間 12 點 12 分,我們確認憑證過期,並認為很有可能就是問題源頭,立即著手更新程序。UTC 時間午間 12 點 37 分,憑證重新授權,更新的憑證開始推動後台服務。在接下來的 5 至 15 分鐘期間,負載平衡器開始自動在內部端點部署新憑證,我們的服務間 HTTPS 通訊及管理介面隨之復原。
處理此次事故的 Live Ops 團隊也在這個階段著手管理事故——與員工聯絡、找到合適的人員投入搶修——,並在 UTC 時間午間 12 點 38 分以 Zoom 通話加速與 Slack 協作人員的協調。Slack 是優秀的通訊工具,但是在危急情境下,沒有什麼比得上以聲音或影像進行的即時通訊。我們的工具和程序定期向內部的關係人發送最新訊息,以確保每個人都對發生的事故有最新了解。此時,已經有超過 25 人直接投入處理這個問題,同時從玩家支援、社群、工程,到製作等等,我們在眾多產品和團隊之中也都有人在觀察問題的發展。

我們有一份請求圖表每分鐘計算單一微服務的請求次數,其中顯示憑證中斷時次數明顯減少,而完全復原時則有所提升。
促成因素
我們的憑證監控服務未能主動監控用於內部服務間通訊的 DNS 區域,這是我們的疏失。憑證監控服務關閉了整個 DNS 命名空間,而非個別端點或憑證,此外,此內部空間的設定也遺失了。這次事故後,我們將此區域轉移至新的監控方案,該方案能處理這個落差。在此次事故之前,我們也開始一項在全球啟用並配置 AWS Config 的計劃,範圍涵蓋許多帳號。由於此項全球性的措施,我們能輕鬆地新增 AWS Config 規則,啟用憑證過期的深度防護警報。
此內部憑證未使用自動更新,而在今年初發現這件事時,並未優先處理使用自動更新所需要的程序。我們有適當的系統及服務正在運作中,能加速自動更新,但轉換為使用這些功能的程序在此次事故時尚未完成。有了現在的監控系統,我們相信我們比先前更受到保護,能免於憑證過期的危險。我們會著手為這項憑證與其他憑證改採自動更新。在此過渡期間,我們為所有憑證完成了手動審核。
我們所使用的服務間通用憑證安裝在成千上萬不同的生產服務中,也因此影響範圍十分廣泛。我們使用 AWS ACM(AWS 憑證管理員)管理此憑證,使我們可以在幾分鐘內快速地更新此憑證,並將其套用至數以百計的生產環境服務。過期問題並非出於 AWS ACM 本身,而是出於我們對憑證的管理。我們將著手分離憑證的影響範圍,其中包括更新我們以 AWS ACM 使用憑證的程序。
2) Epic Games 啟動器流量大幅增加
大部份服務在更新憑證後已立即恢復,但 Epic Games 啟動器在一段時候內仍然無法使用。
在憑證於 UTC 時間午間 12 點 46 分發行後,請求量一時間激增,超出 Epic Games 啟動器服務的負荷能力,這是支援 Epic Games 啟動器用戶端的重要後台服務。請求量激增的原因,是因為用戶端出現未預期的重試邏輯,而這只會在故障情況下出現。近年,我們著手強化 Epic Games 啟動器的恢復力,但這次的請求量激增超出我們的意料之外。追蹤連線 我們的主機負荷達到上限,因此伺服器機群發生封包遺失狀況,即使在後台應用機隊擴增到 250% 的情況下,仍然在恢復方面面對困難的挑戰。Epic Games 啟動器遭遇層疊式故障和中斷,在恢復過程中,我們需要限制後台的流量,然後逐步增加系統流量,同時提升我們的連線追蹤上限。
龐大的 Epic Games 啟動器用戶端數量,對 Epic Games 啟動器後台服務造成數以千萬計的連線數,使 Epic Games 啟動器系統的構成要素之效能因為負荷而下降。我們必須減少後台的流量,使它們能夠恢復。一般來說,該服務設有高載容量,但並不足以應對我們在中斷初期遭遇的 28 倍負載量。

我們有一份圖表顯示 Epic Games 啟動器後台負載平衡器每分鐘收到的請求數。初期流量為平常的 28 倍,最高曾在 UTC 時間下午 3 點 12 分爆增為平時的 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 Games Store 網站的無效資產
在 UTC 時間下午 3 點 12 分,我們的憑證已更新,並恢復 Epic Games 啟動器服務,於是開始將呼叫 Epic Games Store 的客戶端解除封鎖。由於中斷時間較長,因此請求 Epic Games Store 內容的用戶端數量顯著高於平時,負載也出現相應的增加。我們在 UTC 時間下午 3 點 30 分開始評估後續影響。
起初,一切看起來都很正常,但我們開始收到內部報告,指出 Store 發生排版問題和錯誤,並成功確認及再現這些內容。在調查細節之後,我們馬上注意到網頁客戶端(瀏覽 epicgames.com 的使用者與 Store 互動的方式)試著取得不在我們 CDN 上的獨特資產 ID。我們確認了在伺服器機群使用的容器版本,這些版本都一樣,但如果是這樣的話,為什麼同樣的應用程式版本會回傳不同的靜態資產值?
一定有什麼問題。這是這次事故中非常令人困惑的一段時間,而且最終發現有許多我們所取得的訊號(例如所部署的版本)是錯誤的訊號。我們當時發現了 Epic Games Store 後台的擴展與 CDN 上 403 錯誤的增加之間有所關聯,這為我們指出了詳細調查新實例的途徑。當我們在本機傳輸新實例的內容時,我們發現所傳回的內容是無效的。我們循線追溯到某個預期之外的容器,連結到一個 CI/CD 工作流。這是個前一天的工作流,與我們在這次事故中所遭遇的一切都完全沒有任何關聯。這些結果是很令人意外,但是在詳細的研究過後,我們還是迅速地復原了容器的版本、中止無效的實例,並復原流量。
在任何大型的擴展中,本來應該都要能避免這個問題發生,但因為我們通常會為在伺服器機群保留大量的預留空間,因此這個問題一直到 Epic Games 啟動器的流量使 Epic Games Store 發生大型擴展時才爆發。
促成因素
憑證中斷導致 Epic Games 啟動器發生問題,而復原的過程中在 Epic Games Store 生成了大量的請求,使 Epic Games Store 的系統發生擴展。這是個在預期之中且受到樂見的狀況。
我們遭到應用機群所呈現的訊號與版本狀態誤導,以為我們的機群部署是統一一致的。我們變更了版本部署架構,以便在未來預防錯誤診斷。
Epic Games Store 最近的某一項 CI/CD 流程變更包含設定錯誤,以預期之外的方式更新了應用程式產出。我們已經對 CI/CD 流程做出更正,復原了錯誤的變更。我們的版本部署架構變更將會使我們在類似狀況再度發生時獲得防護。
時間線
- UTC 時間午間 12 點 00 分:內部憑證過期
- UTC 時間午間 12 點 06 分:回報事故並啟動事故管理程序
- UTC 時間午間 12 點 15 分:準備好第一位顧客的訊息傳送
- UTC 時間午間 12 點 21 分:多個團隊確認許多大規模服務錯誤
- UTC 時間午間 12 點 25 分:確認重新核發憑證的程序已經啟動
- UTC 時間午間 12 點 37 分:確認憑證已重新核發
- UTC 時間午間 12 點 46 分:恢復部份服務
- UTC 時間午間 12 點 54 分:發現 Epic Games 啟動器服務有追蹤連線問題
- UTC 時間下午 1 點 41 分:重新啟動 Epic Games 啟動器服務節點
- UTC 時間下午 3 點 05 分:為 Epic Games 啟動器服務提升追蹤連線限制
- UTC 時間下午 3 點 12 分:Epic Games 啟動器服務恢復的第一個訊號出現
- UTC 時間下午 3 點 34 分:Epic Games Store 網頁服務擴展
- UTC 時間下午 3 點 59 分:第一批 Epic Games Store 資產遺失報告
- UTC 時間下午 4 點 57 分:發現 Epic Games Store 網站服務版本不符的錯誤
- UTC 時間下午 5 點 22 分:Epic Games Store 網站服務版本更正完畢
- UTC 時間下午 5 點 35 分:完全恢復
接下呢?
在上述內容中,我們說明了在 4 月 6 日時導致一連串意外,並最終迫使服務中斷的狀況。我們提及了問題成因以及我們採取的行動,但是我們還是要在此摘要。
這些問題的產生沒有單一的根源。在技術層面和組織層面都有大量因素導致這次事故開展。中斷的規模和時間長度都幫助我們發現,不只是我們的系統中有明確的問題(我們將著手修正),我們的內部程序中某些以前未曾遭受質疑的預設亦然,特別是在監管憑證管理的部份。
我們馬上以新的憑證監控系統涵蓋這個區域,並且審核所有現存已知的憑證,於此同時,我們也要更深入檢查在憑證監控系統中的任何其他間隔,並為未來建立防護,像是為所有以 ACM 為基礎的 AWS 憑證新增 AWS Config 監控系統。我們也著手縮減所有特定憑證會影響到的範圍。
我們會更仔細檢視 Epic Games 啟動器客戶端的通訊模式,並且馬上修正某些我們在這部份找到的錯誤,同時也提升我們的能力,以回應流量顯著增加的情況。在永久地為此在伺服器機群提升連線追蹤表格後,我們應該能處理相似負載量,而且不會有任何封包遺失。如果您也使用大規模的機群,那麼這對您也許是個提醒,請記得確認您的連線追蹤表格限制,而若您也使用這項 Netfilter 功能,則這也是個警訊。此外,我們很樂意擔任提醒的角色,請您記得確認客戶端的重新嘗試邏輯,特別是在長時間中斷後它們會如何集體反應。
以 Epic Games Store 來說,我們部署了修正,這項修正應該能避免更動即時的應用程式物件,而我們也從中學習到如何修正在生成資產時出現的錯誤。
我們希望這份事故報告能為您提供額外的細節,使您能知道在 4 月 6 日所發生的事情。我們也希望這些細節能呈現我們所學到的教訓和改善方法,並且幫助其他人免於類似的問題。
請加入我們!
這份貼文是由我們的可靠性工程 (Reliability Engineering) 團隊撰寫,並且有 Epic 的其他工程團隊提供大量的幫助。
您對此類問題感興趣嗎?對遊戲以及遊戲服務充滿熱情嗎?Epic 永遠期待具有天賦和能力的人加入我們。我們在全球僱用具備各種類型完整技能的人。如果您在尋找我們目前開放的職缺,請造訪Epic Games Career 中心。
這份貼文對您是否有幫助?或您是否覺得這份貼文有趣?請到 public-incident-response@epicgames.com 讓我們知道。