搭配 GitHub Actions 使用 WIF
使用短期身分權杖而非長期 API 金鑰,讓 GitHub Actions 工作流程向 Claude API 進行驗證。
每一次 GitHub Actions 工作流程執行都可以向 GitHub 託管的簽發者 https://token.actions.githubusercontent.com 請求一個已簽署的身分權杖。透過「Workload Identity Federation」(工作負載身分聯合),即 WIF,您的工作流程可將該權杖交換為短期的 Anthropic 存取權杖,如此一來您的 CI 作業便能呼叫 Claude API,而無需在儲存庫中存放 ANTHROPIC_API_KEY 密鑰。
權杖的 sub 宣告(claim)編碼了儲存庫與觸發情境。對於推送至分支的情況,其格式為 repo:<owner>/<repo>:ref:refs/heads/<branch>。Pull request 執行使用 repo:<owner>/<repo>:pull_request,而受環境管控的部署則使用 repo:<owner>/<repo>:environment:<name>。您的聯合規則會比對此宣告(以及其他宣告,例如 repository_owner 與 ref),以決定哪些工作流程執行被允許進行驗證。
先決條件
- 熟悉 WIF 概念:服務帳戶(service accounts)、聯合簽發者(federation issuers)與聯合規則(federation rules)。
- 一個您可以編輯工作流程檔案並授予
id-token: write權限的 GitHub 儲存庫。 - 在 Claude Console 中為您的 Anthropic 組織建立服務帳戶、聯合簽發者與聯合規則的權限。
- 您的 Anthropic 組織 ID。您可以在 Claude Console 的 Settings → Organization 下找到它。
設定您的工作流程
GitHub 只會向明確請求的作業簽發身分權杖。請在工作流程或作業層級新增 id-token: write 權限:
permissions:
id-token: write
contents: read在作業內部,執行器(runner)會公開兩個環境變數:ACTIONS_ID_TOKEN_REQUEST_URL 與 ACTIONS_ID_TOKEN_REQUEST_TOKEN。以請求權杖作為 bearer 憑證、並以您選擇的 audience 作為查詢參數來呼叫請求 URL,然後將回傳的「JSON Web Token」(JSON 網路權杖),即 JWT,寫入檔案:
- name: Fetch GitHub OIDC token
run: |
curl -sS -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=https://api.anthropic.com" \
| jq -r .value > /tmp/gha-jwt如果您偏好 JavaScript,actions/github-script 透過 core.getIDToken(audience) 提供相同的功能:
- name: Fetch GitHub OIDC token
uses: actions/github-script@v8
with:
script: |
const fs = require('fs');
const token = await core.getIDToken('https://api.anthropic.com');
fs.writeFileSync('/tmp/gha-jwt', token);解碼後的權杖帶有描述該次工作流程執行的宣告。您的聯合規則會比對這些宣告:
{
"iss": "https://token.actions.githubusercontent.com",
"sub": "repo:your-org/your-repo:ref:refs/heads/main",
"aud": "https://api.anthropic.com",
"repository": "your-org/your-repo",
"repository_owner": "your-org",
"ref": "refs/heads/main",
"sha": "abc123...",
"workflow": "CI",
"actor": "octocat",
"event_name": "push"
}請參閱 GitHub 的 OIDC subject 宣告參考文件以取得 sub 格式的完整清單。
設定 Anthropic
在 Claude Console 中,開啟 Settings → Workload identity,點擊 Connect workload,然後選擇 GitHub Actions 圖塊。精靈會引導您完成註冊簽發者、建立服務帳戶以及建立聯合規則。
精靈會為您建立這些資源。無論您是在精靈中輸入這些值,還是將它們傳送至 Admin API,請使用下列值:
聯合簽發者: GitHub 公開發布其 OIDC 探索文件與 JWKS,因此請使用探索模式(discovery mode)。當 GitHub 輪替金鑰時,Anthropic 會自動重新整理金鑰。
{
"name": "github-actions",
"issuer_url": "https://token.actions.githubusercontent.com",
"jwks": { "type": "discovery" }
}聯合規則: 僅比對您打算信任的工作流程執行。請參閱限制哪些工作流程可以進行驗證以了解如何安全地限定這些宣告的範圍。
{
"name": "gha-main",
"issuer_id": "fdis_...",
"match": {
"subject_prefix": "repo:your-org/your-repo:ref:refs/heads/main",
"audience": "https://api.anthropic.com",
"claims": {
"repository_owner": "your-org"
}
},
"target": {
"type": "service_account",
"service_account_id": "svac_..."
},
"workspace_id": "wrkspc_...",
"oauth_scope": "workspace:developer",
"token_lifetime_seconds": 600
}請在工作負載允許的範圍內盡可能具體。僅當規則必須比對來自同一儲存庫的多種事件類型時,才將 subject_prefix 放寬為 repo:your-org/your-repo:*(並搭配 claims.ref 限制條件),因為 sub 的尾段在 ref:...、environment:... 與 pull_request 事件之間會有所不同。
取得並使用權杖
在作業上設定聯合環境變數,然後照常呼叫 SDK。Anthropic() 會讀取 ANTHROPIC_IDENTITY_TOKEN_FILE,在第一次請求時交換 JWT,並在存取權杖到期前自動重新整理。
import anthropic
# 從作業環境讀取 ANTHROPIC_FEDERATION_RULE_ID、ANTHROPIC_ORGANIZATION_ID、
# ANTHROPIC_SERVICE_ACCOUNT_ID、ANTHROPIC_WORKSPACE_ID 以及 ANTHROPIC_IDENTITY_TOKEN_FILE
# 等環境變數。
client = anthropic.Anthropic()
message = client.messages.create(
model="claude-opus-5",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello, Claude"}],
)
print(next(block.text for block in message.content if block.type == "text"))每個由 GitHub 簽發的身分權杖大約在簽發後五分鐘到期。權杖請求端點(ACTIONS_ID_TOKEN_REQUEST_URL)在整個作業期間都保持有效,因此您可以在任何時間點取得新的權杖。SDK 會在首次使用時交換權杖,並快取所產生的 Anthropic 存取權杖。對於執行時間超過 Anthropic 權杖有效期的作業,SDK 會在每次重新整理時重新讀取 ANTHROPIC_IDENTITY_TOKEN_FILE,因此請定期重新執行取得步驟(或將其包裝在背景迴圈中)以保持檔案為最新狀態。或者,您也可以向 SDK 傳入一個直接呼叫 ACTIONS_ID_TOKEN_REQUEST_URL 的權杖提供者回呼函式,而非使用檔案路徑。
驗證設定
成功的交換會回傳一個以 sk-ant-oat01- 開頭的 access_token,以及一個以秒為單位的 expires_in 值。被拒絕的交換則會回傳一個不透明的 401 authentication_error,並附帶固定訊息 Authentication failed,無論是哪一項檢查失敗皆然;在大多數情況下,拒絕原因會記錄在驗證歷史頁面中該次嘗試的項目上,而疑難排解失敗的交換會依序逐一說明各項檢查。GitHub Actions 端最常見的原因是 sub 宣告格式不符(其尾段在 ref:...、environment:... 與 pull_request 事件之間會有所不同);歷史項目會顯示原因 match_subject_prefix。
限制哪些工作流程可以進行驗證
請將規則的 match 區塊鎖定在符合您使用情境的最小範圍:
- 固定至單一儲存庫: 使用
subject_prefix: "repo:your-org/your-repo:*",使組織中的其他儲存庫不會被比對到。 - 固定至受保護的分支: 在
claims下新增"ref": "refs/heads/main"(或您的發行分支),使 pull request 執行與功能分支不會被比對到。 - 明確固定擁有者: 在
claims下新增"repository_owner": "your-org",作為針對sub解析邊界情況的縱深防禦檢查。 - 固定至部署環境: 對於部署作業,比對
subject_prefix: "repo:your-org/your-repo:environment:production",並在 GitHub 中以必要審查者來管控該環境。
後續步驟
- Workload Identity Federation:完整的設定逐步說明、環境變數與憑證優先順序。
- 驗證:聯合與 API 金鑰的比較。
Was this page helpful?