作者分析

CI/CD 裡那把永遠不過期的 token

程式碼一推上去,CI/CD 就自動測試、打包、部署;為了做到這些,設定裡放了一把權限很大、永遠不會過期的 token。三年後它還在那裡,當初設定它的人已經離職了。這篇講怎麼用 OIDC 短期憑證把它拿掉。

30 秒看懂
  • CI/CD 為了自動部署,常放著一把權限很大、永遠不過期的雲端金鑰,建立的人離職後就沒人敢動它。
  • 第三方外掛和 Action 跑在同一個執行環境,一旦被植入惡意程式碼,就能把環境變數裡的金鑰送出去。
  • GitHub Actions 支援 OIDC,工作流程向雲端證明身分換取短期 token,CI 設定裡就不必存放長期雲端金鑰。

三年前放進去的那把金鑰

假設有一家三十人的軟體公司,CI/CD 用一把雲端管理員金鑰部署到正式環境。某天,一個第三方 CI 外掛被發現遭到植入惡意程式碼,會把執行環境裡的環境變數送出去。公司這才緊張起來:那把金鑰是誰建的?權限有多大?還有哪些流程在用?要換掉的話,會不會讓部署全部中斷?

先說清楚,這是示意情境,不是真實事件,公司與經過都是為了說明而設。但這個形狀在自動化做得越早的團隊越常見:當初為了讓部署跑起來,放進一把權限很大、永遠不會過期的 token;三年後它還在那裡,當初設定它的人已經離職了。

這篇要講的只有一件事:CI/CD 裡不該有永遠不過期的雲端金鑰。

永遠不過期,風險在哪裡

第一層是壽命。長期有效的金鑰外洩後,在被撤銷前一直可用;沒人發現,它就一直可用。

第二層是權限。一把金鑰通常能部署所有環境,測試流程和正式部署用的是同一把。

第三層是供應鏈。第三方外掛、Action 都跑在同一個執行環境裡,讀得到你放在環境變數裡的金鑰。

最後是沒人敢換。不知道還有誰在用,換掉可能讓部署全部中斷,所以它就一直留著。

這篇示意情境裡,可能被送出去的是什麼

這是示意情境;下表列的是 CI/CD 執行環境裡最常見、也最容易被外掛讀到的憑證。

leaked credentials這次外洩了什麼:服務、用途、存在形式
服務憑證類型用途存在形式放在哪權限範圍狀態
雲端帳號(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。評估時仍要考慮預覽版的狀態。

這篇提到的項目要花多少錢

來源沒有列各方案價格,表裡的金額大多是估算或未公開,照實標出來。

cost把 CI/CD 長期金鑰換掉的成本
項目用量單價期間US$NT$舉證
盤點 CI/CD 裡所有長期憑證
估
工程師一人估 2–4 小時一次性——本站估算,依 repo 與流程數量而定
把一條部署流程改成 OIDC
估
工程師一人估每條 1–3 小時一次性——本站估算
GitHub Actions OIDC 搭配主要雲端
估
平台原生不另外花錢(來源說法)—0.000來源指出平台原生 OIDC 不用另外花錢;本文未逐一查證各家計價
AWS Secrets Manager/Google Cloud Secret Manager依密鑰數與呼叫量本文來源未列價格每月——本文未取得價格
示意情境中金鑰外洩後的損失未知未公開———示意情境;有沒有被使用本身就是缺口
合計(僅可證明列)0.000
匯率假設 1 USD ≈ NT$32。單價為公開牌價或帳單實付,來源:本站估算;GitHub、AWS、Google Cloud 官方文件(2026-10-17 讀取)。「舉證」欄標明每筆損失的證據來源與等級( 可證明 推論 缺口)。

改 OIDC 的工時是一次性的;那把永遠不過期的金鑰,風險是每天都在累積的。

你可以學到什麼

站在攻擊者那一側看,CI/CD 執行環境是一個每天自動打開好幾次的保險箱,裡面放著權限最大的鑰匙,旁邊還站著一排第三方外掛。他不用打穿你的雲端,只要成為其中一個外掛的一行程式碼。

lessons本案的 5 個教訓
  1. 01
    CI/CD 裡永遠不過期的雲端金鑰,外洩後在被撤銷前一直可用;建立人離職後,常常沒人敢換。
  2. 02
    第三方外掛和 Action 跑在同一個執行環境,讀得到你放在環境變數裡的金鑰,這就是供應鏈風險的形狀。
  3. 03
    GitHub Actions 支援 OIDC 換取短期 token,部署到 AWS、Azure、Google Cloud 時,CI 設定裡就不必存放長期雲端金鑰。
  4. 04
    OIDC 的信任條件要限定特定 repo、分支或環境;寫成整個組織都能用,等於換一種方式開大門。
  5. 05
    第三方 Action 用完整 commit SHA 鎖版本;暫時換不掉的金鑰依環境拆分、縮權限、設到期日。
keywords重點學習:最需要學習的 10 個關鍵字10 個
  1. 01
    OIDC(OpenID Connect)
    這篇的解法:讓工作流程證明身分換取短期 token,不再存放長期金鑰。
  2. 02
    長期憑證
    這篇的問題:永遠不過期,外洩後一直可用。
  3. 03
    工作負載身分(Workload Identity)
    雲端端接收 OIDC 的機制,決定哪個工作流程能拿到什麼權限。
  4. 04
    信任條件(Trust Policy)
    限定 repo、分支、環境的地方;設得太寬就是新的大門。
  5. 05
    GitHub Actions
    示範平台;OIDC 支援 AWS、Azure、Google Cloud、HashiCorp Vault。
  6. 06
    commit SHA 鎖版本
    讓第三方 Action 的內容固定,作者改標籤也不會偷換你的程式碼。
  7. 07
    供應鏈風險
    第三方外掛和你的金鑰在同一個執行環境,它被入侵就等於你被入侵。
  8. 08
    CI secret
    長期金鑰最常藏的地方,也是盤點的第一站。
  9. 09
    受管輪換(Managed Rotation)
    不能用 OIDC 的密鑰,交給 Secrets Manager 定期換。
  10. 10
    撤銷優先
    外洩時的順序:先撤銷,再查稽核紀錄,最後補新憑證。
try today今天就可以來試試約 15 分鐘

全部唯讀,不改任何設定;做完你會知道自己有沒有同樣的破口。

  1. 列出 repo 裡設定的 Actions secret 名稱(只列名稱與更新時間,看不到值)(唯讀)
    gh secret list
    看到什麼代表什麼:名稱看起來像雲端金鑰、且更新時間是好幾年前的,就是示意情境裡那一把的同類;把名稱、更新時間、用到它的 workflow 檔名抄進「ci-secret-inventory-p3.md」,第一步的盤點就從這份開始。
  2. 列出所有工作流程用到的第三方 Action,看是用標籤還是完整 SHA(唯讀)
    grep -rn "uses:" .github/workflows
    看到什麼代表什麼:結尾是 @v3、@main 這類會變動標籤的,就是還沒鎖版本的外掛。
  3. AWS 使用者:列出 CI 用的 IAM 使用者底下的存取金鑰(唯讀)
    aws iam list-access-keys --user-name <CI 用的 IAM 使用者>
    看到什麼代表什麼:看到狀態為 Active、建立日期很久以前的金鑰,代表 CI 還在用長期憑證。
  4. 對那把金鑰查上次被使用的時間與服務(唯讀)
    aws iam get-access-key-last-used --access-key-id <金鑰 ID>
    看到什麼代表什麼:最近仍在使用,代表有流程依賴它;記下時間,對照你知道的部署紀錄。
  5. 在雲端 IAM 主控台查看有沒有已設定的 OIDC 身分提供者(唯讀)
    看到什麼代表什麼:沒有任何一個,代表所有 CI 部署都還靠長期金鑰;這是改 OIDC 的起點。

揭露:本文未受任何廠商贊助,提及的產品僅為舉例。

來源

分享
精選拆解直送信箱

每篇新文章一封:三點摘要、關鍵字定義、今天能做的一件事。