CI/CD 裡那把
永遠不過期的 token
為什麼現在很紅:CI/CD 裡那把雲端管理員金鑰,誰建的、權限多大、還有誰在用,三個問題常常沒有一個答得出來。
- 一句話結論
- CI/CD 為了自動部署,常放著一把權限很大、永遠不過期的雲端金鑰,建立的人離職後就沒人敢動它。
- 他要的是什麼
- 他不用攻擊你的雲端。他只要讓你用的某個第三方外掛多一行程式碼,下一次部署,你的管理員金鑰就會自己送過來。
- 你今天做一件事
- 今天就列出 CI/CD 裡所有的長期憑證,標上建立人與權限;能改成 OIDC 的,排進這個月的工作。 直接去做 →
- 哪些能信
- 3 可證明2 推論2 缺口 每個主張都標了等級,缺口是誠實寫出來的。
- 破口速查
- 受害端一律去識別化;寫「未公開」代表公開資料查不到。
- 伺服器服務商
- 不適用(示意情境;涉及的是 CI/CD 平台與雲端帳號)
- 網路服務商
- 不適用(同上)
- 漏洞出現的地方
- 部署流程層:CI/CD 設定裡存著長期有效、權限涵蓋所有環境的雲端金鑰;第三方外掛與 Action 跑在同一個執行環境,可以讀到這把金鑰;建立人已離職,沒人知道還有哪些流程依賴它,所以沒人敢換
- 馬上自我檢測
gh secret list grep -rn "uses:" .github/workflows aws iam list-access-keys --user-name <CI 用的 IAM 使用者> aws iam get-access-key-last-used --access-key-id <金鑰 ID>- 漏洞修補方式
- 盤點 CI/CD 裡所有長期憑證;雲端部署改用 OIDC 換取短期 token,信任條件限定特定 repo、分支或環境;第三方 Action 用完整 commit SHA 鎖版本;暫時換不掉的金鑰依環境拆分、縮權限、設到期日;外洩時先撤銷、再查稽核紀錄、最後補上新憑證
有 15 分鐘再看:其餘 2 點
- 第三方外掛和 Action 跑在同一個執行環境,一旦被植入惡意程式碼,就能把環境變數裡的金鑰送出去。
- GitHub Actions 支援 OIDC,工作流程向雲端證明身分換取短期 token,CI 設定裡就不必存放長期雲端金鑰。
程式碼一推上去,CI/CD 就自動測試、打包、部署;為了做到這些,設定裡放了一把權限很大、永遠不會過期的 token。三年後它還在那裡,當初設定它的人已經離職了。這篇講怎麼用 OIDC 短期憑證把它拿掉。
本篇目錄
三年前放進去的那把金鑰
假設有一家三十人的軟體公司,CI/CD 用一把雲端管理員金鑰部署到正式環境。某天,一個第三方 CI 外掛被發現遭到植入惡意程式碼,會把執行環境裡的環境變數送出去。公司這才緊張起來:那把金鑰是誰建的?權限有多大?還有哪些流程在用?要換掉的話,會不會讓部署全部中斷?
先說清楚,這是示意情境,不是真實事件,公司與經過都是為了說明而設。但這個形狀在自動化做得越早的團隊越常見:當初為了讓部署跑起來,放進一把權限很大、永遠不會過期的 token;三年後它還在那裡,當初設定它的人已經離職了。
這篇要講的只有一件事:CI/CD 裡不該有永遠不過期的雲端金鑰。
永遠不過期,風險在哪裡
第一層是壽命。長期有效的金鑰外洩後,在被撤銷前一直可用;沒人發現,它就一直可用。
第二層是權限。一把金鑰通常能部署所有環境,測試流程和正式部署用的是同一把。
第三層是供應鏈。第三方外掛、Action 都跑在同一個執行環境裡,讀得到你放在環境變數裡的金鑰。
最後是沒人敢換。不知道還有誰在用,換掉可能讓部署全部中斷,所以它就一直留著。
這篇示意情境裡,可能被送出去的是什麼
這是示意情境;下表列的是 CI/CD 執行環境裡最常見、也最容易被外掛讀到的憑證。
| 服務 | 憑證類型 | 用途 | 存在形式 | 放在哪 | 權限範圍 | 狀態 |
|---|---|---|---|---|---|---|
| 雲端帳號(IAM) | 長期存取金鑰 | CI/CD 自動部署到正式環境 | CI/CD 設定裡的 secret,執行時以明文環境變數提供給流程 | CI/CD 平台的 secret 設定 | 雲端管理員等級,涵蓋所有環境 | 示意情境;建立人已離職、從未輪換,撤銷前持續有效 |
| 同一執行環境裡的其他 secret(第三方 API key 等) | API key/token | 部署時呼叫第三方服務 | 明文環境變數 | CI/CD 平台的 secret 設定 | 依各服務而定 | 該外掛是否在你的流程裡執行過、有沒有送出,無法確認 |
第二列標成缺口,是因為要先確認那個外掛有沒有在你的流程裡跑過,才談得上有沒有被送出去。
能證明的、只能推論的
這篇是觀點文,情境是示意的,所以能證明的只有官方文件與官方公告寫明的事;情境裡的經過只能算推論,不知道的就寫成缺口。
不花錢就能做的流程
到這裡,其實已經足夠理解問題在哪。如果你想直接動手,可以跳到「今天就可以來試試」;下面是完整的六步流程。
第一步,盤點 CI/CD 裡的所有長期憑證。 名稱、建立人、權限、使用的流程、最後使用時間。
第二步,改用 OIDC 短期憑證。 讓工作流程向雲端證明身分,換取短期 token,CI 設定裡就不再需要長期雲端金鑰。
第三步,縮小信任範圍。 雲端端的信任條件,限定特定 repo、分支或環境,不要寫成「整個組織都能用」。
第四步,第三方 Action 鎖版本。 用完整的 commit SHA 鎖定版本,不要用會變動的標籤。差別長這樣:
# 會變動的標籤:作者改了標籤指向,你下次部署就跑到新程式碼
uses: some-org/some-action@v3
# 完整 commit SHA:內容固定,要升級得自己改
uses: some-org/some-action@0123456789abcdef0123456789abcdef01234567
第五步,還沒辦法換的,就縮權限、設到期日。 依環境拆分金鑰,正式環境的金鑰只給正式部署的流程。
第六步,外洩時的順序。 先撤銷,再查稽核紀錄,最後補上新的憑證。
什麼時候不需要買工具
部署目標是 AWS、Azure 或 Google Cloud,而 CI 是 GitHub Actions 的話,平台原生的 OIDC 不用另外花錢,就能把長期雲端金鑰拿掉。需要把第三方 API key 這類「不能用 OIDC」的密鑰也統一管理時,才需要密鑰管理平台。
市面上大致分四類。CI 與雲端原生:GitHub Actions OIDC 搭配 AWS、Azure、Google Cloud 的工作負載身分。雲端密鑰管理:AWS Secrets Manager(支援受管輪換或用 Lambda 自訂輪換)、Google Cloud Secret Manager。開源密鑰管理:OpenBao(OpenSSF 下的 Vault 開源分支)、Infisical。商用:HashiCorp Vault(IBM 旗下,BSL 授權);1Password 在 2026/06/15 發表 Credential Broker 私人測試版,新聞稿說首先支援用 GitHub Actions 的工作負載身分驗證後再發放憑證,並記錄每次請求,正式版目標是 2026 年底。
限制也要一起看:OIDC 只解決「CI 到雲端」這一段,第三方 SaaS 的 API key 仍然要另外管理;信任條件設得太寬,等於換一種方式開大門;測試版產品不適合直接用在關鍵流程。選的時候問三件事:部署目標是不是主要雲端(都支援 OIDC,先用原生方式)、非雲端密鑰有多少(多的話,考慮密鑰管理平台)、有沒有維運能力(自架 OpenBao 需要高可用和備份規劃)。
後續更新:2026/07/28,1Password Credential Broker 進入公開預覽,開放給 Enterprise Password Manager 客戶,官網說支援 GitHub Actions 和自訂 OIDC。評估時仍要考慮預覽版的狀態。
這篇提到的項目要花多少錢
來源沒有列各方案價格,表裡的金額大多是估算或未公開,照實標出來。
| 項目 | 用量 | 單價 | 期間 | US$ | NT$ | 舉證 |
|---|---|---|---|---|---|---|
| 盤點 CI/CD 裡所有長期憑證 估 | 工程師一人 | 估 2–4 小時 | 一次性 | — | — | 本站估算,依 repo 與流程數量而定 |
| 把一條部署流程改成 OIDC 估 | 工程師一人 | 估每條 1–3 小時 | 一次性 | — | — | 本站估算 |
| GitHub Actions OIDC 搭配主要雲端 估 | 平台原生 | 不另外花錢(來源說法) | — | 0.00 | 0 | 來源指出平台原生 OIDC 不用另外花錢;本文未逐一查證各家計價 |
| AWS Secrets Manager/Google Cloud Secret Manager | 依密鑰數與呼叫量 | 本文來源未列價格 | 每月 | — | — | 本文未取得價格 |
| 示意情境中金鑰外洩後的損失 | 未知 | 未公開 | — | — | — | 示意情境;有沒有被使用本身就是缺口 |
| 合計(僅可證明列) | 0.00 | 0 | ||||
改 OIDC 的工時是一次性的;那把永遠不過期的金鑰,風險是每天都在累積的。
你可以學到什麼
站在攻擊者那一側看,CI/CD 執行環境是一個每天自動打開好幾次的保險箱,裡面放著權限最大的鑰匙,旁邊還站著一排第三方外掛。他不用打穿你的雲端,只要成為其中一個外掛的一行程式碼。
- 01CI/CD 裡永遠不過期的雲端金鑰,外洩後在被撤銷前一直可用;建立人離職後,常常沒人敢換。
- 02第三方外掛和 Action 跑在同一個執行環境,讀得到你放在環境變數裡的金鑰,這就是供應鏈風險的形狀。
- 03GitHub Actions 支援 OIDC 換取短期 token,部署到 AWS、Azure、Google Cloud 時,CI 設定裡就不必存放長期雲端金鑰。
- 04OIDC 的信任條件要限定特定 repo、分支或環境;寫成整個組織都能用,等於換一種方式開大門。
- 05第三方 Action 用完整 commit SHA 鎖版本;暫時換不掉的金鑰依環境拆分、縮權限、設到期日。
- 01OIDC(OpenID Connect)這篇的解法:讓工作流程證明身分換取短期 token,不再存放長期金鑰。
- 02長期憑證這篇的問題:永遠不過期,外洩後一直可用。
- 03工作負載身分(Workload Identity)雲端端接收 OIDC 的機制,決定哪個工作流程能拿到什麼權限。
- 04信任條件(Trust Policy)限定 repo、分支、環境的地方;設得太寬就是新的大門。
- 05GitHub Actions示範平台;OIDC 支援 AWS、Azure、Google Cloud、HashiCorp Vault。
- 06commit SHA 鎖版本讓第三方 Action 的內容固定,作者改標籤也不會偷換你的程式碼。
- 07供應鏈風險第三方外掛和你的金鑰在同一個執行環境,它被入侵就等於你被入侵。
- 08CI secret長期金鑰最常藏的地方,也是盤點的第一站。
- 09受管輪換(Managed Rotation)不能用 OIDC 的密鑰,交給 Secrets Manager 定期換。
- 10撤銷優先外洩時的順序:先撤銷,再查稽核紀錄,最後補新憑證。
全部唯讀,不改任何設定;做完你會知道自己有沒有同樣的破口。
- 列出 repo 裡設定的 Actions secret 名稱(只列名稱與更新時間,看不到值)(唯讀)
gh secret list看到什麼代表什麼:名稱看起來像雲端金鑰、且更新時間是好幾年前的,就是示意情境裡那一把的同類;把名稱、更新時間、用到它的 workflow 檔名抄進「ci-secret-inventory-p3.md」,第一步的盤點就從這份開始。 - 列出所有工作流程用到的第三方 Action,看是用標籤還是完整 SHA(唯讀)
grep -rn "uses:" .github/workflows看到什麼代表什麼:結尾是 @v3、@main 這類會變動標籤的,就是還沒鎖版本的外掛。 - AWS 使用者:列出 CI 用的 IAM 使用者底下的存取金鑰(唯讀)
aws iam list-access-keys --user-name <CI 用的 IAM 使用者>看到什麼代表什麼:看到狀態為 Active、建立日期很久以前的金鑰,代表 CI 還在用長期憑證。 - 對那把金鑰查上次被使用的時間與服務(唯讀)
aws iam get-access-key-last-used --access-key-id <金鑰 ID>看到什麼代表什麼:最近仍在使用,代表有流程依賴它;記下時間,對照你知道的部署紀錄。 - 在雲端 IAM 主控台查看有沒有已設定的 OIDC 身分提供者(唯讀)看到什麼代表什麼:沒有任何一個,代表所有 CI 部署都還靠長期金鑰;這是改 OIDC 的起點。
揭露:本文未受任何廠商贊助,提及的產品僅為舉例。
環境背景、時間線、攻擊鏈對照 ATT&CK、關鍵證據、根因、處置與檢討都在完整版,約 7 分鐘。
來源
- GitHub Docs:以 OpenID Connect 強化部署安全
- AWS Secrets Manager:輪換密鑰
- Google Cloud Secret Manager 總覽
- OpenBao(開源 Vault 分支)
- Infisical(開源密鑰管理)
- IBM 新聞稿:完成收購 HashiCorp
本文為公開報導與官方公告的整理與拆解,非第一手鑑識;證據等級依來源可信度標註。
本文由 AI 團隊協助研究與撰寫,經隱私與事實檢查後發布;證據等級依來源可信度標註。
複製下面這段,貼給你在用的 AI 工具(Claude Code、Cursor、Copilot、ChatGPT 都可以)。它會用本篇的破口位置、自我檢測與學習重點,對你的專案或環境做一次資安掃描,列出潛在問題與建議的調整或加強方式。
預設是唯讀:只發現問題、提出建議,不會改你任何檔案或設定。
M2 身分與金鑰 · 想在自己的環境做一次同樣的盤點,從 自我盤點 開始。
每篇新文章一封:三點摘要、關鍵字定義、今天能做的一件事。或先 加入會員 記錄你完成的任務。