SBOM
跨工程團隊的 SBOM 產生:一套政策,涵蓋每條管線
大多數組織的問題不在於沒有 SBOM,而在於有六套 SBOM 流程。先統一輸出:一種格式、一組欄位、一個產生時間點、一個存放位置。再讓各團隊的管線逐步符合這些規範,並優先在發布建置中產生 SBOM。客戶、稽核人員以及 CRA 等法規的主管機關,看的是 SBOM 及其背後的流程,而不是您買了哪一款掃描器。
更新日期
為什麼各團隊各自的掃描器拼湊不出一套 SBOM 計畫
用五款工具掃描同一個產品,您會得到五份 SBOM。這些差異是結構性的,而不是程式錯誤:
- 讀取不同的輸入,時間點也不同。一款工具讀取 lockfile,另一款讀取已安裝的相依套件樹,另一款讀取容器映像檔,還有一款讀取二進位檔。每款工具看到的都是產品的不同切面。
- 同一個東西有不同的名稱。一款工具以套件 URL 識別元件,另一款用 CPE,還有一款只用檔案名稱。兩份描述同一個函式庫的 SBOM,無法以共同的鍵值合併。
- 深度不同。有些只列出直接相依套件,有些列出完整的遞移相依樹,有些還會列出建置工具。為什麼不同的產生工具對同一個儲存庫的結果不一致,請參閱 開源 SBOM 產生工具。
- 有些工具回答的是另一個問題。基礎架構漏洞掃描器回報的是執行中主機上安裝了什麼。這對維運很有用,但它描述的並不是您出貨的產品。
結果是:您無法跨產品合併、去除重複或比較 SBOM,也無法向稽核人員展示一套流程,因為根本沒有這樣的流程。
| 方法 | 讀取的輸入 | 時間點 | 遺漏的內容 | 常見的識別碼 |
|---|---|---|---|---|
| lockfile 或 manifest 掃描器 | 簽出程式碼中的 lockfile 與 manifest | 建置之前或之後 | 任何 lockfile 都未列出的內容:安裝掛鉤、建置腳本下載的內容、基礎映像檔 | 套件 URL |
| 容器映像檔掃描器 | 映像檔中的套件資料庫與檔案 | 建置之後 | 僅用於建置的工具、編譯進去的程式碼、任何沒有套件記錄的內容 | 作業系統與程式語言套件使用套件 URL |
| 二進位檔或韌體掃描器 | 二進位檔中的字串與特徵碼 | 建置之後 | 確定性:版本與元件都是推斷出來的 | CPE 或推斷的名稱 |
| 主機漏洞掃描器 | 執行中伺服器上已安裝的軟體 | 營運期間 | 出貨給客戶的產品本身 | CPE 或廠商產品名稱 |
| 建置時記錄 | 發布建置實際取用的內容 | 建置期間 | 非您自行建置的軟體;無法看到的部分會標示為不完整 | 套件 URL |
SBOM 政策:應標準化哪些項目
標準化的對象是 SBOM,而不是掃描器。政策固定輸出與流程;每條管線再以它能執行的最佳產生工具來符合政策。下表的每一列都是可以檢查的項目。
| 要求 | 規則 | 原因 | 如何檢查 |
|---|---|---|---|
| 範圍 | 每個出貨給客戶的產品版本,包括韌體與容器映像檔。內部工具可選擇是否納入。 | 客戶與主管機關詢問的是您出貨的內容。 | 版本登記冊中的每個版本都有 SBOM。 |
| 格式與版本 | 一種主要格式(CycloneDX 或 SPDX),並訂定最低版本。應要求時接受另一種格式。 | 一種格式代表一個剖析器、一個驗證器與一個存放位置。BSI TR-03183-2 要求 CycloneDX 1.6 以上或 SPDX 3.0.1 以上,對歐盟客戶而言是合理的底線。 | 結構描述驗證會回報格式與版本。 |
| 最低欄位 | 每個有套件 URL 的元件都要附上套件 URL,只有在沒有時才使用 CPE;另外包括供應商、版本、宣告的授權、相依關係、工具名稱與版本、時間戳記以及產生情境。 | 這些是比對、授權審查與稽核所使用的欄位。請將它們與什麼是 SBOM中的最低要素對齊。 | 管線中的欄位檢查會計算缺少的值。 |
| 產生時間點 | 每次都在產出該版本的 CI 建置中產生。不是在稽核時,也不是在筆電上。 | 重新建置並不是同一次建置;請參閱建置時 SBOM。 | SBOM 的建置 ID 與該版本的建置 ID 相符。 |
| 深度 | 完整的遞移相依樹,而不只是頂層。 | CRA 的最低要求是頂層相依套件;但漏洞與客戶的要求都會更深入。 | 第一層以下也存在相依關係。 |
| 存放位置 | 與發布的建置產物放在一起,可依產品與版本取得。 | 資安公告發布時沒人找得到的 SBOM,就稱不上佐證資料。 | 依產品與版本,隨機取得某個版本的 SBOM。 |
| 保存期限 | 至少為產品的支援期間,再加上您所適用法規要求的文件保存期間。 | CRA 訂有技術文件的保存期間,而 SBOM 是技術文件的一部分。 | 比較政策訂定的期間與各工具的保存期限。 |
| 驗證 | 每份 SBOM 都在管線中進行結構描述驗證;無效的 SBOM 會讓建置或發布關卡失敗。 | 無效的 SBOM 會在客戶的工具中默默失效。 | 發布關卡的日誌顯示有驗證步驟。 |
| 負責人 | 產品團隊負責產生;產品資安團隊負責政策、驗證規則與涵蓋率報告。 | 產生需要管線的負責人;一致性需要規則有單一負責人。 | 每條管線都指定了負責人。 |
| 例外 | 具名且有期限的例外登記冊:團隊、原因、結束日期。 | 即使有團隊暫時無法遵循,政策仍能維持運作。 | 沒有任何例外已超過結束日期。 |
SBOM 最佳實務中的檢查清單涵蓋單一 SBOM 的規則;這份政策則是位於其上的一層。每個團隊都在管線旁的一個檔案中,宣告其管線如何符合政策:
# sbom-policy.yaml, one per release pipeline
product: gateway-firmware
owner: team-gateway
format: cyclonedx
spec_version: "1.6"
generated_in: release-build
generator: build-time-recording
store: artifact-registry
validation: schema, fail-on-errors
exception: none
在建置中產生,而不是各團隊事後產生
建置時產生是應該追求的標準。它描述的是實際出貨的建置,包含任何 lockfile 都未列出的隱藏相依套件,而且同一套機制能為該管線上的每個團隊產生相同結構的 SBOM。用廚房來比喻最容易理解:掃描器是嚐一口湯再猜食譜;記錄器則是看著每樣食材進入廚房。
對於非您自行建置的映像檔、第三方二進位檔,以及沒有 CI 的舊產品,掃描器仍是合適的工具。請在政策中寫明這一點,並記錄產生情境,讓讀者知道每份 SBOM 看到了什麼。
| 情境 | 產生方式 | 應記錄的產生情境 |
|---|---|---|
| 在您掌控的 CI 中建置的版本 | 記錄建置,或在發布作業中執行產生工具 | 「建置期間記錄」或「安裝後,從檔案產生」 |
| 在 CI 中建置的容器映像檔 | 記錄映像檔建置;若記錄器未涵蓋作業系統套件,再掃描結果以取得這些套件 | 建置 ID 與映像檔摘要值(digest) |
| 第三方映像檔或設備 | 映像檔掃描器,若廠商有提供 SBOM 則一併使用 | 「掃描輸出,非我們自行建置」 |
| 供應商的二進位檔 | 向供應商索取其建置 SBOM;以二進位分析作為檢查 | 供應商、版本、取得方式 |
| 沒有管線的舊產品 | 掃描出貨的建置產物;規劃建立管線 | 「掃描輸出」,以及一筆有結束日期的例外 |
混合 CI:同一組織中的 GitHub Actions、GitLab 與 Jenkins
這份政策在設計上就不綁定特定 CI:它定義的是輸出,因此 GitLab 或 Jenkins 管線可以透過產生工具步驟來符合政策,GitHub Actions 管線則可以使用建置時記錄。產生工具步驟的規則如下:
- 在發布作業中、安裝步驟之後執行,而不是在另一個重新安裝的作業中執行。
- 鎖定產生工具的版本,並將 CI action 鎖定到某個 commit,而不是標籤。為什麼這對掃描器尤其重要,請參閱 開源 SBOM 產生工具。
- 將產生情境記錄為「安裝後,從檔案產生」,讓讀者知道它看到了什麼。
- 以與其他所有管線相同的結構描述驗證輸出。
Syft、Trivy 與 cdxgen 等開源產生工具都能輸出 CycloneDX 與 SPDX,因此格式規則不會強迫您選擇特定工具。各工具的比較,請參閱 SBOM 工具比較。
CRACI 目前支援 GitHub Actions;GitLab CI 與 Jenkins 已列入產品藍圖,但尚無時程。這對導入的影響是:在使用 GitHub Actions 的地方開始採用建置時記錄,其他地方保留產生工具步驟,並在同一份涵蓋率報告中追蹤兩者。
當客戶要求特定格式版本時
客戶要求 CycloneDX 1.6,而您的工具輸出的是 1.7。這種情況之所以發生,是因為對方的匯入工具或其自身政策鎖定了某個版本;BSI 的底線是 1.6,因此歐盟客戶經常指定這個版本。您的選項如下:
- 詢問是否接受較新的版本。通常是可以的。
- 使用 CycloneDX CLI 轉換,再針對目標版本驗證,並檢查遺失了什麼:只存在於較新規格中的欄位會被捨棄。
- 若對方要求 SPDX,同一個 CLI 也能與 SPDX JSON 2.3 互相轉換。其文件警告,在 SPDX 與 CycloneDX 之間轉換「可能會導致部分資訊遺失」。
cyclonedx convert --input-file bom.cdx.json --input-format json \
--output-file bom-1.6.cdx.json --output-format json --output-version v1_6
cyclonedx validate --input-file bom-1.6.cdx.json --input-format json \
--input-version v1_6 --fail-on-errors
除非您傳入 --input-version,否則驗證器會依據 CycloneDX 1.7 進行檢查。政策規則:保留原始 SBOM 作為記錄。轉換後的副本屬於衍生交付物,請將其衍生方式(工具、版本、日期)一併保存。如何回應這類要求,請參閱客戶的 SBOM 要求;兩種格式的比較,請參閱 CycloneDX 與 SPDX 比較。
提供給法務的授權資料
只要政策要求正確的欄位,同一份 SBOM 也能為法務團隊所用。法務需要每個元件的授權、宣告的授權(套件自己標示的授權)與認定的授權(經人查證的授權)之間的差別、copyleft 義務,以及沒有授權的元件清單。CycloneDX 1.6 會將授權標示為宣告或認定,SPDX 則為兩者分別設有欄位。
- 要求使用 SPDX 授權識別碼或表達式,例如
MIT或Apache-2.0 OR MIT。 -
將
NOASSERTION與缺少的授權標記出來以供審查。在 SPDX 中,NOASSERTION代表未做出判定或未提供資訊;它不是一種授權。 - 在發布前(而不是發布後)將 copyleft 授權轉交法務。
SBOM 帶有的是宣告的授權。包含認定授權、聲明與義務的授權合規審查,屬於法務工作或專門工具的任務;請參閱開源授權合規。
逐一團隊導入
| 階段 | 負責人 | 完成條件 | 常見阻礙 |
|---|---|---|---|
| 1. 盤點:產品、管線、CI 系統與目前使用的產生工具,每條發布管線一列 | 產品資安團隊 | 每個已出貨的產品都有一列 | 沒有人知道是哪條管線建置某個版本 |
| 2. 發布政策與例外登記冊 | 產品資安團隊 | 政策已核准並發布 | 爭論該強制使用哪款工具(政策並不強制任何工具) |
| 3. 與一兩個有實際理由的團隊試行:客戶要求、截止期限,或目前工具無法處理的產品 | 試行團隊 | 試行的版本附上符合規範的 SBOM 出貨 | 沒有迫切理由的團隊會降低其優先順序 |
| 4. 在試行管線中加入驗證關卡 | 試行團隊 | 無效的 SBOM 會讓發布失敗 | 擔心阻擋發布;可先從警告開始 |
| 5. 依 CI 系統擴大範圍;只有在替代方案符合政策時,才淘汰各團隊自用的掃描器 | 產品團隊 | 每個 CI 系統都達到涵蓋率目標 | 沒有負責人的管線 |
| 6. 每月回報涵蓋率 | 產品資安團隊 | 報告每月提交給管理階層 | 指標以人工計算 |
第 1 階段的盤點試算表應該是最後一份試算表;如何擺脫試算表,請參閱 SBOM 自動化。以 Yocto 為基礎的產品是常見的試行對象,因為通用掃描器很難處理它;請參閱為什麼 SBOM 掃描器會遺漏 Yocto 建置。
衡量涵蓋率
管理階層與稽核人員要求的數字,每一項都定義為比率:
- 版本涵蓋率:附上符合政策之 SBOM 出貨的版本 ÷ 已出貨的版本。
- 產品涵蓋率:在目前支援期間內至少有一份符合規範之 SBOM 的產品 ÷ 支援中的產品。
- 驗證通過率:通過驗證的 SBOM ÷ 產生的 SBOM。
- 識別碼涵蓋率:具有套件 URL(或 CPE)的元件 ÷ 元件總數。
- 授權涵蓋率:具有宣告授權的元件 ÷ 元件總數。
- 完整性:產生工具標示為完整的 SBOM ÷ SBOM 總數。只有在工具會回報時才能計算。
- SBOM 產出時間:從版本發布到 SBOM 可取得所需的時間。
每月報告範例(示意數字):
| 指標 | GitHub Actions 管線 | GitLab 與 Jenkins 管線 | 全部 |
|---|---|---|---|
| 版本涵蓋率 | 46 / 48 | 19 / 27 | 65 / 75 |
| 驗證通過率 | 100% | 92% | 97% |
| 識別碼涵蓋率 | 99% | 88% | 95% |
| 未結案的例外 | 1 | 4 | 5 |
作為提供給主管機關或稽核人員的佐證資料,這一組內容包括政策、例外登記冊、涵蓋率報告與數份 SBOM 範例。它展示的是一套經過落實與衡量的流程。CRA 方面的內容,請參閱 CRA 指南。
CRACI 的定位
對於 GitHub Actions 管線,CRACI 就是執行器:您設定 runs-on: craci,每個作業就會取得一份記錄的 SBOM,不需要產生工具步驟。每份 SBOM 都帶有完整性狀態、遞移相依套件、每個套件的套件 URL 以及每個元件宣告的授權,並可匯出為 CycloneDX 或 SPDX 格式。授權政策規則可以封鎖建置,受監控的 SBOM 會持續重新評估,建置歷史則會顯示哪些建置含有有漏洞的相依套件。這讓這些團隊預設就符合政策中「在發布建置中產生」、「識別碼」與「授權」這幾列的要求。您也可以加入第三方 SBOM,讓外購元件與您的建置一併受到監控。
請參閱 CRACI 的 SBOM 產生與 GitHub Actions 中的 SBOM。
CRACI 不適用的情況
- 使用 GitLab CI 或 Jenkins 的團隊:目前不支援,已列入產品藍圖。請使用符合政策的產生工具步驟。
- GitHub Enterprise Server:目前不支援。
- 基礎架構與主機掃描,也就是伺服器上安裝了什麼以及錯誤組態:這是另一項工作,請保留那些工具。
- 對非您自行建置之供應商映像檔的二進位檔或韌體分析:CRACI 記錄的是建置,不會掃描二進位檔。
- 長期保存:CRACI 預設保存建置資料 180 天,Enterprise 方案可自訂保存期限。如果您的政策需要更長期保存 SBOM,請將其匯出到您自己的存放位置。
跨團隊 SBOM 產生:常見問題
使用不同工具的團隊之間,要如何標準化 SBOM 產生?
標準化的對象是輸出,而不是工具。撰寫一套政策,固定格式與版本、最低欄位、SBOM 的產生時間點、存放位置、保存期限,以及由誰驗證。讓每條管線以它能執行的最佳產生工具來符合政策,並依據政策衡量涵蓋率。
SBOM 政策應該包含哪些內容?
範圍、格式與最低版本、最低欄位(套件 URL、供應商、版本、宣告的授權、相依關係、工具、時間戳記、產生情境)、在發布建置中產生、完整的遞移深度、與版本一起存放、保存期限、在管線中驗證、負責人,以及有期限的例外登記冊。
應該讓每個團隊執行自己的掃描器,還是讓 SBOM 來自建置?
能做到的地方,就讓 SBOM 來自建置。建置時 SBOM 描述的是實際出貨的建置,並讓該管線上的每個團隊都得到相同結構的 SBOM。對於非您自行建置的內容,則保留掃描器:第三方映像檔、供應商的二進位檔,以及沒有管線的舊產品。
客戶希望我們的 SBOM 採用較舊的 CycloneDX 版本,該怎麼辦?
先詢問是否接受較新的版本。若不接受,就使用 CycloneDX CLI(cyclonedx convert 搭配 --output-version v1_6)轉換一份副本,針對該版本進行驗證,並檢查哪些欄位被捨棄。保留原始檔案作為記錄,並保存副本的衍生方式。
如何從 SBOM 中取得授權資料提供給法務?
在政策中要求使用 SPDX 授權識別碼或表達式,將 NOASSERTION 與缺少的授權標記出來以供審查,並在發布前將 copyleft 授權轉交法務。SBOM 帶有的是宣告的授權;認定的授權、聲明與義務則需要授權審查。
如何衡量各產品的 SBOM 涵蓋率?
以比率表示:附上符合規範之 SBOM 出貨的版本、支援中且有符合規範之 SBOM 的產品、驗證通過率、具有套件 URL 的元件、具有宣告授權的元件、在工具會回報時的完整 SBOM,以及從版本發布到 SBOM 可取得的時間。依 CI 系統每月回報。
要向稽核人員證明 SBOM 產生具有一致性,需要哪些佐證資料?
政策、例外登記冊、每月涵蓋率報告,以及數份附有產生情境的 SBOM 範例。這些內容合起來展示了一套套用於每個版本並經過衡量的流程,而這正是稽核人員或客戶會檢查的重點。