GitHub Actions→Azure 認証の実装手順!OIDC×Azure CLI で爆速セットアップ 2025年版

目次

はじめに

ども!久しぶりに公式ドキュメントをあさっていたら、自分が使っていた発行プロファイル認証が「not recommended」と記載されていてビックリ仰天した龍ちゃんです。

皆さん、GitHub Actions から Azure リソースにデプロイする際、どの認証方式を使っていますか?

「え、推奨されない方式だったの!?」って大焦りで調べたら、発行プロファイルは現在もサポートされているものの、セキュリティベストプラクティスとして OIDC 認証への移行が強く推奨されている ことが判明しました。

特に以下の理由から、Microsoft は OIDC 認証を推奨しています:

  • 発行プロファイルは Basic 認証を使用しており、セキュリティ上の懸念がある
  • 発行プロファイルには平文パスワードが含まれる
  • OIDC 認証はシークレットキー不要で、より安全

そこで、Microsoft 公式が推奨する OIDC(OpenID Connect)認証に直接移行したんですが、設定できるならこっちのほうが良いなとなったのでまとめていきます!

シークレットキー不要でパスワードレス認証ができて、セキュリティレベルが大幅に向上しました。

今回は、GitHub Actions から Azure への 3 つの認証方式を比較し、Azure CLI での爆速セットアップ方法を解説します!

この記事でわかること

Azure 認証方式 3 つの徹底比較(発行プロファイル vs Service Principal vs OIDC)
OIDC 認証の仕組みと他方式との違い
Azure CLI でのフェデレーション認証設定方法(コマンド実行)
GitHub Actions での汎用的な認証設定方法
必要な権限とその確認方法(超重要!)
トラブルシューティングの実例と解決方法

🎯 この記事の対象読者

以下のような方にお勧めです。

✅ Azure CLI の基本操作ができる方
✅ GitHub Actions から Azure にデプロイしたい方
✅ 発行プロファイルを使っていて、セキュアな方式に移行したい方
✅ シークレットキー管理の手間を減らしたい DevOps エンジニア
✅ ターミナル操作に抵抗がない方

なぜ Azure CLI を使うのか?

  • 爆速セットアップ: コピペで 5 分で完了
  • 🔄 再現性が高い: コマンドをスクリプト化できる
  • 📝 IaC 化しやすい: Bicep/Terraform への移行が容易

ポータルのポチポチ作業は不要です!

それでは、見ていきましょう!

はじめに – なぜ OIDC 認証が必要なのか?

GitHub Actions から Azure 認証の重要性

GitHub Actions から Azure Functions、Web Apps、Static Web Apps、Container Apps などにデプロイする際、Azure への認証が必要です。

この認証方式、実は3 つの選択肢があるんですよね:

  1. 発行プロファイル(Publish Profile)
  2. Service Principal + シークレットキー
  3. OIDC 認証(OpenID Connect)

並べた順に難しくなっていきます。結論から言うと、Microsoft 公式が推奨しているのは OIDC 認証です。

なぜ OIDC 認証が推奨されるのか、他の 2 つの方式と比較しながら見ていきましょう。

Azure 認証方式 3 つの徹底比較

実体験と移行の経緯

正直に言うと、私が実際に使ったことがあるのは「発行プロファイル」と「OIDC 認証」の 2 つだけです。

Service Principal は選択肢として存在しますが、セキュリティベストプラクティスとして OIDC 認証が推奨されていると分かった時点で、直接 OIDC 認証に移行しました

なぜ Service Principal をスキップしたかというと:

  1. シークレットキー管理の手間: Service Principal も結局シークレットキーが必要で、定期的なローテーション作業が発生する
  2. OIDC 認証が最終解: セキュリティベストプラクティスとして推奨されているなら、最初から OIDC 認証にした方が合理的
  3. 移行コスト: Service Principal に移行してから、さらに OIDC に移行するのは二度手間

つまり、「発行プロファイル → Service Principal(中間) → OIDC(推奨)」という段階を踏まず、最初から最終形態に移行したわけです。

ただし、Service Principal は歴史的経緯や他のプロジェクトで遭遇する可能性もあるので、選択肢として紹介しておきます。

それでは、3 つの方式を詳しく比較していきましょう!

1. 発行プロファイル方式(最も簡単だが、セキュリティ上推奨されない)

仕組み

発行プロファイル(Publish Profile)は、Azure ポータルからXML ファイルをダウンロードして、GitHub Secrets に保存する方式です。

Azure Portal → リソース → 発行プロファイルのダウンロード
          ↓
GitHub Secrets に AZURE_PUBLISH_PROFILE として保存
          ↓
GitHub Actions でデプロイ

コード例

# 発行プロファイル方式
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to Azure Functions
        uses: Azure/functions-action@v1
        with:
          app-name: "my-function-app"
          publish-profile: ${{ secrets.AZURE_PUBLISH_PROFILE }} # XML形式

発行プロファイルの中身(例):

<publishData>
  <publishProfile
    profileName="my-function-app - Web Deploy"
    publishMethod="MSDeploy"
    publishUrl="my-function-app.scm.azurewebsites.net:443"
    userName="$my-function-app"
    userPWD="verylongsecretpassword123..."  <!-- ← これが問題! -->
    ...
  />
</publishData>

メリット

設定が超簡単: Azure ポータルから 1 クリックでダウンロード
初心者にやさしい: 複雑な権限設定が不要
すぐに動く: 5 分で設定完了

デメリット

セキュリティリスク大: パスワードが平文で含まれる
Basic 認証を使用: Microsoft が「inherently insecure(本質的に安全でない)」と警告
監査ログ不足: 誰がデプロイしたか追跡困難
権限が広すぎる: リソース全体への管理者権限
ローテーション困難: パスワード更新が面倒
Microsoft 非推奨: セキュリティベストプラクティスとして OIDC 認証が推奨されている

⚠️ 重要な注意:
Microsoft 公式ドキュメントでは「The technique described in this article is inherently insecure, because this technology uses Basic Authentication」と明記されており、本番環境での使用は推奨されていません。学習目的や個人プロジェクトでの利用にとどめ、本番環境では OIDC 認証を採用することを強くお勧めします。

2. Service Principal + シークレットキー方式(従来の推奨)

仕組み

Azure AD で Service Principal(サービスプリンシパル)を作成し、Client Secret(シークレットキー) を発行して認証する方式です。

Azure AD → Service Principal作成
       ↓
Client Secret発行(有効期限: 最長2年)
       ↓
GitHub Secretsに保存
       ↓
GitHub Actionsで認証

コード例

# Service Principal + シークレットキー方式
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - name: Azure Login
        uses: azure/login@v2
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }} # JSON形式

AZURE_CREDENTIALS の中身(例):

{
  "clientId": "xxx-xxx-xxx",
  "clientSecret": "your-secret-key-here", // ← シークレットキー
  "subscriptionId": "xxx-xxx-xxx",
  "tenantId": "xxx-xxx-xxx"
}

Service Principal の作成方法

# Service Principal作成
az ad sp create-for-rbac \
  --name "github-actions-sp" \
  --role "Contributor" \
  --scopes "/subscriptions/{subscription-id}/resourceGroups/{resource-group}" \
  --sdk-auth

出力された JSON をそのまま GitHub Secrets に保存します。

メリット

RBAC 権限管理: 必要な権限のみ付与可能
監査ログ充実: Azure AD での詳細なログ
複数リソース対応: 1 つの Service Principal で複数リソースにアクセス
よく使われている: 情報が豊富

デメリット

シークレットキー管理: 定期的なローテーションが必要(有効期限: 最長 2 年)
漏洩リスク: シークレットキーが漏洩したら、全リソースにアクセス可能
管理コスト: 有効期限が切れたら、手動で更新が必要
GitHub Secrets に保存: 暗号化はされているが、アクセス可能

重要な補足: Service Principal でも OIDC 認証が可能

実は、Service Principal でも Federated Identity Credentials を使えば、シークレットキー不要の OIDC 認証が可能です。

つまり、以下の 2 つの方式は技術的には非常に類似しています:

  • Service Principal + Federated Credentials
  • Managed Identity + Federated Credentials(この記事で解説する方式)

主な違い:

  • Managed Identity: 常に Azure リソースに紐づけられる。Azure が自動的に認証情報を管理
  • Service Principal: Azure リソースに紐づけなくても独立して存在可能

なぜ Managed Identity を選んだか:

  • Azure リソース(Functions, Web Apps 等)にデプロイする場合、Managed Identity の方がシンプル
  • リソースとの紐付けが明確で、管理しやすい
  • Microsoft のベストプラクティスドキュメントでも Managed Identity が推奨されている

ただし、複数の Azure サブスクリプションをまたいでアクセスする必要がある場合など、Service Principal + Federated Credentials の方が適している場合もあります。

3. OIDC 認証方式(Microsoft 公式推奨)

仕組み

OIDC(OpenID Connect)認証は、短命なトークンを使った認証方式です。シークレットキーが一切不要なのが最大の特徴。

GitHub Actions → GitHub OIDCプロバイダー
              ↓
          OIDCトークン発行(5分間有効)
              ↓
          Azure AD → Federated Identity Credential検証
              ↓
          Managed Identity → Azureアクセストークン発行
              ↓
          Azureリソースにデプロイ

トークン有効期限の詳細:

  • GitHub OIDC トークン(JWT): 5 分間有効
  • Azure アクセストークン: 約60-90 分(平均 75 分、一般的には 1 時間として扱われる)
  • トークンの更新: Azure SDK/CLI が自動的に管理(手動更新不要)

コード例

# OIDC認証方式(推奨)
jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      id-token: write # ← OIDC認証に必須!
      contents: read
    steps:
      - name: Azure Login (OIDC)
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
          # シークレットキーは不要!

必要なシークレット(すべて識別子のみ):

AZURE_CLIENT_ID: xxx-xxx-xxx  (Managed IdentityのClient ID)
AZURE_TENANT_ID: xxx-xxx-xxx  (テナントID)
AZURE_SUBSCRIPTION_ID: xxx-xxx-xxx  (サブスクリプションID)

重要:
これらはすべて識別子のみで、シークレットキーは含まれていません。つまり、万が一漏洩しても、それだけでは Azure にアクセスできない仕組みです。

メリット

シークレットキー不要: パスワードレス認証でセキュリティリスク削減
自動ローテーション: GitHub の OIDC トークン(JWT)は 5 分間のみ有効、Azure のアクセストークンも自動管理(手動ローテーション不要)
漏洩リスク最小化: 識別子のみで、シークレットが存在しない
監査ログ充実: Azure AD での詳細な認証ログ
セキュリティベストプラクティス: Azure App Service 向けに公式推奨
リポジトリ・ブランチ制限: 特定の GitHub リポジトリ・ブランチからのみ認証可能

デメリット

初期設定がやや複雑: Azure ポータルでの設定が必要
理解に時間がかかる: OIDC の仕組みを理解する必要がある
権限が必要: Managed Identity 作成と RBAC 設定に管理者権限が必要

私の経験:
最初は「設定が複雑そう…」って敬遠していたんですが、一度設定してしまえば、その後の管理が超ラク!シークレットキーローテーションの手間がゼロになったのは感動しました。

イメージとしては、GitHub リポジトリ自体に認証の権限を割り振るという感じです。発行プロファイルや Service Principal のように「シークレットを GitHub Secrets に保存する」のではなく、「このリポジトリからの実行は信頼できる」と Azure 側で事前に承認しておくイメージですね。

3 つの認証方式 比較表

項目発行プロファイルService PrincipalOIDC 認証
セキュリティ❌ 低⚠️ 中✅ 高
設定の簡単さ✅ 超簡単⚠️ 普通⚠️ やや複雑
シークレット管理❌ パスワード必要❌ シークレットキー必要✅ 不要
ローテーション❌ 困難⚠️ 手動(年 1 回程度)✅ 完全自動(手動不要)
漏洩リスク❌ 高⚠️ 中✅ 最小
監査ログ❌ 不足✅ 充実✅ 充実
権限制御❌ 広すぎる✅ RBAC 可能✅ RBAC 可能
Microsoft 推奨❌ Not Recommended⚠️ サポート継続✅ ベストプラクティス
初期設定時間5 分15 分30 分
運用コスト⚠️ 中⚠️ 中✅ 低

どの方式を選ぶべきか?

結論: セキュアに運用したいのであればOIDC 認証一択です。

  • 個人プロジェクト・学習用: 発行プロファイルで素早くスタート → 慣れたら OIDC に移行
  • チーム開発・本番環境: 最初から OIDC 認証を採用

私も複数のプロジェクトで検証しましたが、長期的に見ると OIDC 認証が圧倒的にコストパフォーマンスが高いです。というか、発行プロファイルの管理が面倒くさかったです。再発行のたびに GitHub Secret に保存ってアプリが増えれば増えるほど面倒になるんですよね。特にモノレポ環境であれば、効果絶大です。

前提条件と必要な権限

必要な環境

OIDC 認証を設定するには、以下の環境が必要です:

  • Azure CLI: バージョン 2.30 以上(インストール方法は後述)
  • Azure サブスクリプション: Azure リソースをデプロイするため
  • GitHub リポジトリ: Admin 権限が必要(GitHub Secrets を設定するため)
  • ターミナル: Bash、PowerShell、または Zsh

Azure CLI のインストール確認

すでに Azure CLI がインストールされているか確認しましょう:

az version

出力例:

{
  "azure-cli": "2.50.0",
  "azure-cli-core": "2.50.0",
  "azure-cli-telemetry": "1.0.8",
  ...
}

まだインストールしていない場合

方法 1: ローカルマシンにインストール

macOS / Linux (Homebrew):

brew install azure-cli

Windows (winget):

winget install Microsoft.AzureCLI

その他のインストール方法: Azure CLI 公式ドキュメント

方法 2: DevContainer でチーム全体の環境を統一(オプション)

もし DevContainer を使って開発をしているなら、この方法も検討できます。DevContainer Features を使えば、チーム全体で同じバージョンの Azure CLI を使用でき、環境差異によるトラブルを防げます。

注意: Docker Desktop のライセンスや、企業のセキュリティポリシーによる制約がある場合は、ローカルインストールをお勧めします。

.devcontainer/devcontainer.json:

{
  "name": "Azure Development",
  "image": "mcr.microsoft.com/devcontainers/base:bullseye",
  "features": {
    "ghcr.io/devcontainers/features/azure-cli:1": {
      "version": "latest"
    }
  }
}

メリット:

  • チーム全員が同じ環境で作業可能
  • 新メンバーのオンボーディングが簡単(コンテナ起動するだけ)
  • CI/CD 環境とローカル環境の差異をなくせる

詳しい手順: DevContainer と Azure CLI の詳細な環境構築手順は、別記事「DevContainer 実践入門:Azure CLI+GitHub CLI 環境をチーム全体で統一」で解説しています。Azure CLI、GitHub CLI、SWA CLI を統一環境として構築する方法を紹介しているので、ぜひご覧ください。

Azure へのログイン

Azure CLI で Azure にログインします:

az login

ブラウザが開くので、Azure アカウントでログインしてください。

ログイン確認:

az account show

出力例:

{
  "id": "xxx-xxx-xxx-xxx",
  "name": "Pay-As-You-Go",
  "tenantId": "xxx-xxx-xxx-xxx",
  "user": {
    "name": "user@example.com",
    "type": "user"
  }
}

必要な権限(超重要!)

ここが一番重要なポイントです。

OIDC 認証設定とフェデレーション認証の設定には、かなり強い権限が必要です。

私も最初、権限不足でエラーに悩まされて、Azure の管理者に 3 回も確認とお願いの申請をしました…。社内の担当者には本当に頭が上がりません。

なので、設定前に必ず権限を確認しておくことを強くオススメします

最小権限セット

以下の操作を実行するには、それぞれ対応する権限が必要です:

  1. User Assigned Managed Identity の作成:
    • Microsoft.ManagedIdentity/userAssignedIdentities/write
    • Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials/write
  2. RBAC 権限割り当て:
    • Microsoft.Authorization/roleAssignments/write
    • これはリソースグループレベルの「所有者」または「ユーザーアクセス管理者」ロールが必要
  3. リソースデプロイ全般:
    • Microsoft.Resources/deployments/write

推奨ロール

リソースグループレベルの「所有者」ロールが最も簡単です。

もしくは、以下の組み合わせ:

  • 共同作成者 (Contributor) + ユーザーアクセス管理者 (User Access Administrator)

私の場合、リソースグループの所有者権限を割り振ってもらいました。

権限確認方法

Azure CLI で現在のユーザーの権限を確認します:

# リソースグループを変数に設定(後で使います)
RESOURCE_GROUP="rg-example"  # 実際のリソースグループ名に置き換え

# 自分のロール割り当てを確認
az role assignment list \
  --resource-group $RESOURCE_GROUP \
  --query "[].{Principal:principalName, Role:roleDefinitionName, Scope:scope}" \
  --output table

期待される出力:

Principal             Role    Scope
--------------------  ------  ----------------------------------------
user@example.com      Owner   /subscriptions/.../resourceGroups/rg-example

「Owner」ロールが表示されていれば OK!

もし Owner ロールがない場合は、以下のいずれかを確認してください:

  • Contributor + User Access Administrator の組み合わせ
  • サブスクリプションレベルでの Owner ロール

権限が不足している場合の対処

管理者に権限を依頼する

権限が不足している場合は、以下のテンプレートで管理者に依頼しましょう。(こういう時の AI はマジで頼りになりますよね。)

件名: リソースグループへの所有者ロール付与依頼

以下のリソースグループに対して「所有者」ロールを付与してください:
- リソースグループ名: <RESOURCE_GROUP_NAME>
- 理由: GitHub OIDC認証設定とAzureリソースデプロイのため

必要な具体的な操作:
1. User Assigned Managed Identityの作成
2. Federated Identity Credentialの設定
3. RBAC権限割り当て

よろしくお願いいたします。

ポイント:
権限確認は設定前に必ず実施しましょう。

途中でエラーになると、中途半端な状態で止まってしまい、トラブルシューティングが超面倒です。

さらに、誰もメンテナンスしていない Managed Identity やロールが作られてしまい、後から担当者に「これ何に使ってるんですか?」って確認が飛んでくる可能性もあります…(察してください…)。

OIDC 認証の仕組み詳細

OIDC 認証フロー

sequenceDiagram
    participant GHA as GitHub Actions
    participant GitHub as GitHub OIDC Provider
    participant Azure as Azure AD
    participant MI as Managed Identity
    participant Resources as Azure Resources

    GHA->>GitHub: 1. Request OIDC Token
    GitHub->>GHA: 2. Issue OIDC Token (15min)
    GHA->>Azure: 3. Exchange Token
    Note right of GHA: client-id, tenant-id, subscription-id
    Azure->>Azure: 4. Verify Federated Credential
    Note right of Azure: issuer, subject, audiences
    Azure->>MI: 5. Validate Managed Identity
    MI->>Azure: 6. Issue Azure Access Token
    GHA->>Resources: 7. Access Azure Resources
    Resources->>GHA: 8. Operation Success

フローの詳細解説

  1. GitHub Actions が OIDC トークンをリクエスト:
    • ワークフローにpermissions.id-token: writeを設定
    • GitHub Actions が自動的に GitHub OIDC プロバイダーにリクエスト
  2. GitHub が OIDC トークン(JWT)を発行:
    • リポジトリ、ブランチ、環境などの情報を含む JWT トークンを発行
    • 有効期限: 5 分間(非常に短命で安全)
  3. Azure にトークンを Exchange(交換):
    • azure/login@v2アクションが自動的に実行
    • Client ID、Tenant ID、Subscription ID を使用
    • ここが OIDC 認証の魔法のポイント!  GitHub Actions 上で発行したトークンを Azure 上のアクセストークンに交換しています
  4. Azure がフェデレーション認証情報を検証:
    • issuer: https://token.actions.githubusercontent.com(GitHub 固定)
    • subject: repo:{org}/{repo}:environment:production(設定したパターン)
    • audiences: api://AzureADTokenExchange(Azure 固定)
  5. Managed Identity を検証:
    • Azure AD が Managed Identity の存在を確認
    • RBAC 権限を確認
  6. Azure アクセストークンを発行:
    • GitHub Actions が使用できる Azure アクセストークンを発行
  7. Azure リソースにアクセス:
    • Azure Functions、Web Apps などにデプロイまたはアクセス
  8. 操作成功:
    • 結果を GitHub Actions に返す

なぜシークレットキー不要なのか?

OIDC 認証の魔法は、GitHub と Azure の信頼関係(Trust Relationship) にあります。

従来方式:

GitHub Actions → シークレットキー提示 → Azure「認証OK」

OIDC 認証:

GitHub Actions → OIDCトークン提示 → Azure「このトークン、本当にGitHubが発行した?」
                                  ↓
                         Federated Identity Credentialで検証
                                  ↓
                         「リポジトリ・ブランチも一致!」→ 認証OK

ポイント:

  • GitHub の OIDC トークン(JWT)は5 分間のみ有効(非常に短命で安全)
  • Azure が発行するアクセストークンは約60-90 分有効(Azure SDK/CLI が自動管理)
  • 特定のリポジトリ・ブランチからのみ認証可能(Federated Identity Credential で制限)
  • トークン自体がGitHub の署名付きで、改ざん不可能

つまり、シークレットキーを保存しなくても、「この GitHub Actions の実行は、確かに信頼できるリポジトリからのものだ」と証明できるわけです!

Azure CLI での爆速セットアップ

それでは、Azure CLI を使って OIDC 認証を設定していきましょう!

所要時間: 約 5 分(コピペで完結)

ステップは全部で 3 つです:

  1. User Assigned Managed Identity 作成
  2. Federated Identity Credential 設定
  3. RBAC 権限設定

事前準備: 環境変数の設定

まず、これから使う変数をまとめて設定しておきます。コピペで使えるように、実際の値に置き換えてください:

# プロジェクト設定
APP_NAME="myapp"                    # アプリケーション名(任意)
RESOURCE_GROUP="rg-example"         # 既存のリソースグループ名
LOCATION="japaneast"                # リージョン

# GitHub設定
GITHUB_ORG="your-org"               # GitHub組織名またはユーザー名
GITHUB_REPO="your-repo"             # GitHubリポジトリ名

# Managed Identity名
IDENTITY_NAME="${APP_NAME}-github-identity"

確認:

echo "Identity名: $IDENTITY_NAME"
echo "リソースグループ: $RESOURCE_GROUP"

ステップ 1: User Assigned Managed Identity 作成

GitHub からの認証を受け入れる Managed Identity を作成します。

az identity create \
  --name $IDENTITY_NAME \
  --resource-group $RESOURCE_GROUP \
  --location $LOCATION

実行結果(例):

{
  "clientId": "xxx-xxx-xxx-xxx-xxx",
  "id": "/subscriptions/.../resourceGroups/rg-example/providers/Microsoft.ManagedIdentity/userAssignedIdentities/myapp-github-identity",
  "location": "japaneast",
  "name": "myapp-github-identity",
  "principalId": "yyy-yyy-yyy-yyy-yyy",
  "resourceGroup": "rg-example",
  "type": "Microsoft.ManagedIdentity/userAssignedIdentities"
}

重要な情報を変数に保存:

# Client IDとPrincipal IDを取得して変数に保存
CLIENT_ID=$(az identity show \
  --name $IDENTITY_NAME \
  --resource-group $RESOURCE_GROUP \
  --query clientId -o tsv)

PRINCIPAL_ID=$(az identity show \
  --name $IDENTITY_NAME \
  --resource-group $RESOURCE_GROUP \
  --query principalId -o tsv)

echo "Client ID: $CLIENT_ID"
echo "Principal ID: $PRINCIPAL_ID"

この Client ID は後で GitHub Secrets に設定します。メモしておきましょう!

結果確認(Azure ポータル):

ステップ 2: Federated Identity Credential 設定

次に、GitHub リポジトリと Managed Identity を紐づける「フェデレーション認証情報」を設定します。

これが超重要なセクションです!

subject パターンの選択

Federated Identity Credential には、「どの GitHub リポジトリ・ブランチ・環境から認証を許可するか」を指定するsubjectというフィールドがあります。

主要な subject パターン:

パターンsubject 形式使用例
production 環境(推奨)repo:{org}/{repo}:environment:production本番環境デプロイ
main ブランチrepo:{org}/{repo}:ref:refs/heads/main基本的な CI/CD
タグrepo:{org}/{repo}:ref:refs/tags/v*リリースデプロイ
Pull Requestrepo:{org}/{repo}:pull_requestPR 環境デプロイ

私の場合、production 環境パターンを使っています。理由は以下の通り:

✅ GitHub Actions のenvironment機能と連携できる
✅ 環境ごとに異なる Secrets・Variables を管理できる
✅ 「本番環境へのデプロイ」という意図が明確

production 環境の Federated Credential 作成

az identity federated-credential create \
  --name github-federated-production \
  --identity-name $IDENTITY_NAME \
  --resource-group $RESOURCE_GROUP \
  --issuer "https://token.actions.githubusercontent.com" \
  --subject "repo:${GITHUB_ORG}/${GITHUB_REPO}:environment:production" \
  --audiences "api://AzureADTokenExchange"

実行結果(例):

{
  "audiences": ["api://AzureADTokenExchange"],
  "issuer": "https://token.actions.githubusercontent.com",
  "name": "github-federated-production",
  "resourceGroup": "rg-example",
  "subject": "repo:your-org/your-repo:environment:production",
  "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials"
}

ポイント:

  • --subjectrepo:your-org/your-repo:environment:production 部分が、GitHub Actions ワークフローの environment: "production" と一致します
  • --audiences は固定値(api://AzureADTokenExchange
  • --issuer も固定値(https://token.actions.githubusercontent.com

⚠️ 重要: 環境名の大文字小文字

GitHub Actions は環境名を自動的に小文字に変換して Subject クレームを生成します。

  • GitHub 環境名: Production(大文字)
  • 実際の Subject: repo:org/repo:environment:production小文字

Subject 設定時は必ず小文字で指定してください。大文字小文字が一致しないとAADSTS70021エラーが発生します。

main ブランチの Federated Credential も追加する場合

az identity federated-credential create \
  --name github-federated-main \
  --identity-name $IDENTITY_NAME \
  --resource-group $RESOURCE_GROUP \
  --issuer "https://token.actions.githubusercontent.com" \
  --subject "repo:${GITHUB_ORG}/${GITHUB_REPO}:ref:refs/heads/main" \
  --audiences "api://AzureADTokenExchange"

これで、production 環境と main ブランチの両方からデプロイできるようになります!

設定確認

作成した Federated Credential を確認しましょう:

az identity federated-credential list \
  --identity-name $IDENTITY_NAME \
  --resource-group $RESOURCE_GROUP \
  --query "[].{Name:name, Subject:subject}" \
  --output table

出力例:

Name                          Subject
----------------------------  ---------------------------------------------------------
github-federated-production   repo:your-org/your-repo:environment:production
github-federated-main         repo:your-org/your-repo:ref:refs/heads/main

結果確認(Azure ポータル):

⚠️ Federated Credential の制限事項

  • 数量制限: 1 つの Managed Identity あたり最大 20 個
  • 完全一致のみ: Subject はワイルドカード不可(完全一致のみサポート)

大規模プロジェクトで複数のリポジトリ・環境を管理する場合は、用途別に複数の Managed Identity を作成することを推奨します。

ステップ 3: RBAC 権限設定

Managed Identity を作成しただけでは、Azure リソースにアクセスできません。

RBAC(Role-Based Access Control)で権限を付与する必要があります。

どのロールを付与するか?

デプロイ対象の Azure サービスによって、必要なロールが異なります。

Azure サービス推奨ロールスコープ
Azure FunctionsWebsite Contributorリソースグループまたは個別リソース
Azure Web AppsWebsite Contributorリソースグループまたは個別リソース
Azure Static Web AppsWebsite Contributorリソースグループまたは個別リソース
Azure Container AppsContributorリソースグループまたは個別リソース
複数サービスWebsite Contributorリソースグループ(推奨)

私の場合: リソースグループスコープでWebsite Contributorロールを付与しています。

理由:

  • Functions、Web Apps、Static Web Apps 全体をカバー
  • 管理が簡単(個別リソースごとに設定する必要がない)
  • 最小権限の原則に従いつつ、実用的

RBAC 権限の付与

リソースグループスコープでWebsite Contributorロールを付与します:

# リソースグループのIDを取得
RESOURCE_GROUP_ID=$(az group show \
  --name $RESOURCE_GROUP \
  --query id -o tsv)

# Website Contributorロールを割り当て
az role assignment create \
  --assignee $PRINCIPAL_ID \
  --role "Website Contributor" \
  --scope $RESOURCE_GROUP_ID

実行結果(例):

{
  "principalId": "yyy-yyy-yyy-yyy-yyy",
  "principalType": "ServicePrincipal",
  "roleDefinitionName": "Website Contributor",
  "scope": "/subscriptions/.../resourceGroups/rg-example",
  "type": "Microsoft.Authorization/roleAssignments"
}

⚠️ 重要: 権限の伝播時間

ロール割り当て直後は、権限が有効になるまで最大 5 分間かかる場合があります。

推奨アクション:

  • 割り当て後、数分待ってからデプロイを実行
  • 初回デプロイ時に権限エラーが発生した場合は、5 分後に再試行

設定確認

RBAC 権限が正しく付与されたか確認しましょう:

az role assignment list \
  --assignee $PRINCIPAL_ID \
  --resource-group $RESOURCE_GROUP \
  --query "[].{Principal:principalId, Role:roleDefinitionName, Scope:scope}" \
  --output table

出力例:

Principal                            Role                 Scope
-----------------------------------  -------------------  ----------------------------------------
yyy-yyy-yyy-yyy-yyy                  Website Contributor  /subscriptions/.../resourceGroups/rg-example

Website Contributorロールが表示されていれば OK!

結果確認(Azure ポータル):


🎉 これで Azure 側の設定は完了です!

たった 3 つのコマンド(Identity 作成、Federated Credential 設定、RBAC 付与)でセットアップ完了です。

GitHub Actions での認証設定

Azure CLI での設定が完了したら、次は GitHub Actions ワークフローを設定します。

GitHub Secrets の設定

まず、OIDC 認証に必要な 3 つのシークレットを GitHub Secrets に設定します。

必要な値を取得

すでに Azure CLI で取得した値を確認しましょう:

# 1. Client ID(すでに取得済み)
echo "AZURE_CLIENT_ID: $CLIENT_ID"

# 2. Tenant ID
TENANT_ID=$(az account show --query tenantId -o tsv)
echo "AZURE_TENANT_ID: $TENANT_ID"

# 3. Subscription ID
SUBSCRIPTION_ID=$(az account show --query id -o tsv)
echo "AZURE_SUBSCRIPTION_ID: $SUBSCRIPTION_ID"

これらの値をメモしておきましょう!

GitHub Secrets に手動で設定

GitHub リポジトリで以下のシークレットを設定します:

  1. GitHub リポジトリ → Settings → Secrets and variables → Actions
  2. New repository secret をクリック
  3. 以下の 3 つのシークレットを追加:
NameValue
AZURE_CLIENT_ID上記で取得した Client ID
AZURE_TENANT_ID上記で取得した Tenant ID
AZURE_SUBSCRIPTION_ID上記で取得した Subscription ID

ポイント:
これらのシークレットはすべて識別子のみで、シークレットキーは含まれていません。つまり、万が一漏洩しても、それだけでは Azure にアクセスできない仕組みになっています。

基本的なワークフロー構成

OIDC 認証を使うには、以下の 3 つが必須です:

  1. permissions.id-token: write: GitHub Actions が OIDC トークンを発行できるようにする
  2. azure/login@v2アクション: OIDC トークンを Azure アクセストークンに交換
  3. GitHub Secrets 設定: CLIENT_ID、TENANT_ID、SUBSCRIPTION_ID

基本テンプレート

name: Deploy to Azure

on:
  push:
    branches:
      - main
  workflow_dispatch:

permissions:
  id-token: write # ← OIDC認証に必須!
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-latest
    environment: "production" # ← production環境を指定

    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Azure Login (OIDC)
        uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
          # シークレットキーは不要!

      - name: Azure CLI - リソース一覧表示(動作確認)
        run: |
          az resource list --resource-group <RESOURCE_GROUP_NAME> --output table

ポイント解説:

  1. permissions.id-token: write:
    • これがないと、OIDC トークンが発行されない
    • GitHub Actions の重要な設定
  2. environment: "production":
    • Federated Identity Credential のsubjectで指定した環境と一致させる
    • Azure ポータルで設定した環境名と同じにする
  3. azure/login@v2アクション:
    • client-idtenant-idsubscription-idの 3 つだけで OK
    • シークレットキーは不要

トラブルシューティング

OIDC 認証でよくあるエラーと解決方法をまとめます。

エラー 1: OIDC token exchange failed

症状:

Error: Login failed with Error: OIDC token exchange failed. Please check the following:
- Federated credentials are correctly configured
- The subject claim in the OIDC token matches the subject in the federated credential

原因:
Federated Identity Credential のsubjectパターンが、GitHub Actions の実行環境と一致していない。

解決方法:

1. Azure ポータルで subject を確認

  • Managed Identity のフェデレーション資格情報を開く
  • 設定した資格情報のサブジェクトを確認

:

subject: repo:your-org/your-repo:environment:production

2. GitHub Actions ワークフローの環境を確認

jobs:
  deploy:
    environment: "production" # ← ここが一致しているか確認

3. 一致しない場合の修正

パターン A: ワークフロー側を修正

# Azure側が environment:production なら
jobs:
  deploy:
    environment: "production" # ← これに変更

パターン B: Azure 側を修正

  • Azure ポータルで、フェデレーション資格情報を再作成
  • ワークフローに合わせたエンティティ型を選択

エラー 2: permissions.id-token: write がない

症状:

Error: Unable to get ACTIONS_ID_TOKEN_REQUEST_URL

原因:
GitHub Actions ワークフローにpermissions.id-token: writeが設定されていない。

解決方法:

ワークフローファイルにpermissionsセクションを追加します。

permissions:
  id-token: write # ← これを追加
  contents: read

jobs:
  deploy:
    # ...

注意:

  • permissionsは job レベルではなく、ワークフローのトップレベルに記述

エラー 3: GitHub Secrets が設定されていない

症状:

Error: Input required and not supplied: client-id

原因:
AZURE_CLIENT_IDなどの GitHub Secrets が設定されていない。

解決方法:

1. GitHub Secrets を確認

GitHub リポジトリのSettings → Secrets and variables → Actionsで、以下のシークレットが設定されているか確認:

  • AZURE_CLIENT_ID
  • AZURE_TENANT_ID
  • AZURE_SUBSCRIPTION_ID

2. 設定されていない場合は追加

上記の「GitHub Secrets の設定」セクションを参照して、3 つのシークレットを追加してください。

デバッグ Tips

GitHub Actions ログでの確認ポイント

  1. OIDC トークン発行成功:
   Federated token successfully exchanged.
  1. Azure Login 成功:
   Login successful.
  1. デプロイ成功:
   Deployment successful.

これらのメッセージが確認できれば、OIDC 認証は正常に動作しています!

番外編: Unknown Principal の削除方法

OIDC 認証の設定中に、Managed Identity を作り直したり削除したりすると、ロール割り当てだけが残ってしまうことがあります。

このような場合、Azure ポータルで権限を確認すると「Unknown Principal」として表示され、通常の方法では削除できません。

詳しい解決方法は別記事で解説しています:

📝 「Cannot find user or service principal」エラー解決!Azure RBAC の正しい削除方法

この記事では以下を詳しく解説しています:

  • Unknown Principal が発生する原因と Azure の仕様
  • プリンシパル ID では削除できない理由(エラーメッセージの解説)
  • 割り当て ID(Assignment ID)を使った正しい削除方法
  • 実務での推奨運用フローとセキュリティ対策

OIDC 認証の設定前にクリーンアップしておくと、後々のトラブルシューティングが楽になりますので、ぜひご参照ください!

まとめ

お疲れさまでした!長い記事でしたが、最後までお読みいただきありがとうございます。

3 つの認証方式の再確認

今回の記事で、GitHub Actions から Azure への3 つの認証方式を徹底比較しました:

  1. 発行プロファイル: ⚠️ 簡単で引き続きサポート(セキュリティリスクあり)
  2. Service Principal + シークレットキー: ⚠️ 従来推奨(管理コストが高い)
  3. OIDC 認証: ✅ セキュリティベストプラクティス(パスワードレスで安全)

OIDC 認証で得られる 3 つの大きなメリット

シークレットキー不要: パスワードレス認証でセキュリティリスク削減
自動ローテーション: GitHub の OIDC トークン(JWT)は 5 分間のみ有効、Azure のアクセストークンも自動管理(手動ローテーション不要)
監査ログ充実: Azure AD での詳細な認証ログ(どのリポジトリ・ブランチからデプロイされたかが記録)で、コンプライアンス対応も万全

この記事で実装したこと

今回の記事では、以下の実装を解説しました:

  1. 3 つの認証方式の徹底比較(発行プロファイル、Service Principal、OIDC)
  2. Azure ポータルでの画面操作による OIDC 認証設定
  3. User Assigned Managed Identity 作成
  4. Federated Identity Credential 設定(複数 subject パターン対応)
  5. RBAC 権限設定のベストプラクティス
  6. GitHub Secrets の設定方法(画面操作)
  7. GitHub Actions での汎用的な認証設定方法
  8. トラブルシューティング(よくあるエラーと解決方法)

特に、「3 つの認証方式の比較」と「Azure ポータルでの画面操作による設定」のセクションは超重要です。

セキュリティ面での改善効果

私の場合、Azure Functions のデプロイで発行プロファイル方式を使っていて、以下のような課題がありました:

❌ XML ファイル内に平文パスワードが含まれるセキュリティリスク
❌ GitHub Secrets に長期間有効な認証情報を保存
❌ 発行プロファイルの再生成・更新作業が必要
GitHub Actions で非推奨表示が出てびっくり

発行プロファイル → OIDC 認証に直接移行してから:

✅ シークレットキー管理の手間が完全にゼロ
✅ セキュリティリスクが大幅に削減(平文パスワード不要)
✅ GitHub の OIDC トークン(JWT)は 5 分間のみ有効、Azure のアクセストークンも自動管理(手動ローテーション不要)
✅ 監査ログでの認証履歴が明確(どのリポジトリ・ブランチからデプロイされたかが記録される)

Service Principal を経由せず、最初から最終形態の OIDC 認証に移行したので、二度手間を避けられました。セキュリティレベルの大幅向上と、今後の管理コストの削減を実現できました。

次のステップ

この記事で OIDC 認証の基本は理解できたと思います。次は以下にチャレンジしてみてください!

  1. 複数環境対応: dev、staging、production の 3 環境で Federated Identity Credential を分ける
  2. 監視・アラート設定: Application Insights でデプロイ成功・失敗を監視
  3. 自動テスト統合: GitHub Actions で CI/CD パイプラインを拡張
  4. Infrastructure as Code: Bicep IaC で設定を自動化(上級者向け)

特に、「複数環境対応」は本番運用では必須です。環境ごとに異なる Federated Identity Credential を設定することで、誤って本番環境にデプロイするリスクを防げます。

龍ちゃんの所感

GitHub Actions から Azure にデプロイする際、「発行プロファイルが簡単だから、それでいいや」って思っていた方、私と同じように「Deprecated」って表示されてびっくりする前に、ぜひ OIDC 認証にチャレンジしてみてください!

私も最初は「設定がややこしそう…Service Principal とか経由した方がいいのかな?」って思ったんですが、いきなり OIDC 認証に移行して正解でした

この記事の手順通りに進めれば、Azure CLI と Azure ポータルの画面操作で設定できます。

一度設定してしまえば、その後の管理が超ラク!

シークレットキーのローテーション作業から解放されて、セキュリティレベルも向上する。

Microsoft 公式が推奨している方式なので、セキュリティ面でも信頼性が高く、今後のデプロイのスタンダードになっていくはずです。

質問や「こんなエラーが出た!」などの困りごとがあれば、ぜひコメント欄で教えてください。一緒に解決していきましょう!

それでは、セキュアで楽な Azure デプロイライフを!

参考リンク

公式ドキュメント

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です