Azure App Service の Kudu/SCM エンドポイントを curl、独自スクリプト、CI/CD、拡張機能から直接呼び出している場合は、認証トークンの取得方法を確認してください。2026年5月5日にマージされた Microsoft の vscode-azuretools 向け変更では、Kudu/SCM への直接呼び出しで ARM 管理 API 向けトークンではなく、App Service 専用の OAuth2 audience を使う方針が示されています。従来のように https://management.azure.com/ 向けのトークンを流用している実装は、将来的に失敗する可能性があります。(GitHub)
この記事では、Azure App Service の Kudu/SCM 認証で何が変わるのか、どの処理が影響を受けやすいのか、移行時にどこを確認すべきかを実務向けに整理します。
何が変わるのか:Kudu/SCM 呼び出しは App Service audience のトークンを使う
今回のポイントはシンプルです。App Service の Kudu/SCM エンドポイントへ Bearer トークンでアクセスする場合、トークンの audience を Azure Resource Manager ではなく App Service に合わせる必要があります。
Kudu は Azure App Service のデプロイ、ログ、ファイル操作、診断などを支える管理用サービスです。Microsoft Learn でも、App Service を作成すると HTTPS で保護された Kudu の companion app が作成され、通常は https://<app-name>.scm.azurewebsites.net でアクセスできると説明されています。(Microsoft Learn)
これまで一部のスクリプトやツールでは、次のような ARM 向けトークンを Kudu に流用していたケースがあります。
az account get-access-token
または、より明示的に次のような指定をしていたケースです。
az account get-access-token \
--resource https://management.azure.com/
Azure CLI の az account get-access-token は、--scope を指定しない場合の既定値が Azure Resource Manager であることがドキュメント上でも示されています。つまり、何も指定せずに取得したトークンは、Kudu/SCM ではなく ARM 管理 API 向けになりやすい点に注意が必要です。(Microsoft Learn)
今後の Kudu/SCM 直接呼び出しでは、Public Azure なら次のように App Service の scope を明示するのが基本です。
TOKEN=$(az account get-access-token \
--scope https://appservice.azure.com/.default \
--query accessToken \
-o tsv)
そのうえで、Kudu/SCM エンドポイントへ渡します。
curl -H "Authorization: Bearer $TOKEN" \
"https://<app-name>.scm.azurewebsites.net/api/settings"
重要なのは、これは「自分の Web アプリの認証 audience」ではないという点です。App Service の Kudu/SCM というプラットフォーム側エンドポイントを呼び出すため、https://appservice.azure.com/.default のような App Service 用 audience を使います。
影響を受けやすい処理
影響が出やすいのは、Azure Portal や高レベルの Azure CLI コマンドだけを使っている利用者ではなく、Kudu/SCM に対して直接 HTTP リクエストを投げている運用です。
| 確認対象 | 影響の可能性 | 見直すポイント |
|---|---|---|
curl や Postman で Kudu REST API を呼んでいる | 高い | Bearer トークンの audience が ARM になっていないか |
| 独自の ZIP デプロイスクリプト | 高い | /api/zipdeploy、/api/publish 呼び出し前のトークン取得 |
| CI/CD のカスタムステップ | 高い | az account get-access-token の既定トークンを使っていないか |
| VS Code 拡張や社内ツール | 中〜高 | Kudu クライアント作成時の scope 指定 |
| Basic 認証のデプロイ資格情報のみを使う処理 | 低い | Bearer トークンを使っていなければ直接の対象外 |
| ARM API だけを呼ぶ処理 | 低い | management.azure.com 向けトークンのままでよい |
Microsoft Learn では、SCM/Kudu/OneDeploy REST endpoint の認証方式として Basic authentication と Microsoft Entra が挙げられています。Bearer トークンを使う Microsoft Entra 認証へ移行している組織ほど、今回の audience 指定を確認する価値があります。(Microsoft Learn)
変更の背景:ARM トークンの流用は安全な前提ではなくなる
ARM は Azure リソースを管理するための API です。一方、Kudu/SCM は App Service のデプロイ、ログ、ファイルシステム、プロセス、診断などに関わる管理用エンドポイントです。
両者はどちらも Azure の管理に関係しますが、同じ audience のトークンで扱う前提にしてしまうと、次のような問題が起きます。
| 問題 | 内容 |
|---|---|
| 認証境界が曖昧になる | ARM 管理 API 向けトークンを、別サービスである Kudu に流用することになる |
| 破壊的変更に弱い | Kudu 側が App Service audience のみを受け付けるようになると失敗する |
| ソブリンクラウドで壊れやすい | Public Azure 前提の URL や audience をハードコードすると Gov/China などで失敗する |
| 原因調査が難しい | 401/403 が RBAC、IP制限、audience 不一致のどれか分かりにくくなる |
今回の PR では、Kudu/SCM への呼び出しで App Service audience を使うための getAppServiceScopes() や createKuduClient() が追加され、ZIP/WAR/Flex デプロイ、デプロイ結果取得、VFS 操作、ログストリーム、トンネル関連処理などが見直されています。(GitHub)
App Service audience の指定例
Public Azure の場合は、基本的に次の scope を使います。
https://appservice.azure.com/.default
US Government などの環境では audience が異なります。PR の変更では、環境ごとに App Service resource URL を切り替える実装が追加されています。(GitHub)
| Azure 環境 | App Service scope の例 |
|---|---|
| Public Azure | https://appservice.azure.com/.default |
| Azure US Government | https://appservice.azure.us/.default |
| Azure China | https://appservice.azure.cn/.default |
Public Azure のスクリプト例は次のとおりです。
APP_NAME="<app-name>"
TOKEN=$(az account get-access-token \
--scope https://appservice.azure.com/.default \
--query accessToken \
-o tsv)
curl -sS \
-H "Authorization: Bearer $TOKEN" \
"https://${APP_NAME}.scm.azurewebsites.net/api/deployments"
US Government 環境では、scope を次のように変えます。
TOKEN=$(az account get-access-token \
--scope https://appservice.azure.us/.default \
--query accessToken \
-o tsv)
China 環境では次のようにします。
TOKEN=$(az account get-access-token \
--scope https://appservice.azure.cn/.default \
--query accessToken \
-o tsv)
ソブリンクラウドを使っている場合は、management.azure.com や appservice.azure.com をコードに直接書くのではなく、利用中の Azure environment からエンドポイントを組み立てる実装にしておくと安全です。今回の PR でも、Flex デプロイ関連で https://management.azure.com のハードコードを環境別の Resource Manager endpoint に置き換える変更が入っています。(GitHub)
リポジトリやパイプラインで確認すべき検索キーワード
まずは、Kudu/SCM への直接呼び出しがあるかを洗い出します。GitHub、Azure Repos、ローカルリポジトリ、CI/CD の YAML、社内 Wiki に対して、次の文字列を検索してください。
.scm.azurewebsites.net
scm.
kudu
zipdeploy
api/publish
api/zipdeploy
api/deployments
api/vfs
api/logstream
get-access-token
management.azure.com
Authorization: Bearer
見つかった箇所では、次の順番で確認すると効率的です。
| 確認項目 | 判断基準 |
|---|---|
| Kudu/SCM の URL を呼んでいるか | https://<app>.scm... や /api/zipdeploy などがあれば対象 |
| Bearer トークンを使っているか | Authorization: Bearer があれば audience を確認 |
トークン取得時に --scope を指定しているか | 未指定なら ARM 向けの可能性が高い |
management.azure.com を指定していないか | Kudu 呼び出し用なら置き換え対象 |
| 環境別 URL をハードコードしていないか | Gov/China/ASE では特に注意 |
たとえば、次のようなコードは見直し対象です。
TOKEN=$(az account get-access-token \
--resource https://management.azure.com/ \
--query accessToken \
-o tsv)
curl -H "Authorization: Bearer $TOKEN" \
"https://<app-name>.scm.azurewebsites.net/api/zipdeploy"
修正後は、Public Azure であれば次のように App Service scope を指定します。
TOKEN=$(az account get-access-token \
--scope https://appservice.azure.com/.default \
--query accessToken \
-o tsv)
curl -X POST \
-H "Authorization: Bearer $TOKEN" \
-T app.zip \
"https://<app-name>.scm.azurewebsites.net/api/zipdeploy"
SDK や独自ツールでは scope を明示する
Azure SDK や独自クライアントを使っている場合も、考え方は同じです。Kudu/SCM に送るトークンを取得する箇所で、ARM ではなく App Service の scope を指定します。
TypeScript のイメージは次のとおりです。
import { DefaultAzureCredential } from "@azure/identity";
const credential = new DefaultAzureCredential();
const token = await credential.getToken(
"https://appservice.azure.com/.default"
);
const response = await fetch(
"https://<app-name>.scm.azurewebsites.net/api/deployments",
{
headers: {
Authorization: `Bearer ${token?.token}`
}
}
);
.NET の場合も、Kudu/SCM 呼び出し用の TokenRequestContext に App Service scope を指定します。
using Azure.Core;
using Azure.Identity;
var credential = new DefaultAzureCredential();
var token = await credential.GetTokenAsync(
new TokenRequestContext(new[]
{
"https://appservice.azure.com/.default"
})
);
// token.Token を Authorization: Bearer に設定して Kudu/SCM を呼び出す
ここで https://management.azure.com/.default を使うと、ARM API には適していますが、Kudu/SCM 呼び出しの移行方針とは合いません。
401・403 が出たときの切り分け
移行後に失敗した場合、すぐに権限不足と決めつけず、audience、RBAC、ネットワーク制限を分けて確認してください。
| 症状 | よくある原因 | 確認ポイント |
|---|---|---|
| 401 Unauthorized | トークンの audience が違う | JWT の aud が https://management.azure.com/ になっていないか |
| 403 Forbidden | RBAC 不足 | Microsoft.Web/sites/publish/Action を含むロールがあるか |
| 403 または接続不可 | SCM サイトのアクセス制限 | SCM 側の IP 制限、Private Endpoint、ネットワーク経路 |
| Public Azure では成功し Gov/China で失敗 | audience や endpoint のハードコード | 環境別の App Service scope を使っているか |
| Portal では開けるがスクリプトだけ失敗 | スクリプト側の token scope 不一致 | az account get-access-token の指定を確認 |
Kudu に Microsoft Entra 認証でブラウザーアクセスする場合、アプリのスコープに対して Microsoft.Web/sites/publish/Action を含む適切なロールが必要です。Microsoft Learn では、例として Website Contributor、Owner、Contributor などが挙げられていますが、Owner や Contributor は権限が広いため、必要最小限のロール設計を検討すべきです。(Microsoft Learn)
また、SCM サイトはメインサイトとは別にアクセス制限を設定できます。Microsoft Learn では、SCM サイトが Web Deploy endpoint であり Kudu console でもあること、メインサイトと同じ制限を使うか個別に制限できることが説明されています。(Microsoft Learn)
ネットワーク制限と audience 変更を混同しない
今回の変更は、主に Bearer トークンの audience に関するものです。したがって、正しい App Service audience のトークンを使っても、SCM サイトへのネットワークアクセスが許可されていなければ接続できません。
特に Azure Functions では、各 Function App に対応する scm endpoint があり、Advanced Tools、Kudu、デプロイなどで利用されます。ネットワーク分離を行う場合は、この scm endpoint も考慮する必要があります。(Microsoft Learn)
App Service と Application Gateway を組み合わせる構成でも、SCM サイトにリバースプロキシを使えないこと、ほとんどの場合は個別の IP アドレスやサブネットにロックダウンすることが推奨されると説明されています。(Microsoft Learn)
つまり、トラブルシューティングでは次の順番で見るのが現実的です。
1. Kudu/SCM の URL が正しいか
2. Bearer トークンの audience が App Service になっているか
3. RBAC に publish 権限があるか
4. SCM サイトのアクセス制限でブロックされていないか
5. ソブリンクラウドや ASE の endpoint をハードコードしていないか
既存のデプロイ方式ごとの対応方針
すべての App Service 利用者がすぐにコード修正を迫られるわけではありません。重要なのは、自社がどの認証方式で Kudu/SCM を使っているかを把握することです。
| 利用パターン | 対応方針 |
|---|---|
| Azure Portal から Kudu を開くだけ | 通常は大きな作業なし。ただし権限とアクセス制限は確認 |
az webapp deploy など高レベル CLI を使う | Azure CLI を最新化し、直接 REST 呼び出しがないか確認 |
curl で /api/zipdeploy を呼ぶ | トークン取得を App Service scope に変更 |
| GitHub Actions で独自スクリプトを使う | OIDC やサービスプリンシパルで取得する scope を確認 |
| Basic 認証の publish profile を使う | audience 変更の直接対象ではないが、Basic 無効化方針があるなら Entra 対応を準備 |
| VS Code 拡張や社内拡張を使う | 依存パッケージや拡張機能の更新状況を確認 |
| Azure Government/China を使う | audience と Resource Manager endpoint のハードコードを重点確認 |
Microsoft Learn のデプロイ認証表では、Azure CLI の一部コマンドが Basic 認証無効時に Microsoft Entra を使うこと、SCM/Kudu/OneDeploy REST endpoint でも Microsoft Entra が使えることが示されています。高レベルコマンドに任せている場合でも、内部で古いツールや固定スクリプトを呼んでいないかを確認しておくと安全です。(Microsoft Learn)
移行時に失敗しやすいポイント
az account get-access-token の既定値を信じてしまう
もっとも多い落とし穴は、az account get-access-token を引数なしで使うことです。これは「Azure にログインしているから App Service にも使える」という意味ではありません。Kudu/SCM 用には App Service scope を明示してください。
アプリ本体の Entra アプリ登録と混同する
App Service 認証、Easy Auth、独自 API の audience と、Kudu/SCM の App Service audience は別物です。自社アプリの api://... やクライアント ID を Kudu 呼び出しに使っても、Kudu/SCM の認証としては適切ではありません。
401 と 403 を同じ原因として扱う
401 は token audience や token 期限切れ、403 は RBAC やアクセス制限が原因になりやすいです。もちろん例外はありますが、最初からすべてを権限不足として調べると遠回りになります。
Public Azure の URL をソブリンクラウドに流用する
https://appservice.azure.com/.default は Public Azure 用です。Azure US Government や Azure China では App Service audience が異なります。環境ごとに URL を切り替える実装にしてください。
トークンを外部サイトに貼り付けて確認する
JWT の aud を確認したい場合でも、本番トークンを外部サービスに貼り付けるのは避けるべきです。ローカルツールや社内で許可された方法でデコードしてください。
まず取るべきアクション
今回の Azure App Service Kudu/SCM 認証変更で、最初にやるべきことは大規模な改修ではなく、直接 Kudu を呼んでいる箇所の棚卸しです。
特に、次の3つを優先してください。
1. `.scm.azurewebsites.net` や `/api/zipdeploy` を呼ぶスクリプトを探す
2. Bearer トークン取得時に ARM audience を使っていないか確認する
3. Public/Gov/China など利用環境に合った App Service scope へ変更する
Kudu/SCM の直接呼び出しは、デプロイやログ取得など運用の中核に入り込みやすい部分です。トークンの audience 不一致は、実行時まで気づきにくく、発生するとデプロイ停止や障害調査の遅延につながります。
App Service を使うチームは、まず CI/CD、社内ツール、運用スクリプトから management.azure.com の流用を探し、Kudu/SCM 呼び出しでは App Service audience を明示する形に移行してください。

コメント