Azure App Serviceのアプリケーション設定にパスワードなどの秘密情報をそのまま格納している場合、Azureポータルあるいはデプロイのコードなどから、その秘密情報が漏れてしまう危険がある。「Key Vault」の「シークレット」でこれを抑える方法を紹介する。
対象:Azure App Service、Key Vault(キーコンテナー)、Azureポータル
「Azure App Service」上のアプリケーションから、認証の必要な別のサービスを利用するのはよくあることだろう。
そして、その認証に必要なID/パスワードといった秘密情報をApp Serviceの「アプリケーション設定」などに保存しておき、アプリケーションのコードから参照するのも、よくあることだ。
しかし、その秘密情報は安全だろうか? 例えばアプリケーション設定に保存した秘密情報は、そのApp Serviceの設定を閲覧できるスタッフならば容易に知ることができる。また、リソースをデプロイしているコードのアプリケーション設定部分には、秘密情報が暗号化されずに露出していることも多いのではないだろうか。
本Tech TIPSでは、秘密情報を管理するためのサービス「Azure Key Vault」(キーコンテナー)とApp Serviceを連携させることで、こうした秘密情報の漏えいをなるべく防ぐ方法の一つを紹介したい。
簡単に説明すると、Key Vaultの「シークレット」に秘密情報を保存し、それをApp Serviceから「参照」するように設定する。これによりApp Serviceを参照可能なユーザーでも、Key Vault上の秘密情報を知ることができない。また、デプロイのコードには秘密情報を埋め込まずに済む。
本Tech TIPSでは、Azureポータルでの設定手順を説明する(Azure CLIでの設定方法は別のTech TIPSで解説)。App ServiceとKey Vaultはあらかじめデプロイ済みとする。
Key Vaultからシークレットを読み出すには、事前にKey VaultとApp Serviceの間で設定しなければならないことがある。その一つが、対象のApp Serviceで「マネージドID」を有効にすることだ。
マネージドIDとは、Azure標準のIDサービス「Microsoft Entra ID(Azure Active Directory)」からApp Serviceなどのリソースに対して発行されるIDの一種だ。マネージドIDをサポートしているAzure上のリソースに対し、容易に認証して接続できる。また、パスワードなどの資格情報を管理する必要はない。詳細は、Microsoft Learnの「Azure リソースのマネージド ID とは」を参照していただきたい。
マネージドIDには「システム割り当て」「ユーザー割り当て」の2種類のIDがある。本Tech TIPSでは、より簡単に利用できる前者で説明する。
App ServiceでマネージドIDを有効化するには、以下の画面のようにAzureポータルを操作する。この作業は1回行えばよい。
これでマネージドIDの有効化は完了だ。
App ServiceのマネージドIDを有効化したら、そのIDを使って、App ServiceがKey Vaultのシークレットを取得できるようにアクセス許可を設定する。
このとき、Key Vaultでアクセス許可の仕組み(モデル)として、あらかじめ「コンテナーアクセスポリシー」「Azureロールベースのアクセス制御(Azure RBAC)」のどちらを選択しているかによって、設定手順は異なる。ここでは、シンプルな前者を選んでいるものとして説明する(Microsoftは後者を推奨している)。
コンテナーアクセスポリシーでApp Serviceにシークレット取得を許可するには、以下の画面のようにAzureポータルを操作する。この作業は1回行えばよい。
これでアクセスポリシーの設定は完了だ。
Key Vaultにシークレットを保存するには、以下の画面のようにAzureポータルを操作する。この作業はシークレットごとに1回ずつ行う必要がある。
これでシークレットの保存は完了だ。
Key Vaultにシークレットを保存したら、それをApp Serviceで取得するように設定しよう。
ここではApp Serviceのアプリケーション設定を対象として説明する。ただ接続文字列についても、ほぼ同じ手順でKey Vaultシークレットを参照できる。
アプリケーション設定の値(内容)には、平文で秘密情報を記入する代わりに、Key Vaultのシークレットを参照するための下記文字列を指定する。
@Microsoft.KeyVault(VaultName=<Key Vault名>;SecretName=<シークレット名>)
操作手順は以下の画面の通りだ。ただし、アプリケーション設定の内容を除けば、その手順は通常のアプリケーション設定と変わらず、アプリケーション設定ごとに1回ずつ行う必要がある。
これでアプリケーション設定の追加は完了だ。
App Serviceの再起動が確認したら、Key Vaultのシークレットを正しく参照できているかどうか、必ず確認しよう。
それには、前述の手順で対象のアプリケーション設定の編集画面を再び開く。以下の画面のように「状態」が[✔ Resolved]と表示されていれば、Key Vaultのシークレットを正しく参照して、その値を取得できている。
一方、参照が失敗していると、以下の画面のように「状態」が「× <エラーを表すタイトル>」と表示される。「エラーの詳細」に表示されている内容を確認して対処しよう。特に、前述の参照文字列では名前のスペルミスやカッコの過不足、セミコロンの欠落などがないかどうか、よく確認したい。
正常に参照できたら、アプリケーション側でもKey Vaultシークレットに設定した値が正しく取得できているかどうか確認してみよう。それには「<アプリケーション設定名>」あるいは「APPSETTING_<アプリケーション設定名>」という環境変数の値を取得すればよい。
上記の環境変数に、アプリケーション設定の値、すなわち「@」から始まる参照文字列そのものが格納されていたら、Key Vaultシークレットへの参照が失敗しているので、設定を再確認すること。
注意したいのは、Key Vaultシークレットへの参照を設定していても、アプリケーションのインスタンス内部を参照可能なユーザーには秘密情報が閲覧されてしまう、という点だ。実際、上記のphpinfo()の出力では、インスタンス上の環境変数の値が平文で表示されている。つまり、何らかの方法で環境変数を参照できるなら、そこから漏えいする恐れがあるということだ。
本Tech TIPSで紹介している方法では漏えいの危険性を下げることはできても、完全に防ぐことはできない。引き続きアクセス権の制限などに注意を払う必要があるだろう。
例えばApp Serviceからアクセスしているリソースで認証用パスワードが変更された場合、当然ながらApp Service側でもアプリケーション設定に含まれるパスワードを更新する必要がある。それがKey Vaultシークレットへの参照なら、Key Vault側でシークレットの内容を更新する必要がある。
ここで注意が必要なのは、Key Vaultシークレットの値を変更すると、それまでの値は「以前のバージョン」に、最新の値が「現在のバージョン」にそれぞれ扱いが変わるという点だ。つまり、上書き更新ではなく、新たな値が追加されつつ、過去の値は削除されることなく残るということである。以下にその追加手順を示す。
「以前のバージョン」「現在のバージョン」にはそれぞれ16進数からなる識別子が付けられていて、参照する側からバージョンを特定して取得できるようになっている。App Serviceの場合、以下のように「SecretVersion=」の指定を参照文字列に追加すればよい。
@Microsoft.KeyVault(VaultName=<Key Vault名>;SecretName=<シークレット名>;SecretVersion=<バージョン番号>)
<バージョン番号>の指定を省略した場合、「現在のバージョン」すなわち最後に追加した最新の値が参照される。そのため、常に最新の値を参照するなら、<バージョン番号>を指定する必要はない。
ここで注意しなければならないのは、Key Vaultシークレットに新しい値を追加した後、App Serviceのアプリケーション設定の内容が最新の値に変わるタイミングだ。
App Serviceを放置した場合は、24時間以内に自動で最新値が反映される。
すぐに反映したいなら、App Serviceで何らかの設定変更をしてKey Vaultシークレットからの再取得を促す必要がある。筆者が試した限りでは、(対象とは関係のない)アプリケーション設定や接続文字列、[構成]−[全般設定]、[ネットワーク]−[アクセス制限]の設定を追加/変更/削除すると、その数秒〜十数秒後には、最新値が反映された。
一方、何の設定変更も伴わない単なる再起動や停止→起動では、最新値は反映されず、1つ前の値のまま変わらなかった。また、Key Vaultシークレットを参照しているアプリケーション設定の編集画面を開き、変更せずに保存しても、やはり変わらなかった。
■関連リンク
Copyright© Digital Advantage Corp. All Rights Reserved.