
微博熱搜API的免費調用教程
在這篇文章中,我們想從技術角度向你概述 Spacelift Azure 集成的工作原理,并討論我們在設計和開發它時遇到和解決的一些問題。
作為一個 CI/CD 系統,我們做了大量的工作來與用戶使用的其他系統集成。有時,就像在 Azure 中一樣,事情會變得非同小適中。如果你熱衷于了解更多信息,請繼續閱讀,無需 Azure 知識!
讓我們先簡單介紹一下我們的 Cloud 集成的工作原理。整個工作流程非常簡單,如下所示:
分解這些要求,我們需要能夠獲取用戶云提供商賬戶的管理憑證,并通過環境變量的方式將其傳遞給Terraform,此時 Terraform 可以運行具有客戶基礎設施訪問權限的應用程序。
注意:為簡單起見,本文在所有示例中都使用了 Terraform,但這種整體方法也適用于我們支持的其他工具,例如 Pulumi。
Azure 集成背后的概念是提供與我們的?AWS?和?GCP?集成類似的體驗,但面向我們的 Azure 客戶。下圖顯示了 AWS 集成工作原理的簡化概述:
AWS 提供了臨時代入其他 AWS 賬戶 中的角色的功能。這允許我們的用戶在 IAM 中創建一個角色,其中包含他們可能想要授予 Spacelift 的任何權限。隨后,他們可以與我們的AWS賬戶建立對該角色的信任關系,從而授權我們的AWS賬戶以該角色的身份進行操作。
角色代入為我們提供了原始 AWS 憑證,并與任何 AWS 工具無縫協作,包括 Terraform AWS 提供商。它還允許我們指定有效期,因此每次運行都可以獲得自己的憑證,這些憑證被限制在短時間內。
盡管 Azure 沒有相同的功能,但它提供了另一種稱為 Azure Active Directory 應用程序的方法,該方法允許創建服務帳戶。Azure AD應用程序是一種資源,它使Spacelift能夠無縫地管理對客戶Azure資源的訪問。
值得解釋一下本文其余部分中使用的一些術語:
我們為集成設定了許多目標:
最初,我們的想法是創建一個多租戶 AD 應用程序:
我們的想法是,我們將生成一個只能用于特定客戶目錄的訪問令牌,并在運行期間將該令牌傳遞給 Terraform Azure RM 提供程序。最后,由于以下問題,我們不得不修改我們的方法:
經過幾天的頭腦風暴,我們想出了一種新的架構。我們可以以編程方式為 Spacelift 用戶創建的每個 Azure 集成生成一個新的 Azure AD 應用程序。
這樣,擁有Azure AD應用程序憑據的訪問權限僅能夠訪問用戶端對應的單一Azure AD租戶。這種方法允許將 Client Secrets 傳遞給 Spacelift 運行,而不必擔心用戶間權限泄漏。最終設計結果如下圖所示:
應用程序通過名為“管理員同意”的流程被安裝到客戶的Active Directory租戶中。完成管理員同意后,將在用戶的 Azure Active Directory 中創建一個服務主體,用戶可以向其授予權限。這允許用戶決定 Spacelift 對其資源的確切訪問級別。
我們面臨的下一個問題與生成運行憑證有關。如提供程序文檔中所述,可以通過設置某些環境變量來配置 Azure RM 提供程序。最初,我們采用一種基本方法,即嘗試在 Spacelift 運行期間生成憑證。這就是我們為 AWS 和 GCP 集成所做的工作,因此,我們預測不會出現重大問題。所采取的步驟如下所示:
這似乎有時奏效…但并非總是如此。
在測試集成時,發生了奇怪的事情。例如,雖然運行的規劃階段能夠成功完成,但在應用過程中卻會出現錯誤,具體表現為來自Azure的權限問題導致失敗。經過調查,我們得出結論,這是由?Azure AD 中的最終一致性引起的。
您可以使用下圖來可視化問題(注意:這只是一個插圖,并不意味著完全準確):
在上面的示例中,步驟 2 可能會成功或失敗,具體取決于機密是否已設法復制到其請求路由到的 Azure AD 服務器。最初,我們嘗試通過發出 API 請求來測試密鑰是否可用,然后使用指數退避重試直到請求成功。我們很快意識到,即便如此,后續的請求也有可能會被路由到另一個Azure AD實例上,而那個實例尚未接收到新的客戶端密碼,因此可能會導致請求失敗。
即使可以驗證密鑰何時完全復制,等待復制完成也會增加至少 30 秒,甚至可能再增加幾分鐘。因此,我們決定將憑證生成和輪換從運行流中移出,并移到計劃任務中:
計劃任務每小時運行一次,生成有效期為 24 小時的密鑰,并嘗試在舊密鑰過期前大約 2 小時為集成生成新密鑰。這允許憑證輪換,同時始終保持有效的密鑰。
生成新密鑰時,我們使用 AWS 的 Key Management Service 對其進行加密,以便它永遠不會以明文形式存儲。
觸發運行時,我們會嘗試在距離到期之前最長時間查找集成的密鑰。為了避免因Azure AD體系結構的最終一致性問題而導致的潛在麻煩,我們會在生成新機密后大約等待10分鐘再進行使用。
您可以使用下圖可視化密鑰生命周期:
此外,在創建新集成時,我們會立即生成密鑰。這有助于確保在觸發運行時,機密已在 Azure AD 中成功傳播。
我們面臨的最后一個主要問題是弄清楚如何為我們自己的管理賬戶實施憑證輪換。集成本身使用 Azure AD 服務主體來管理使用 Microsoft Graph API 的客戶 AD 應用程序。
由于我們在 AWS 中運行自己的大部分基礎設施,因此我們無法選擇使用托管服務身份,這意味著我們需要自己處理憑證輪換。此外,我們的目標是實現流程的自動化,以減輕開發人員定期執行手動任務的負擔,并減少在憑證到期前忘記續訂的風險。
最后,我們決定采用相對簡單的方法,將證書存儲在 Secrets Manager 中,并編寫一個計劃任務來定期檢查證書是否已準備好過期,類似于我們對集成客戶端密鑰采用的方法。如果是這樣,計劃任務將生成新證書并將其上傳到 Secrets Manager 和 Azure AD:
系統中需要使用客戶端證書進行身份驗證的部分會定期檢查更新的證書。與客戶端密鑰輪換一樣,我們會避免在新證書生成后的約10分鐘內使用它,以確保證書有足夠的時間在整個Azure AD系統中傳播生效。
與集成客戶端密鑰類似,Secrets Manager 使用 AWS Key Management Service 對靜態證書進行加密。
希望這篇文章能讓您了解 Spacelift 的 Azure 集成的內部結構,以及我們在實施它時必須解決的一些問題。您可能已經察覺到,我們在確保為用戶提供既安全又愉快的體驗方面,是非常愿意的。
原文鏈接:https://spacelift.io/blog/building-secure-cicd-integration-with-azure