Azure Functions(.NET 8 / Isolated)で QueueTrigger の Connection を Key Vault 参照にすると、Azure では動くのにローカル実行だけ失敗することがあります。本記事では、原因になりやすい VaultName の指定ミスと、local.settings.json の具体例、AzureWebJobsStorage の扱いまでまとめて解説します。
やりたいこと:QueueTrigger の Connection を「接続文字列名」で参照し、実体は Key Vault に置きたい
.NET 8(分離ワーカー / Isolated)の Azure Functions で、Storage Queue のトリガーを次のように書くケースは多いです。
[Function("ProcessEvent")]
public void Run(
[QueueTrigger("my-queue", Connection = "MyConnectionString")] string myQueueItem)
{
// ...
}
このとき Connection = "MyConnectionString" は「接続文字列そのもの」ではなく、設定名(環境変数名)を見に行きます。Azure にデプロイした環境では、アプリ設定(App Settings / 環境変数)に次のような Key Vault 参照を置いておけば、接続文字列(AccountKey を含む)をアプリに直書きせずに済みます。
- App Settings:
MyConnectionString - 値:
@Microsoft.KeyVault(...)形式の参照
問題はここからで、ローカル実行(local.settings.json 等)でも同様に Key Vault 参照を書きたいのに、QueueTrigger の Connection だけが解決されず失敗することです。生の接続文字列(AccountKey を含む)を直書きすると動きますが、開発者全員のローカル設定更新が必要になり、ローテーションや運用の負担が一気に増えます。
ローカル実行で起きる症状:QueueTrigger だけが失敗する
代表的には、起動時(Functions Host がインデックスを作るタイミング)でエラーになり、トリガーが張れません。ログの文言は環境・拡張のバージョンで多少揺れますが、次のようなニュアンスのものが出やすいです。
- 接続設定
MyConnectionStringが見つからない / 解決できない - ストレージ接続文字列の形式が不正
- ストレージアカウントへ接続できない
一方で、同じ Key Vault 参照を使っている別の設定(アプリの独自設定や、コード内で読む IConfiguration)は動いているように見えて、「QueueTrigger だけおかしい」という印象になりがちです。
前提整理:.NET 8 Isolated では「トリガーの解決」は Functions Host 側で起きる
Isolated(分離ワーカー)構成では、ざっくり言うとプロセスが分かれています。
- Functions Host:トリガー/バインディングの解決、リスナーの開始、ホストの内部状態管理
- .NET Worker:あなたの関数コード(DI、ログ、アプリ設定の読み込みなど)
QueueTrigger の Connection は、関数コードが動く「前」に Host が必要とする情報です。つまり「Program.cs で設定を読み替える」「DI で Key Vault を読んでから…」といった工夫をしても、Host 側が接続文字列を解決できなければトリガーは開始できません。
この構造を知っておくと、トラブルシュートが一気に楽になります。「コードは正しいのに起動前に落ちる」系は、Host が読む設定(環境変数/ローカル設定)の段階で何かが起きています。
結論:@Microsoft.KeyVault の VaultName は Key Vault の“名前だけ”を指定する
今回の原因は、Key Vault 参照の書き方(特に VaultName)が誤っていたことでした。ローカル設定に次のように書いていると、QueueTrigger の Connection が解決されずに失敗します。
| 指定 | 例 | 結果 |
|---|---|---|
| NG(ホスト名/URL 形式を入れてしまう) | VaultName=my-vault.vault.azure.net | 参照先 URL が不正になりやすく、Secret を引けずに失敗 |
| OK(Key Vault のリソース名だけ) | VaultName=my-vault | 正しく Secret を参照できる |
ポイントは、「VaultName は Key Vault 名(リソース名)であって、FQDN/URL ではない」ことです。FQDN を入れると、内部で組み立てられる URL が二重になったり、名前解決できない宛先になったりして、結果として Secret が取得できず、@Microsoft.KeyVault(...) が“文字列のまま”残ってしまいます。
そして QueueTrigger は接続文字列が必要なので、そのまま起動に失敗します。逆に言うと、VaultName を正すだけで「ローカルでも Key Vault 参照が動いた」という状況は十分に起こり得ます。
ローカル設定の正しい例:local.settings.json(VaultName は名前だけ)
ローカル実行では local.settings.json の Values が環境変数として扱われます(ファイル自体は通常 Git 管理しません)。今回のポイントを反映した例は次のとおりです。
{
"IsEncrypted": false,
"Values": {
"FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
// Functions Host が内部動作で使うストレージ(後述)
"AzureWebJobsStorage": "UseDevelopmentStorage=true",
// QueueTrigger の Connection が参照する設定名
"MyConnectionString": "@Microsoft.KeyVault(VaultName=my-vault;SecretName=MyConnectionString)"
}
}
この例では、QueueTrigger 側は Connection = "MyConnectionString" のまま変えません。変えるのは「MyConnectionString の値」だけで、Azure でもローカルでも同じキーで運用できます。
Secret に格納する値(Key Vault 側)は“通常どおり”でOK
Key Vault の Secret の値は、従来どおりストレージ接続文字列を入れます。たとえば以下のような形式です(値は環境ごとに異なります)。
DefaultEndpointsProtocol=https;AccountName=xxxx;AccountKey=yyyy;EndpointSuffix=core.windows.net
Key Vault 参照は「参照の書式さえ正しければ」中身の形式はいつもの接続文字列で問題ありません。
@Microsoft.KeyVault の書式を整理:SecretUri と VaultName/SecretName
Key Vault 参照は環境によって書式が混在しやすいので、チーム内でどれを使うか決めておくと事故が減ります。代表的には次の 2 パターンです。
| パターン | 書式例 | 特徴 |
|---|---|---|
| SecretUri 指定 | @Microsoft.KeyVault(SecretUri=https://my-vault.vault.azure.net/secrets/MyConnectionString/xxxxx) | URI をそのまま貼れる。バージョン固定もしやすいが、URI が長くなりがち |
| VaultName / SecretName 指定 | @Microsoft.KeyVault(VaultName=my-vault;SecretName=MyConnectionString) | 短く書ける。今回のように VaultName を FQDN で書かないのが重要 |
どちらを使っても目的は同じですが、VaultName/SecretName 方式は「VaultName に何を入れるか」で詰まりやすいため、ルールを明文化しておくのがおすすめです。
AzureWebJobsStorage を誤解しない:名前が似ているだけで “別物”
QueueTrigger の接続設定(MyConnectionString)とは別に、Functions には AzureWebJobsStorage という有名な設定があります。ここが混線すると、原因が見えにくくなります。
AzureWebJobsStorage は、Functions Host が内部動作で使うストレージ設定名です。拡張パッケージ名に Microsoft.Azure.WebJobs.* が付いている/付いていない、といった参照関係とは別の話で、単に「歴史的にそういう名前」なだけです。
| 設定名 | 主に使うもの | ローカル例 | よくある注意点 |
|---|---|---|---|
AzureWebJobsStorage | Functions Host(内部状態・ログ・一部トリガーなど) | UseDevelopmentStorage=true(Azurite) | 空にすると起動できない/挙動が不安定になることがある |
MyConnectionString(任意名) | QueueTrigger の Connection(Storage Queue への接続) | Key Vault 参照 or 実接続文字列 | 参照名と値の双方を見直す。VaultName の指定ミスに注意 |
ローカルで Azurite を使うなら AzureWebJobsStorage は UseDevelopmentStorage=true が定番です。実ストレージを使うなら接続文字列を入れますが、ここも必要に応じて Key Vault 参照にできます(ただし Host が解決できる前提)。
動作確認の手順:原因切り分けを短時間で終わらせる
同じ現象に当たったとき、再発防止も兼ねて「何を確認すべきか」を手順化しておくと便利です。
Key Vault 側の確認
- Key Vault の名前(リソース名)を確認する(FQDN ではない)
- SecretName が一致しているか確認する(大文字小文字も含め)
- Secret の値が正しい接続文字列形式になっているか確認する
ローカル設定の確認(local.settings.json)
Values配下にMyConnectionStringが存在するか@Microsoft.KeyVault(...)の括弧内が正しいか(特に VaultName)- 余計な空白、全角文字、引用符の欠けがないか
権限(認証)の確認
ローカルで Key Vault の Secret を参照できるようにするには、実行している環境(開発者の Azure アカウント、サービスプリンシパル等)が Key Vault の Secret を読める必要があります。RBAC/アクセス ポリシーのどちらを使っている環境でも、最低限「Secret を取得する権限」が必要です。
ここが不足していると、VaultName が合っていても取得に失敗します。「参照は書けているのに値が解決されない」場合は、書式だけでなく権限も疑ってください。
チーム開発で運用を楽にするコツ
「ローカルにも AccountKey を配る」運用を避けるために、Key Vault 参照を軸にする場合、チームで次のようなルールを作っておくと回りやすくなります。
SecretName と設定名を固定し、環境差分は Key Vault 側で吸収する
- 関数側の
Connectionは固定:Connection = "MyConnectionString" - Key Vault の SecretName も固定:
MyConnectionString - 環境(dev/stg/prod)で Key Vault を分ける、または Secret の値だけを環境別にする
こうしておくと、開発者のローカル設定は「Key Vault 参照の 1 行」だけで済み、接続文字列の配布や更新が最小化できます。
local.settings.json を配らない(例ファイル運用にする)
実ファイルは開発者ローカルに置き、リポジトリには local.settings.json をコミットしないのが基本です。その代わりに、local.settings.example.json のようなサンプルを置き、チームで差分が出ない形にします。
- 例ファイルには Key Vault 参照の書式(VaultName の書き方)を明記
- 実ファイルは各自がコピーして使う(中身は参照だけで個人差が出にくい)
どうしても Key Vault 参照が安定しない場合の回避策
開発環境やツールの事情で、@Microsoft.KeyVault(...) の解決が安定しないこともあります。その場合は「参照の仕組み」から少し外れますが、次の回避策が現実的です。
起動スクリプトで Key Vault から Secret を取得し、環境変数として渡してから起動する
QueueTrigger の接続文字列は Host 起動時に必要なので、Host を起動する前に環境変数を用意するのがポイントです。例えば PowerShell なら次のようなイメージです。
$kvName = "my-vault"
$secretName = "MyConnectionString"
# Azure CLI などで取得(事前にログインが必要)
$cs = az keyvault secret show --vault-name $kvName --name $secretName --query value -o tsv
$env:MyConnectionString = $cs
func start
この方法なら、接続文字列をファイルに固定保存せずに済みます。ただし、Key Vault を読むための認証(az login など)や権限付与が必要で、運用ルールも追加で必要になります。
将来的には「鍵を持たない」設計も検討する
Storage Queue の利用方法によっては、AccountKey を前提としない認証(マネージド ID など)を検討できる場合があります。すべてのケースで置き換えられるわけではありませんが、“接続文字列を安全に配る”発想そのものを減らせるので、中長期的には有効です。
まとめ
- .NET 8 Isolated の QueueTrigger は、Host 側で接続文字列を解決するため、設定の不整合があると起動時に落ちやすい
- ローカルで
@Microsoft.KeyVault(...)を使う場合、VaultName には Key Vault の名前(リソース名)だけを入れる(FQDN/URL 形式は NG) AzureWebJobsStorageは Functions Host の内部ストレージ設定。QueueTrigger の接続設定とは役割が違うので切り分けて考える- 不安定な場合は、起動前に Secret を取得して環境変数に入れてから起動するなど、現実的な回避策も用意しておく

コメント