如何在 Jenkins CI/CD 流水線中保護密鑰?

CI/CD 流水線是 DevOps 團隊軟體交付過程的基本組成部分。該流水線利用自動化和持續監控來實現軟體的無縫交付。通過持續自動化,確保 CI/CD 流水線每一步的安全性非常重要。在流水線的各個階段,通常需要訪問憑據等敏感資訊。保護這些資訊對於保持強大的安全態勢至關重要。本文將帶你了解如何在 Jenkins CI/CD 流水線中保護密鑰(Secrets)。

轉自 SEAL安全

在 CI/CD 流水線中使用 Secrets

如前所述,CI/CD 流水線通常需要訪問敏感資訊,如密碼和 API 密鑰。以明文對它們進行硬編碼會產生嚴重的安全風險,並且違反了大多數合規框架中的審計準則。使用這些憑證而不在非必要的情況下公開它們的機制,對於自動化軟體交付很重要。

用於安全存儲、管理和訪問上述憑證的工具和技術的集合稱為機密管理(Secrets Management)。Secrets 廣泛用於 IT、DevOps 和雲環境。

Secrets 包括:

  • 應用程式生成的密碼
  • 系統到系統的密碼
  • API 密鑰
  • 私有加密密鑰
  • 一次性密碼
  • 證書
  • 特權賬戶憑證

CI/CD 流水線集成了多個配置管理平台,需要 secrets 來啟用服務到服務的通訊。這些平台還需要 secrets 來驗證請求訪問 SSH 伺服器、資料庫、HTTP 服務和其他資源的實體。

CI/CD 中 Secrets 的用途

Secrets 用於管理 CI/CD 流水線中的訪問許可權。一些用例包括源程式碼控制管理、基礎設施連接、協作提供者和驗證。讓我們更詳細地討論這些用例中的每一個。

1. 源程式碼控制管理

版本控制系統,如 Git,便於多人團隊之間的協作。這些系統通過管理和存儲來自多個開發人員的程式碼貢獻,來幫助維護應用程式的開發。由於源程式碼可能包含一些組織最有價值的資產,因此正確驗證和管理 Git 存儲庫的訪問許可權至關重要。

密鑰管理系統對保護用於將貢獻者的主機連接到存儲庫的憑據非常重要。為了避免惡意攻擊者利用 secrets 發起安全攻擊,因此 secrets 並不存儲在版本控制,而是存儲在特殊的敏感文件中(當然這些敏感文件會被排除在存儲庫和日誌之外)。

2. 基礎設施連接

CI/CD 流水線通常由在多個主機上的不同服務組成,這些主機分布在不同的基礎設施上。隨著這些主機不斷地相互通訊,通過 API 調用與服務通訊,從而實現所需的應用程式功能。API 密鑰和系統到系統(system-to-system)密碼等 secrets 能夠支援在基礎設施之間建立安全的連接,從而連接多租戶和多雲 CI/CD 流水線。

3. 跨團隊協作

CI/CD 流水線包含跨多個開發、運營和品質保證環境的協作活動。這些團隊依靠多種工具和框架來協作和共享資訊。使用 secrets 進行協作有助於團隊確保安全通訊並在雙方之間提供一層信任和安全保障。

4. 驗證

身份驗證是 CI/CD 和應用程式安全的關鍵要素。通過將應用程式連接到身份和訪問管理 (IAM)解決方案,secrets 用於確保 CI/CD 流水線的安全性和隱私性。這些解決方案提供了用戶角色和許可權的外部資料庫,讓用戶無需在 CI/CD 流水線中暴露其憑據即可登錄應用程式。

CI/CD 中的 Secrets 使用示例

要為改進密鑰管理奠定基礎,了解一些簡單的用例會很有幫助。

1. AWS 憑證

作為領先的雲 SaaS 平台之一,AWS 是大多數基於雲的基礎設施的常見選擇。與 AWS API 交互以預置和查詢資源通常需要使用密鑰/訪問密鑰憑證。保護這些憑證對於維護 AWS 賬戶的安全至關重要。

2. 基礎架構即程式碼 (IaC)

現代應用程式架構通常依賴於基礎架構即程式碼 (IaC) 來部署運行工作負載的底層系統。對這種配置進行編碼能夠更輕鬆地對可重複、可擴展和安全的基礎架構進行維護。在配置此基礎架構的過程中,通常需要將敏感資訊(例如 SSH 密鑰和 API 憑證)部署到節點。通過 IaC 和 CI/CD 自動配置基礎設施是一種常見模式,管理機密是該工作流程的重要組成部分。

3. 環境變數

環境變數在大多數 CI/CD 流水線中都有一致的用法。在處理 CI/CD 工作流時,需要動態設置值並保留這些數據,以供其他進程和腳本使用。在許多情況下,敏感值需要通過環境變數傳遞,這也再次強調了有效機密管理的必要性。

在Jenkins內保護secrets

Jenkins 需要訪問大量憑據才能與構成完整 CI/CD 流水線的所有平台和應用程式交互。Jenkins 附帶了一個默認的憑證插件,其提供一個內置的密鑰存儲。還帶有憑據綁定插件,可以將憑據綁定到環境變數。

將密鑰存儲在 Jenkins controller 中使流水線中的應用程式,即使這些機密僅被創建一次仍然能夠被多次引用。雖然 Jenkins 憑據插件提供了一種存儲和管理機密的簡單方法,但任何 Jenkins 管理員和流水線作者都可以訪問它們。因此,DevOps 團隊應確保正確配置訪問許可權,以確保 CI/CD 流水線的安全。

Jenkins 支援的 secret 類型

Jenkins 機密插件支援的憑證包括:Secret text、用戶名/密碼對、secrets file、SSH 用戶名和證書。對於數量有限的密鑰,可以單獨存儲,而大量密鑰通常最好使用憑證文件進行管理。

在 Jenkins 中管理 secret

接下來我們將討論在 Jenkins 中保護 secret 的一些可用選項。一起來看看將 secrets 安全地注入 Jenkins 流水線的一些最佳實踐。

1. 一次性密碼 (OTP)

一次性密碼通過確保用戶名/密碼組合不能多次使用來幫助防止用戶帳戶被盜用。雖然該帳戶始終保留用戶名,但用戶每次登錄時都會收到一個 OTP。這可以保證 Jenkins 管理員和用戶帳戶的安全,防止密鑰資訊泄露。

2. 避免硬編碼密鑰

刪除已硬編碼到 CI/CD 配置和 Jenkinsfiles 中的密鑰。這樣能夠讓敏感憑證資訊不出現在流水線中,避免惡意行為者訪問和利用。

3. 將密鑰存儲在多個 Jenkins 文件

將密鑰存儲在多個文件中有助於實施憑據最少暴露原則。這樣可以讓憑據用於盡可能少的應用程式和用戶。

4. 使用授權控制來管理密鑰許可權

開發團隊應配置安全檢查,以確保請求資源訪問的應用程式具有有效應用程式的屬性。這些應用程式需要根據 RBAC (Role-based Access Control)策略中分配的許可權訪問各種資源。

5. 遵循最小許可權原則

僅將許可權授予需要訪問流水線內密鑰的應用程式。團隊應始終如一地審核許可權,確保在流水線的整個生命周期中最小許可權原則得以實施和維護。

管理和存儲密鑰

這一節我們將會介紹3個實際使用密鑰的Jenkins和Akeyless密鑰管理平台的基本例子:

  • 第一個例子是完全不安全的示例:使用純文本環境變數來存儲敏感憑據
  • 第二個例子則是使用原生的Jenkins功能和插件來進行密鑰管理
  • 第三例子將會展示使用第三方工具來進行密鑰管理的好處

純文本示例

首先,我們將會在Jenkins中創建一個「freestyle」項目,並將其連接到GitHub Repo:

圖1 項目創建

無論我們選擇如何管理程式碼中的密鑰,使用Jenkins內置的憑證機制來訪問GitHub倉庫是有用的。

圖2 配置 GitHub 憑據

我們的實際程式碼將是一個非常基本的Python應用程式,它進行API調用。該API需要一個簡單的API密鑰,以文本字元串的形式進行認證:

#!/usr/bin/env python
import os
import requests
api_key = os.environ[『API_KEY』]response = requests.get(「//thedogapi.com/v1/breeds?api_key={}」.format(api_key))
print(response)

Jenkins提供了配置環境變數的功能,然而,如果沒有額外的插件,它們只能對Jenkins的環境或實例進行全局設置。

圖3 配置全局環境變數

程式碼將從剛才配置的環境變數中讀取API密鑰。下面是構建步驟的配置:

圖4 構建配置

構建步驟運行一些簡單的提示,然後實際執行程式碼。下面是一個成功構建的日誌的一部分:

圖5 用暴露的密鑰構建日誌

API密鑰顯然已經在一個構建步驟中的一個簡單指令中以明文日誌的形式暴露出來。一個小小的錯誤配置就有可能導致泄露或危險。

Jenkins Secret Text

現在我們可以嘗試通過使用內置的證書處理程式來提高我們構建環境的安全性:

圖6 配置構建環境以使用密鑰

在本例中,我們將使用簡單的「Secret Text」憑據綁定來存儲API密鑰:

圖7 添加密鑰憑據

接下來,我們配置我們的構建job來使用新的憑證變數:

圖8 更新構建配置

現在,在運行另一個構建job後,我們再次檢查構建日誌:

圖9 使用已經被混淆了的密鑰構建job

儘管我們已經將構建步驟配置為將變數內容列印到日誌中,但Jenkins憑證處理程式知道該值是敏感的,並在任何日誌或輸出中混淆了實際值。

這固然極大地提高了構建的安全性,但並不是十全十美的。這對一個用戶量較少的Jenkins部署已經足夠用,但在一個大型的、分散式的Jenkins架構中,需要管理多個用戶和團隊的訪問許可權,這十分複雜,難以有效管理。此外,存儲在憑證變數中的密鑰值仍然可以被集群中的每個Jenkins實例以及具有適當許可權的任何用戶訪問。

如果任意節點被破壞,跨越多個部署和上下文的密鑰可能處於危險之中。用戶仍然需要手動保護和配置Jenkins的基礎設施,在本例中指密鑰存儲。如果有一種方法可以使用敏感的憑證,而不需要將他們存儲在Jenkins內部,會怎麼樣呢?

密鑰管理工具

讓我們試試使用Akeyless來管理密鑰。既然我們已經和Jenkins部署集成,我們可以按照文檔來進行操作。Akeyless與公開可用的Hashicorp Vault插件集成,因此Jenkins的設置很簡單。

接下來,我們將創建一個免費的Akeyless並配置密鑰:

圖10 在Akeyless中配置密鑰

圖11 創建密鑰(cont)

下一步是創建一個訪問角色,並且該角色有許可權訪問剛剛創建的密鑰:

圖12 創建角色

現在我們需要給我們的訪問角色以正確的許可權來查看密鑰:

圖13 給角色許可權

在Akeyless側我們需要創建的最後一個東西是一種認證方式。這就是我們如何讓外部實體,如我們的Jenkins部署,能夠對Akeyless進行API調用並檢索密鑰。

圖14 創建認證方式

認證方式創建完畢後,請確保通過下載CSV文件來保存訪問ID和密鑰,否則這些值將不會再次顯示。最後,我們需要將我們新創建的角色與這個訪問方式聯繫起來。

圖15 將認證方式與訪問角色聯繫起來

下一步是根據Akeyless文檔配置Jenkins構建環境:

圖16 使用Akeyless的Jenkins構建配置

現在,我們將運行另一個構建,這次配置的是利用此前配置過的Akeyless vault

圖17 使用Akeyless配置構建日誌

在日誌中,現在有一個步驟展示了Jenkins從Akeyless Vault中檢索密鑰。但構建日誌中的憑證值也依舊是模糊的。現在,我們有了一個與Jenkins實例集成的第三方密鑰管理平台。

這看起來有些畫蛇添足,但是一個完全專註於密鑰管理的外部工具是一個強大的抽象。Jenkins首先是一個CI/CD工具,密鑰管理是一個附加功能。在這種情況下,它永遠無法提供一流的功能、管理能力和安全保障,而專門的密鑰管理平台則可以提供:

  • 具有SLA保證的管理基礎設施
  • 零知識加密
  • 直觀的、可訪問的密鑰管理和組織
  • 與標準的DevOps工具和平台集成

像Akeyless這樣的工具還可以避免管理複雜的、自我託管的基礎設施。我們只需點擊幾下,就能擁有一個運行中的密鑰終端。

結 論

由於安全性是 CI/CD 流水線的首要考慮因素,因此在 Jenkins 中使用密鑰時遵循最佳實踐非常重要。Jenkins 流水線依賴密鑰進行身份驗證、協作和基礎設施管理。CI/CD 密鑰管理對大多數團隊來說都是一個挑戰,因為在細節上實施訪問控制非常困難和複雜。

而通過密鑰管理工具,Jenkins 用戶可以獲得更加集中且安全的資源來管理運行 CI/CD 流水線所需的包含敏感資訊的憑據,加速 DevOps 工作流程。同時,安全團隊也能夠全面了解密鑰的位置和使用方式。藉助自動化流程和集中訪問策略,密鑰管理平台還可以幫助安全團隊應對安全相關的法律和合規問題。