GitHub Actions OIDC immutable subject claims:IAM 信任政策怎麼遷移?
GitHub Actions 用 OIDC 交換雲端短效憑證時,最容易被忽略的不是 id-token: write,而是雲端 IAM 信任條件裡的 sub(subject)字串。只要 repository 新建、改名、轉移,或管理員啟用 immutable subject claims,原本只用組織名稱與 repository 名稱的信任政策就可能不再匹配。
先講結論:2026 年 7 月 15 日之後建立的 repository,預設使用含 owner ID 與 repository ID 的 immutable sub 格式;更早建立的 repository 會保留舊格式,除非主動 opt in。 更新雲端 trust policy 前,先用實際 workflow 取得並檢查 token claims,再按照 repository 使用的格式調整條件。GitHub Enterprise Server 目前不提供這套 immutable subject claims。
這不是把 OIDC 改成另一種登入協定,而是改變雲端在 sub 上看到的識別內容。它解決的是名稱被回收後可能重用同一個 subject 的風險,但也要求部署端把「名稱」和「不可變 ID」的遷移順序排好。
如果你的 OIDC 是為了 release provenance,還要把 trust policy 和 artifact attestations 的 subject 設計 分開審查;如果它位於 reusable workflow,則應另外核對 secrets 傳遞與 caller/called workflow 邊界。
先看舊格式與 immutable 格式
以 octo-org/octo-repo 的 main branch 為例,GitHub 官方文件列出的差異如下:
| repository 狀態 | sub 範例 |
|---|---|
| 舊格式 | repo:octo-org/octo-repo:ref:refs/heads/main |
| immutable 格式 | repo:octo-org@123456/octo-repo@456789:ref:refs/heads/main |
如果 job 使用 environment,sub 的 context 會改成 environment 形式,例如:
repo:octo-org@123456/octo-repo@456789:environment:Production這些數字只是官方格式示例,不是你的 repository ID。不要把文章、別人的 IAM 設定或 repository URL 中的數字直接貼進生產政策;應從你自己的實際 token、GitHub API 或 repository 設定取得值。
為什麼名稱不夠安全?
舊的預設 sub 主要使用 organization 和 repository name。如果 repository 被刪除,名稱在之後被另一個 owner 重新建立,雲端 trust policy 看到的字串可能一樣,卻已經不是原來的 repository。Immutable 格式把 owner ID 和 repository ID 放進 repo segment,讓名稱變更或 namespace 重新建立時更容易維持唯一性。
目前需要特別盤點三種事件:
- 2026 年 7 月 15 日之後新建 repository:預設直接使用 immutable 格式。
- 2026 年 7 月 15 日之前的既有 repository:預設保留舊格式,除非 opt in。
- 2026 年 7 月 15 日之後的 repository rename 或 transfer:GitHub 文件指出會移到 immutable 格式。
如果同一個組織同時有新舊 repository,不能把一條以 repo:ORG/REPO:* 為基礎的政策當成所有 repository 都會通過;每個 trust relationship 都要核對它實際收到的 sub。
OIDC workflow 先只做 claims 檢查
GitHub 官方提供 github/actions-oidc-debugger action,可以在接雲端 provider 前查看 workflow 會收到的 claims。最小的檢查 workflow 可以長這樣:
name: Inspect Actions OIDC claims
on: workflow_dispatch:
permissions: id-token: write
jobs: inspect: runs-on: ubuntu-latest steps: - name: Print OIDC claims uses: github/actions-oidc-debugger@mainid-token: write 的意思是允許 workflow 向 GitHub OIDC provider 取得 JWT,不是讓 job 對其他資源取得 write access。這個 debug workflow 不需要 checkout;如果你的實際工作還要讀取原始碼,才另外加入 contents: read。
在共用 repository 或生產環境使用 action 時,應依組織供應鏈政策把 action pin 到受信任的 commit SHA;上面的 @main 只是為了對照官方 debugger 的最小概念範例。Debug log 可能包含不應公開的 claims,請限制 workflow 的觸發者和 log 存取權,不要把完整 JWT 複製到 issue 或聊天頻道。
檢查結果至少記錄:
| Claim | 用途 |
|---|---|
iss | 確認 issuer 是 https://token.actions.githubusercontent.com |
aud | 確認 audience 和雲端 login action/provider 條件一致 |
sub | 確認 IAM trust policy 應比對的主體格式 |
repository_id、repository_owner_id | 對照 immutable repository/owner ID |
ref、environment、job_workflow_ref | 確認 branch、environment 或 reusable workflow 的實際邊界 |
雲端信任政策的遷移順序
不要先在 GitHub 啟用新格式,再回頭猜雲端應該改成什麼。較安全的順序是:
- 列出所有使用 GitHub OIDC 的 AWS、Azure、Google Cloud、Vault 或其他 provider trust relationship。
- 對每個 repository 和觸發條件執行受限制的 debug workflow,保存
iss、aud、sub和非敏感識別資訊。 - 先在 cloud provider 建立能匹配新格式的條件;如果 provider 支援短暫並存,舊格式條件應設定清楚的移除期限,不要用無限制 wildcard 代替遷移。
- 依 GitHub OIDC 設定 UI 或 REST API 為既有 repository opt in,或套用組織的 subject customization;不要把 opt-in 和雲端 login action 的 audience 設定混為一談。
- 執行實際部署 workflow,確認雲端收到的新
sub、aud和job_workflow_ref都符合預期。 - 確認所有舊版 workflow 都已切換後,再刪除舊 trust condition,並保留回滾紀錄。
GitHub 文件特別提醒,如果要自訂 sub template,應先在雲端建立匹配條件,再透過 API 套用 GitHub 設定,避免 token 已改格式但 provider 尚未同步。自訂 subject 會改變整個 sub 的格式;對 immutable repository 而言,owner ID 與 repository ID 仍會保留在 repo segment,不能靠 include_claim_keys 移除。
Provider 條件只換字串,不要放寬邊界
不同雲端 provider 寫 trust condition 的語法不同,但核心都是讓 sub 精確對應 GitHub token:
| Provider | 舊格式條件概念 | Immutable 格式條件概念 |
|---|---|---|
| AWS | token.actions.githubusercontent.com:sub 等於舊 repo: 字串 | 同一個 claim 改成含 owner/repo ID 的字串 |
| Azure | Federated credential 的 subject 等於舊格式 | subject 改成 immutable 格式 |
| Google Cloud | assertion 的 sub 比對舊格式 | assertion.sub 比對 immutable 格式 |
| HashiCorp Vault | bound_subject 使用舊格式 | bound_subject 使用 immutable 格式 |
不要因為遷移麻煩就把條件改成只驗 repository_owner、只驗 aud,或對整個 organization 使用寬鬆 wildcard。若部署需要限制 branch、environment 或 reusable workflow,就把它們一併納入明確的 claims 設計。真正需要的最小權限,應在 cloud role 的 permission policy 另外維持。
什麼時候用 subject customization?
Immutable default 解決 repository identity 的唯一性;subject customization 則處理更細的信任條件。例如組織想要求所有部署都經過固定 reusable workflow,可以使用 job_workflow_ref 作為 sub 的一部分。這是另一個設定層級,不能因為看到 include_claim_keys 就以為等同於 immutable default。
目前文件列出的幾個選擇方向是:
- 只限制某個 repository:使用
repo條件。 - 限制 environment 或 branch:使用預設 context 的對應格式。
- 統一組織部署入口:把
job_workflow_ref納入條件。 - 依 repository metadata 做 ABAC:使用
repo_property_*claims,但要先由組織或 enterprise 管理員啟用。
每次改 template 後,都要重新取得一個新 job 的 token 驗證;舊 job 的 JWT 不會因設定修改而變成新格式。
排錯清單
Not authorized 或 STS 信任失敗
先把雲端錯誤分成 issuer、audience、subject 和 permission 四類。若 iss 和 aud 正確、只有 sub 不匹配,優先檢查 repository 是否新建、rename、transfer 或已 opt in immutable claims。不要一開始就提高 cloud role 權限。
Debugger 取不到 token
確認 workflow 或 job 有 id-token: write,且是 GitHub Actions 執行的 job。缺少這項 permission 時,action 不能要求 OIDC JWT;它和 contents: read、secrets 或 cloud provider 的 role permission 是不同邊界。
只有 reusable workflow 失敗
檢查 token 是由哪個 workflow 產生,以及 caller 和 called workflow 的 repository/organization 關係。跨 organization 或 enterprise 的 reusable workflow,官方要求在 caller workflow 或 job 明確設定 id-token: write;同時確認 job_workflow_ref 是否真的被拿來做 trust condition。
GHES 找不到 immutable 格式
目前 GitHub 文件把 immutable subject claims 限定在 GitHub.com,GHES 不提供這項 rollout。請依 GHES 的 OIDC 文件與實際 claims 設計條件,不要把 GitHub.com 的 owner/repo ID 格式硬套上去。
常見問題
Q: 既有 repository 會自動改成 immutable sub 嗎?
A: 官方目前的說明是,2026 年 7 月 15 日前建立的 repository 保留舊格式,除非 opt in immutable subject claims;同日後的新建、rename 或 transfer 事件則採用 immutable 格式。請以 debug workflow 取得的實際 token 為準。
Q: id-token: write 會讓 workflow 可以寫入雲端資源嗎?
A: 不會。它只允許 workflow 取得 OIDC JWT;真正能不能換成 cloud role,以及 role 能做什麼,仍由 provider 的 trust condition 和 permission policy 決定。
Q: 可以直接用 repo:ORG/REPO:* 同時支援新舊格式嗎?
A: 不能假設可以。Immutable 格式在 owner 和 repository 名稱後加入 @ID,字串結構已經不同;是否能在 provider 中同時設定兩個精確條件要看 provider 語法。遷移期間寧可短暫列出兩個可審核的值,也不要用會放行未知 repository 的 wildcard。
Q: Subject customization 和 immutable subject claims 是同一件事嗎?
A: 不是。Immutable default 把 owner/repository ID 放進預設 sub;customization 則用 include_claim_keys 改變 sub 的內容與信任條件。兩者可以一起影響 token,且 immutable repository 的 ID segment 不能被 customization 移除。
查證範圍:本文於 2026-09-08 檢查 GitHub Actions 官方 OIDC reference 與 immutable subject claims 說明;YAML、debugger 和 provider 條件為未連接實際雲端帳號的示例,沒有在本機或 GitHub repository 執行。
參考資料:
GitHub Docs:OpenID Connect reference
GitHub Changelog:Immutable subject claims for GitHub Actions OIDC tokens
回報錯字、失效連結,或告訴我你想看的延伸主題。