모든 GitHub Actions 워크플로 실행은 https://token.actions.githubusercontent.com에 있는 GitHub의 호스팅 발급자로부터 서명된 ID 토큰을 요청할 수 있습니다. "Workload Identity Federation"(워크로드 ID 페더레이션)을 사용하면 워크플로가 해당 토큰을 단기 Anthropic 액세스 토큰으로 교환하므로, 리포지토리에 ANTHROPIC_API_KEY 시크릿을 저장하지 않고도 CI 작업에서 Claude API를 호출할 수 있습니다.
토큰의 sub 클레임은 리포지토리와 트리거 컨텍스트를 인코딩합니다. 브랜치로의 푸시인 경우 repo:<owner>/<repo>:ref:refs/heads/<branch> 형식을 가집니다. 풀 리퀘스트 실행은 repo:<owner>/<repo>:pull_request를 사용하고, 환경 게이트 배포는 repo:<owner>/<repo>:environment:<name>을 사용합니다. 페더레이션 규칙은 이 클레임(및 repository_owner, ref와 같은 다른 클레임)과 매칭하여 어떤 워크플로 실행이 인증을 허용받을지 결정합니다.
id-token: write 권한을 부여할 수 있는 GitHub 리포지토리.GitHub는 명시적으로 요청하는 작업에만 ID 토큰을 발급합니다. 워크플로 또는 작업 수준에서 id-token: write 권한을 추가하세요:
permissions:
id-token: write
contents: read작업 내부에서 러너는 두 개의 환경 변수 ACTIONS_ID_TOKEN_REQUEST_URL과 ACTIONS_ID_TOKEN_REQUEST_TOKEN을 노출합니다. 요청 토큰을 베어러 자격 증명으로 사용하고 선택한 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-jwtJavaScript를 선호하는 경우, 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"
}sub 형식의 전체 목록은 GitHub의 OIDC subject 클레임 참조를 참조하세요.
설정 안내를 따라 Claude Console에서 페더레이션 발급자를 등록하고, Anthropic 서비스 계정을 생성하고, 페더레이션 규칙을 생성하세요. 다음 GitHub Actions 전용 값을 사용하세요.
페더레이션 발급자: GitHub는 OIDC 디스커버리 문서와 JWKS를 공개적으로 게시하므로 디스커버리 모드를 사용하세요. GitHub가 키를 교체하면 Anthropic이 자동으로 키를 새로 고칩니다.
{
"name": "github-actions",
"issuer_url": "https://token.actions.githubusercontent.com",
"jwks_source": "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
}워크로드가 허용하는 한 최대한 구체적으로 지정하세요. sub의 마지막 세그먼트가 ref:..., environment:..., pull_request 이벤트 간에 다르기 때문에, 규칙이 동일한 리포지토리의 여러 이벤트 유형과 매칭해야 하는 경우에만 subject_prefix를 repo:your-org/your-repo:*로 완화하세요(claims.ref 제약 조건과 함께 사용).
작업에 페더레이션 환경 변수를 설정하고 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-sonnet-4-6",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello, Claude"}],
)
print(message.content[0].text)GitHub에서 발급한 각 ID 토큰은 발급 후 약 5분 후에 만료됩니다. 토큰 요청 엔드포인트(ACTIONS_ID_TOKEN_REQUEST_URL)는 작업 전체 동안 유효하므로 언제든지 새 토큰을 가져올 수 있습니다. SDK는 첫 사용 시 토큰을 교환하고 결과로 받은 Anthropic 액세스 토큰을 캐시합니다. Anthropic 토큰의 수명보다 오래 실행되는 작업의 경우, SDK는 새로 고칠 때마다 ANTHROPIC_IDENTITY_TOKEN_FILE을 다시 읽으므로 파일을 최신 상태로 유지하려면 가져오기 단계를 주기적으로 다시 실행하세요(또는 백그라운드 루프로 감싸세요). 또는 파일 경로를 사용하는 대신 ACTIONS_ID_TOKEN_REQUEST_URL을 직접 호출하는 토큰 제공자 콜백을 SDK에 전달하세요.
교환이 성공하면 sk-ant-oat01-로 시작하는 access_token과 초 단위의 expires_in 값이 반환됩니다. 400 invalid_grant 오류가 발생하면 실패한 교환 문제 해결을 참조하세요. GitHub Actions 측에서 가장 흔한 원인은 sub 클레임 형식이 일치하지 않는 것입니다(마지막 세그먼트가 ref:..., environment:..., pull_request 이벤트 간에 다름).
repo:your-org/*만으로 구성된 subject_prefix는 조직의 모든 리포지토리와 매칭되며, ref 제약 조건이 없으면 포크에서 트리거된 pull_request 실행과도 매칭됩니다. 매칭되는 리포지토리에 대해 풀 리퀘스트를 열 수 있는 사람은 누구나 페더레이션된 Anthropic 토큰을 획득할 수 있습니다.
규칙의 match 블록을 사용 사례에 맞는 가장 좁은 범위로 제한하세요:
subject_prefix: "repo:your-org/your-repo:*"를 사용하여 조직의 다른 리포지토리가 매칭되지 않도록 하세요.claims 아래에 "ref": "refs/heads/main"(또는 릴리스 브랜치)을 추가하여 풀 리퀘스트 실행과 기능 브랜치가 매칭되지 않도록 하세요.sub 파싱 엣지 케이스에 대한 심층 방어 수단으로 claims 아래에 "repository_owner": "your-org"를 추가하세요.subject_prefix: "repo:your-org/your-repo:environment:production"과 매칭하고, GitHub에서 해당 환경에 필수 검토자를 설정하여 게이트를 적용하세요.Was this page helpful?