HashiCorp Vault 成功案例:Comcast Xfinity Mobile 用 Vault 和 Spring Cloud Config 擴展安全性

Vault 成功案例:Elvia 有效整合智能電錶
2022-02-11
HashiCorp Vault 成功案例:UBISOFT 利用 Vault 打造安全的遊戲天堂
2022-02-14

隨著 Xfinity Mobile 將他們的應用程式從單體式平台 (monolith platform) 擴展到在跨五區運行的 80 多個微服務雲原生平台之後,他們便意識到不僅需擴展架構,還要擴展他們的流程和執行層面。

主要轉型重點之一是將組態和機密作為 12 – Factor 的一部分,並進行外部化。此文章將介紹如何將 HashiCorp Vault 與 Spring Boot 和 Spring Cloud Config 一起使用,也歡迎觀看 Xfinity 的影片分享

 

朝向微服務發展

事情發生在 12 到 15 年前左右。我們的第一個應用程式在運行時大概是這樣:它有個 UI,還有一堆應用程式程式碼 —— 我想主要是在兩塊 silvers 上,也有負載平衡器 (load balancer) 和帶有幾個防火牆的資料庫伺服器。一切都還滿簡單的。

但後來我們意識到資料的重要性,因此開始檢討,「我們需要把這些邏輯分隔出來,不希望我們的 UI 邏輯出現在服務當中。我們希望將這個資料庫隔離開來,以增加安全性。」然後事情開始改變。

然後我們也開始留意網域 (domain)。有些上司會要求説,「我的網域需要這些特殊的東西,我對它有特殊要求。」事情也就變得更加支離破碎。我們仍然在做同樣的 MVC。這時 Spring 開始出現了 —— 人們有更多的工具來啟用這種架構。

然後是 Agile。大多數人已經知道或體驗過這些東西。儘管我們正在精進 Agile 的部分,但現在客戶都要求快速,希望事情在指定時間內完成,我們希望從這些服務中獲得可預測的結果。

我們開始將這些東西分解,轉移到功能團隊。這就是我們業內很多人所說的單體模組 (modular monolith)。您仍在容器中部署此應用程式、您仍然擁有這個被部署的單體應用程式,它在部署和發布新功能方面更快速。但可惜的是,它缺乏擴展性。

就在不久前,當時每個人都說,「我們需要擴展性。」Terraforms Consuls 的出現便開始有了轉變,讓應用程式團隊能建立這樣的架構。

這都是圍繞在擴展的部分。它封裝了資料,且有不同版本。這對一個從事單體應用的架構師來說,可說是個夢想,因為當時的應用程式很不方便。您需要完全可預測您發布的內容;這裡提供了可預測性。您可以運行一個版本的 API,也可以運行一個完全不同版本的 API。你可以把東西移入跟移出,效果真的不錯。

很快,我們就無法將我們的硬體基礎架構和微服務一起擴展。我們說過,cloud 就是答案,確實如此。這對於現在公司的營運非常重要。我們必須問自己的問題是,「這種複雜性是故意的嗎?是我們想要的嗎?這是一個很大的計劃,還是我們偶然發現了這個設計跟這個架構?」

是的,這是故意的。這裡的論點是,只要您能夠管理這些複雜性就會方便很多了。

 

複雜度管理

我的團隊開始研究這個。在處理微服務時,它被稱為 12-Factor 原則。很多討論都是關於「你如何處理你的基準代碼 (codebase)?如何處理依賴性問題?從擴展性的角度來看,你對服務做了些什麼?你如何處理日誌和所有內容?」

第一點和第三點對我們來說很重要,是關於您的基準代碼。假設您希望擁有一個可以在多個環境中運行的單一基準代碼。隨之而來的是一組單一的組態,你想管理你的組態,想把它存儲在代碼之外的環境中,你想把它和你的代碼一起移動 —— 這樣就可以預測所要發布的東西。

 

作為代碼的配置

在配置方面,我們有很多管理的衝突。我們是一家 Spring Boot 微服務商。Spring 有一個很好的儲存庫,叫做 Spring Cloud Config。它使您可以將配置(或組態)作為代碼進行管理。在本質上,您將所有代碼移動到 Git 資源庫中,當您遷移應用程式代碼時,您也能將配置版本化。您可以把它們放在一起管理,也能一起遷移。

作為配置的一部分,自然會發生的一件事是,您最終會在配置中有很多機密 —— 您的資料庫密碼、您的 API 密鑰、您的服務憑證等。

因此人們開始討論,「我們要如何處理現在所處的情況?」 有人說,「你為什麼不加密呢?」是的,我們可以加密它,但加密永遠不能解決問題,因為你總是會遇到所謂的 “Chicken-Egg Problem”。

 

整合 Vault 和 Spring

那麼,我將把我的密鑰放在哪裡呢? key zero 在哪裡? 我該如何處理它以及如何確保它是安全的 —— 且它會隨我的代碼在環境中遷移而移動。我們需要一個工具來幫助我們 —— 便偶然發現了 HashiCorp Vault

 

Vault Spring 與 Cloud Config

它的運作是這樣的,我們有微服務、我們有 Cloud Config Server,我們會將我們的配​​置遷移到 Git 中,並將我們所有的機密移到 Vault 中。Config Server 將輕鬆登入進 Vault 裡面。

Spring Cloud 還提供了一個 Spring Config Server。在我們開始整合 Vault 之前,我們只有 Git 作為我們所有配置的來源,這對各位來說很簡單。隨著 Spring 與 Vault 越來越緊密的整合,我只需要在這裡提供這個 block。我需要為主機的 port 提供密鑰,然後有趣的是我可以給出這個指令 —— 這是一個優先事項。我可以說,「如果 Vault 和 GitHub 中有可用的配置,請優先考慮 Vault」,然後啟動,我的 Config Server 便成功啟動了!讓我們看看啟動會是什麼樣子。

 

在架構中解決 Vault 依賴性問題

現在來探討如何讓我的服務也連接到這個 config server。我發現一旦 config server 被裝在 Vault 中,我就必須啟動我的服務。所有與 config server 對話的客戶端現在也需要知道 Vault。我現在不得不把這些 Vault tokens 作為啟動微服務的一部分。

這就是我們開始覺得有點不便的地方。對 Vault 的依賴正在滲透到我架構的其他部分。不僅 config server 需要知道,而且我們所有的微服務都需要知道這一點。以下將會簡單講解一下該問題。

該服務在 port 8082 上執行,若我要調用它,我有我的服務。這背後的代碼又是怎麼樣的 ?  Spring 本質上是非常約定俗成。若您依照慣例 —— 用配置為這個類別加上註解 —— 我必須加上 prefix。 如果各位還記得我 demo 時的另一個視窗 —— 它的 prefix 是 HashiConf,再來是我的用戶名及密碼。

一旦我這樣做,配置會根據我的偏好自動顯示出來 —— 無論它們來自 Git 還是 Vault,我的配置一樣都會進來。這部分很棒,但其他部分就沒這麼好了。

 

評估該方法 —— 第 1 部分

各位覺得以上方法的優點是什麼?我喜歡的點在於,這對我現有的代碼和配置來說改變是最少的,我不必做太多事情,我所要做的就是配置 Vault 並將所有機密移到那裡。然後我對每個微服務的推出都有所掌握。

但我們不認為這是一件好事。我無法做 atomic comment 並將所有這些東西移在一起,所以這是我們覺得不便的地方。我們還發現這個資源庫不支援所有的身份驗證機制。我們想使用 AppRole,但它沒有對這些提供原生支援。我們不得不將所有東西都轉移到部署架構中,所以這不是最理想的解決方案。

 

試試另一種方式

「我們如何做到這一點?」是我們想問自己的問題嗎?我們說,「讓我們這樣做吧。我們在 Vault 中的機密——如果我們回到我們所說的,對它們進行加密,並放在 GitHub 中會怎樣?」

現在我的 config server 不需要知道 Vault。我想,「我的架構中又少了一個需要擔心的耦合。」那我需要做什麼?我想,「無論如何我都必須登入 Vault。如果我只使用主密鑰怎麼辦?我不會儲存所有配置,是只儲存密鑰。」這解決了我的問題,「我該如何處理密鑰?」

這是一個可供我放置密鑰的安全之處。我得到了關於它的所有稽核;我得到了 Vault 為我提供的所有權限 —— 所有的好處都在這裡。所以我想,「這似乎是一個好方法。」我們把對 Spring Cloud Config 的依賴轉移到另一個名為 Spring Vault Core 的資源庫。

 

使用 Spring Vault Template

如果您使用過任何 Spring Frameworks 或 Spring Libraries,它其實是一種非常類似的方法。和 RestTemplate 和 JdbcTemplate 一樣,它提供了 VaultTemplate。讓從 Vault 中讀取、寫入、修改、刪除 API 或密鑰變得非常簡單。它管理您的所有的 tokens。建立身份驗證模板後,您不必管理 token 或 token 的生命週期。然後它還支援 Vault 中的所有身份驗證機制 —— 實在非常強大。

為了初始化模板,您必須提供端點及客戶身份驗證。端點非常簡單。您可以根據 URI 或路徑建立它。而客戶身份驗證稍微複雜一些,但只需 10 行甚至更少的程式碼。您只需弄清楚您的身份驗證是什麼就可以了。我們使用的是 AppRole,您只需將初始 token 和身份驗證路徑傳遞給 Vault。

只需幾行程式碼,我們就能夠與 Vault 整合,獲得主密鑰,並將其放入我們的基準代碼中。一旦初始化了 VaultTemplate,您就可以用它來讀取任何路徑。

我們來看看它的樣子。回到一個類似的方法 —— 我只儲存主密鑰,而不是儲存用戶密碼。如果您看到這裡的路徑,我仍然按照微服務儲存它,但我也說過想讓它具有特定的環境。我們希望針對每個環境有特定的主密鑰,不想在所有環境中用相同密鑰。而這滿足我的需求。

在後端,這仍要經過所有存取控制列表 (ACL),即您在 Vault 中設定的所有規則,以及誰擁有權限等。在我們的例子中,我們使用 GitHub 作為基本身份驗證,因此 GitHub 中的群組擁有 Vault 中某些路徑得權限。在外部,Vault 團隊正在為我們處理這些事情。但這給了我一個非常簡單的 API 來訪問 Vault 並提取我想要的內容。

一起來看看我的 config server 現在的情況。從技術上來說,它應該是 Git,但因為我需要同時運行兩個 MO,所以我指向內部文件系統進行配置。但這應該是 Git。如圖所示,我的 config server 現在只指向 Git 以獲取所有配置。

 

 

專為開發者打造的服務

我們發現,作為微服務啟動的一部分,我需要提供易於開發人員使用的資源庫。身為開發者 —— 如果我正在與新的 API 或與新服務進行整合,我有服務憑證 —— 我想儲存它們,並確保它與我的程式碼一起存在於我的環境中。我將利用這些憑證,並調用此端點,這是一個加密端點,然後我會給它我需要加密的密鑰跟環境。

但我還沒有完成,我雖已經完成了加密,但我仍然需要一種在運行時能夠解密它的方法。那會是怎樣的呢?如果你們看到了我之前給你們看的類似程式碼 —— 我將用我們建立的庫替換它。它叫做 KeyUtil。

我們先重啟一下這個服務,看看啟動前是否生效。該服務現在使用 config server 作為後端,它將轉到 Git;它會去採用那個配置。它在他們的 VLT 中看到這些 prefixes,因此它知道這是一個密鑰 —— 且必須與 Vault 對話。它已經初始化了 Vault;去獲取主密鑰並對其進行解密。讓我們回頭來談談這樣做的結果如何。

我們給了開發人員一個啟動器 —— 就像在 Spring 中一樣,對啟動器有依賴性。我們給他們一個「vault 啟動器」。他們只需考量那個啟動器的依賴性,所有東西都會自動連接進來。

它連接到我們給他的端點。它消除了所有依賴,「你如何獲得主密鑰,如何處理它?」他們不必擔心如何獲取它或如何恢復它。我們給他一個 Java API 來為他們解密這些東西。我在我的程式碼中使用它。只是一個自動連接的 util 庫。他們不必擔心自動連接是如何發生的,便可以自動連線。

我們給他們一個 REST API 來加密這些東西。所有事情都是在他們不知道密鑰在哪或密鑰從哪裡來的情況下完成的。

 

評估該方法 —— 第 2 部分

以上方法的好處是什麼?若您與之前的解決方案相比,我的機密和配置都在 GitHub 中的一個地方,並且在 GitHub 中有妥善的保護。我可以做一個 atmotic comment,我也可以在不同環境中測試它。我可以利用我的 pipeline 一直驗證它,而且我知道當推送一個程式碼的版本時,其他相應版本的配置也會被移入。我不必與 Vault 團隊協調,確保他們也推送相同配置或使其上線。

我獲得了 12 factors 的其中一個 —— 我可以一起移動程式碼和配置。對 Vault 的依賴性轉移到每個環境只有一個 key-value  —— 我們忽略了這些東西,但這很重要。我已經確定,當我的應用程式正在擴展時、當我有突發的流量或者有一些事情發生時,儘管我收到大量的請求,也不會讓 Vault 平台超載。我這邊的問題不會影響到 Vault 團隊。

其次,如果我要擴大規模,我會添加一套全新的服務。當我在為活動做準備時,我不需要讓 Vault 團隊中相關的同仁也為該活動做準備。這對他們來說是無關緊要的。對我來說,一個事件不應該滲透到我們這邊的架構中。這讓我們兩者間的工作內容有適當的區分。

 

一些預想不到的好處

我們發現我們對 Vault 的依賴現在轉移到了 bootstrap。我的資源庫在啟動時能獲取密鑰。在我的服務啟動並運行之後 —— 若基於某種原因我與 Vault 的連接中斷,或者存在網路分裂 (network partition) 或防火牆等問題,而我無法連到 Vault —— 我並不受影響。我的服務將啟動並運行。我唯一擔心的是服務是否正在擴展或新服務是否正在啟動。

正如之前提到的,我解耦了我的應用程式,因此他們不必知道我的擴展,且所有密鑰都是完全安全的。開發人員可以使用它,但他們不需要知道它的來源或詳細資訊。

 

總結

若各位是 Spring 商,或者有正在使用 Spring 的開發團隊,那麼 Spring 提供了一些很好的資源庫。有三個主要的生產級資源庫,背後有一個很棒的開源社群和一些優秀的參與者。如果您想直接與 Vault 進行低端、高級的整合 —— 這也是我們最終使用的;如果各位不是微服務應用程式提供商,但仍然在雲端部署,則可以將 Spring Vault 當作資源庫。