Azure App Serviceのアプリ設定にパスワードなどを格納していると、Azureポータルあるいはデプロイのコードなどから、それが漏れてしまう危険がある。これを「Key Vault」の「シークレット」で解決することが可能だ。その方法のうち、PowerShellでの手順を説明する。
対象:Azure App Service、Key Vault(キーコンテナー)、PowerShell
「Azure App Service」上のアプリケーションから認証が必要な別のサービスを利用するために、IDやパスワード、APIキーなどの秘密情報を「アプリ設定」に保存しておき、アプリケーションのコードから参照する。これはよくある実装だろう。
ただ、このように保存している秘密情報は、そのApp Serviceの設定を閲覧できるスタッフならば容易に知ることができる。また、リソースをデプロイしているコードのアプリ設定部分には、秘密情報が暗号化されずに露出していることも多いのではないだろうか。
そこでTech TIPS「【Azure Key Vault】App Serviceのアプリケーション設定から『シークレット』な情報が漏れないようにする(Azureポータル編)」では、「Azure Key Vault」(キーコンテナー)とApp Serviceを連携させることで、秘密情報の漏えいを抑える方法を紹介した。
本Tech TIPSでは、Azure PowerShellで同じことを実現する手順を紹介したい。基本的な事柄については前出のTech TIPSで説明しているので、そちらに目を通してから本Tech TIPSを読み進めていただきたい。
App ServiceとKey Vaultは、同じサブスクリプションであらかじめデプロイ済みとする。また、以下に記載しているコマンドレットの実行前には、「Connect-AzAccount」コマンドレットでAzureへログイン(接続)し、「Set-AzContext」コマンドレットでデフォルトのサブスクリプションを選択しておく必要がある。
Key Vaultからシークレットを読み出すには、まず参照元のApp Serviceで「マネージドID」を有効化する必要がある。本Tech TIPSでは、「システム割り当て」「ユーザー割り当て」という2種類のマネージドIDのうち、より簡単に利用できる前者で説明する。
システム割り当てのマネージドIDを有効化するには、以下のように「Set-AzWebApp」コマンドレットを実行する。
Set-AzWebApp -Name <App Service名> `
-ResourceGroupName <App Serviceリソースグループ名> `
-AssignIdentity $true # システム割り当てのマネージドIDを有効化
「-AssignIdentity」オプションに「$true」を指定すると、システム割り当てのマネージドIDが有効になる。
この作業はApp Serviceごとに1回行えばよい。
App ServiceでマネージドIDを有効化すると、「プリンシパルID」(オブジェクトID)という固有のGUIDが割り当てられる。Key Vaultシークレットを参照するには、このプリンシパルIDが必要なので、以下のように「Get-AzWebApp」コマンドレットで取得しておく。
$site = Get-AzWebApp -Name <App Service名> ` # App Serviceを取得
-ResourceGroupName <>App Serviceリソースグループ名>
$principalId = $site.Identity.PrincipalId # プリンシパルIDを変数に格納
$principalId # 表示
何も表示されない場合は、システム割り当てのマネージドIDがまだ無効のままと考えられる。前述の手順で有効化してみよう。
プリンシパルIDは「Get-AzADServicePrincipal」コマンドレットでも取得できる。
$principalId = (Get-AzADServicePrincipal -DisplayName <App Service名>).Id
$principalId # 表示
この作業もApp Serviceごとに1回行えばよい。
次に、App ServiceがKey Vaultシークレットを取得できるように、有効化したマネージドIDを使ってアクセス許可を設定する。
本Tech TIPSでは、「コンテナーアクセスポリシー」「Azureロールベースのアクセス制御(Azure RBAC)」という2種類のKey Vaultアクセス制御方式のうち、よりシンプルな前者を選んでいるものとして説明する(Microsoftは後者を推奨している)。
コンテナーアクセスポリシーでApp ServiceにKey Vaultシークレットの取得を許可するには、以下のように「Set-AzKeyVaultAccessPolicy」コマンドレットを実行する。
Set-AzKeyVaultAccessPolicy -VaultName <Key Vault名> `
-ObjectId $principalId ` # 取得したプリンシパルID(を格納しておいた変数)
-PermissionsToSecrets Get # 「取得」のみ許可
「-ObjectId」オプションの後には、取得しておいたApp ServiceマネージドIDのプリンシパルIDを指定する。
「-PermissionsToSecrets」オプションの後には、Key Vaultシークレットに対して許可する操作として、唯一必要な「get(取得)」のみ指定している。複数の場合は、操作内容を表す単語「all」「backup」「delete」「get」「list」「purge」「recover」「restore」「set」を選んで、半角コンマで区切りつつ列挙すればよい。
この作業はマネージドID(プリンシパルID)ごとに1回ずつ行う必要がある。
Key Vaultシークレットに秘密情報を保存するには、以下のように「Set-AzKeyVaultSecret」コマンドレットを実行する。
# 秘密情報を対話的に入力する場合
$securedSecret = Read-Host "秘密情報を入力してください"
-AsSecureString
# 秘密情報を平文で記載する場合(非推奨)
$securedSecret = ConvertTo-SecureString `
-String '<パスワードなどの秘密情報>' `
-AsPlainText
# Key Vaultにシークレットを登録する
Set-AzKeyVaultSecret -VaultName <Key Vault名> `
-Name <シークレット名> ` # 半角英数字とハイフンで127文字以内
-SecretValue $securedSecret
<シークレット名>は、半角の英数字およびハイフン、かつ127文字以内で指定する必要がある。
この作業はKey Vaultシークレットごとに1回ずつ行う必要がある。
App Service からKey Vaultシークレットを参照して、そこに保存してある秘密情報をアプリ設定に格納するには、以下のようにアプリ設定を変更する。
$site = Get-AzWebApp -Name <App Service名> ` # App Serviceを取得
-ResourceGroupName <App Serviceのリソースグループ名>
$appSettings = $site.SiteConfig.AppSettings # 既存のアプリ設定を抽出
# 既存のアプリ設定の一覧をハッシュテーブルに変換
$newAppSetHash = @{}
$appSettings | ForEach-Object {
$newAppSetHash[$_.Name] = $_.value
}
# シークレットを参照するアプリ設定をハッシュテーブルに追加
$appSetName = "<アプリ設定の名称>" # 半角の英数字とピリオド、アンダースコア
$appSetValue = "@Microsoft.KeyVault(VaultName=<Key Vault名>;SecretName=<シークレット名>)"
$newAppSetHash[$appSetName] = $appSetValue
# ハッシュテーブルからアプリ設定を変更
Set-AzWebApp -Name $site.Name `
-ResourceGroupName $site.ResourceGroup `
-AppSettings $newAppSetHash
PowerShellの場合、アプリ設定の一部のみ変更することはできず、全てのアプリ設定を指定して更新する必要がある。今回のような新規追加の場合、まず既存のアプリ設定を全て読み出し、それに新たなアプリ設定を追加して反映するという手順を踏む必要がある点に注意してほしい。
追加したいアプリ設定が複数の場合は、その名称と値の組み合わせを上記リストのハッシュテーブル「$newAppSetHash」に追加すればよい。
<アプリ設定の名称>は、半角の英数字とピリオド、アンダースコアで指定する必要がある。
上記リストを実行すると、自動的にアプリケーションのリサイクルがかかり、一時的にWebサイト/アプリの応答が途絶することがあるので注意が必要だ。
上記で追加したアプリ設定に対して「デプロイスロットの設定」を「オン」にする、すなわち、スロット固有にするには、以下も実行する必要がある。
# 「デプロイスロットの設定」が「オン」である既存のアプリ設定名一覧を取得
$slotConfigNames = Get-AzWebAppSlotConfigName $site
$appSetNames = $slotConfigNames.AppSettingNames # アプリ設定のみ抽出
# 取得した一覧に、さきほど追加したアプリ設定名を追加
$newAppSetNames = $appSetNames + $appSetName
# App Serviceに反映
Set-AzWebAppSlotConfigName $site -AppSettingNames $newAppSetNames
「デプロイスロットの設定」を「オン」にするには、「Get-AzWebAppSlotConfigName」コマンドレットで既存のアプリ設定名の一覧を取得し、それに新たなアプリ設定名を追加して、「Set-AzWebAppSlotConfigName」コマンドレットで反映すればよい。
設定が完了したら、App ServiceからKey Vaultシークレットが正しく参照(取得)できているかどうか確認しよう。それには、前述のリスト内の<アプリ設定の名称>($appSetName変数)と同じ名前の環境変数の内容がKey Vaultシークレットの内容と同じであるかどうかチェックすればよい。
以下ではLinuxベースのApp ServiceにSSHで接続し、「printenv <アプリ設定の名称>」と実行して環境変数の内容を表示させている。
参照に失敗していると、前述の「@Microsoft〜」から始まる参照文字列が(展開されることなく)そのまま環境変数の内容として格納されているはずだ。その場合はアプリ設定などを再確認すること。
上記の例から分かるように、Key Vaultシークレットへの参照を設定していても、アプリケーションのインスタンス内部で環境変数など参照可能なユーザーには、秘密情報が閲覧されてしまう。本Tech TIPSで紹介している方法では漏えいの危険性を下げることはできても、完全に防ぐことはできない。引き続きアクセス権の制限などに注意を払う必要がある。
認証情報の更新に伴い、Key Vaultシークレットの内容も更新しなければならない場合は、追加時のコマンドラインのうち「-SecretValue」オプションの値のみ<更新された秘密情報>(SecureString型)に差し替えて実行する。
Set-AzKeyVaultSecret -VaultName <Key Vault名> `
-Name <シークレット名> `
-SecretValue <更新された秘密情報> ` # SecureString型
App Serviceを放置した場合、上記コマンドレットを実行してから24時間以内に自動で最新の内容(更新した内容)が反映される。
すぐに反映したいなら、アプリ設定を読み出して、変更することなく、そのまま反映する。
$site = Get-AzWebApp -Name <App Service名> ` # サイトを取得
-ResourceGroupName <App Serviceのリソースグループ名>
$appSettings = $site.SiteConfig.AppSettings # 既存のアプリ設定を抽出
# 既存のアプリ設定の一覧をハッシュテーブルに変換
$newAppSetHash = @{}
$appSettings | ForEach-Object {
$newAppSetHash[$_.Name] = $_.value
}
# ハッシュテーブルからアプリ設定の更新を実行
Set-AzWebApp -Name $site.Name `
-ResourceGroupName $site.ResourceGroup `
-AppSettings $newAppSetHash
するとアプリケーションのリサイクルとKey Vaultシークレットの再読み出しが実行され、最新のKey Vaultシークレットの内容が反映される。
■関連リンク
Copyright© Digital Advantage Corp. All Rights Reserved.