勇者だって最初はひのきの棒とナベのふた

技術を中心に発信。時々SFの読書感想も。

Azure DefaultAzureCredential() 認証についてのお話

はじめに

どうも、masamoriです。しば犬って可愛いですよね。小紅書でしば犬ばっかり見てたら、タイムラインとレコメンドがしば犬ばっかりになって幸せです。
さて、今回はAzureの認証について調べたことについて書きます。

Azure Function を使ってKey Vaultにアクセスしようとする時、MSの推奨としてはマネージドIDを使うことになっています。
というより、Azureのリソース間で認証を行うときはマネージドIDが便利でセキュアです。なぜなら、コードにシークレットを埋め込む必要がなくなるからです。(.envとか使っていても、埋め込んでることにはなる。) ちなみに、マネージドIDって何?って方は、こちらの記事を見ると分かりやすいです。 tech-lab.sios.jp

マネージドIDを使用して、Entra IDから資格情報を得るときに使うメソッドが. DefaultAzureCredential().
です。

Functionをローカルで開発していて上手くいっていたのに、デプロイしてFiunctionを動かしてみるとKey Vaultの認証で弾かれてしまうことがありました。 というわけで、この原因を調べるべくDefaultAzureCredential()について少し深掘りをしてみました。

そもそも

DefaultAzureCredential()の定義はこちらです。

learn.microsoft.com

これが有効になっている場合、ドキュメントに書かれているCredentialの上から順番に試されていくんですね。なので、環境によっては違うCredentialが読み込まれることも十分にあり得るわけです。

そして、次にこちらの記事

learn.microsoft.com

これはApp ServiceからDBに接続するチュートリアルになりますが、注目する部分はここ

DefaultAzureCredential は、開発環境と Azure 環境の両方に適応できるだけの柔軟性を備えています。 ローカルで実行しているとき、任意の環境 (Visual StudioVisual Studio Code、Azure CLI、Azure PowerShell) からログインしている Azure ユーザーを取得できます。 Azure で実行しているとき、マネージド ID が取得されます。 そのため、開発時と運用時の両方でデータベースへの接続が可能です。

コード実行の裏側で、こういうことが行われているんですね。
これ別の解釈すると、「環境によって取得するCredentialは違うから、気をつけて開発してね」っていうことなんだと思います。
ローカルとデプロイ環境だと当然環境も違うので、取得するCredentialが異なる。その結果、ローカルで動かした時に認証が上手くいっていても、デプロイ環境の設定(マネージドIDの設定やマネージドIDへの権限付与)が上手くいっていない場合、デプロイするとアプリケーションが動かない場合があるということです。

僕のケースでは、ローカル環境でaz account showと打つと、自分のアカウントが出てきたので、AzureCLIにサインインしている状態です。
なので、認証としては"DefaultAzureCliCredential"が使われている可能性が高いです。そして、デプロイした場合"DefaultManagedIdentityCredential"が認証として読み込まれる優先順位が高いので、ManagedIDが設定されていなかったので、Functionの実行に失敗したという感じでしょうか。

あれ?そうなると、デプロイした環境だと"DefaultAzureCliCredential"は読み込まれないんでしょうか?挙動を見るとそうなりますよね。つまり、デプロイした環境(Azure環境)ではAzureCLI環境は読み込まれず、環境変数やマネージドIDを使って認証をすることになります。この辺、やや複雑ですね。間違っていたらご指摘ください。

というわけで

Functionを使ってAzureの各リソースにアクセスしたい場合、まずはFunctionのマネージドIDをオンにして、各リソースにそのマネージドIDに対して適切な権限を割り振りましょう。ユーザーに割り振ってしまうと、アプリケーションの想定する挙動とは異なると思います。
冒頭のKey Vaultにアクセスできない問題は、Key Vaultに対してユーザーにはシークレットの読み取り権限が設定されていたにも関わらず、FunctionのマネージドIDには割り振られていなかったんですね。 なので、全く同じコードでも動かなかったと。
というわけで、マネージドIDに権限を割り振ったら解消しました。

終わりに

認証周りは結構複雑になりがちです。ドキュメント通りに実装して他のAzureリソースにアクセスできない場合、認証を見直してみましょう。
個人的には認証周りはややこしいなーと思っています。 マネージドIDとかサービスプリンシパルとか、そもそもEntra IDってなんなの?みたいな。

マネージドID、サービスプリンシパルについてもいずれ記事にしてみたいと思います。
いつになるか分かりませんが。