はじめに

今回はAzureが提供するセキュリティ関連ソリューションである「Azure Key Vault」について説明します。Azure Key Vaultの仕組みと機密情報を保管する方法について説明していきます。

Azure Key Vaultとは

Azure Key Vaultは、システムにまつわる機密情報を保管する保管庫(Vault)としての役割と、保管した機密情報に安全にアクセスするための仕組みを備えたAzureのセキュリティ関連サービスです。APIキー、パスワード、証明書などの、システムへのアクセスを制御する際に使用するセンシティブな情報を保管できます。 これらの機密情報を一元的に管理することでセキュリティリスクが局所化されます。Azure Key Vaultでは後述する認証認可の仕組みによって外部からの不正なアクセスを防ぐことはもちろんのこと、組織内部からのセキュリティリスクにも対応することができます。Azure Key Vaultではアプリケーション内に一切の機密情報を持つことなくシステムを構築できるようになるため、例えば外部の開発ベンダーにアプリケーションの開発を依頼する場合などでも、ベンダーに対してパスワードを伝えることなくアプリケーションを構築することができ組織内部からの機密情報流出リスクを抑えることができます。

Azure Key Vaultのしくみ

Azure Key Vaultは、Azureの環境上に作成される「キーコンテナー」と呼ばれる仮想のコンテナー内に機密情報であるAPIキー、パスワード、証明書などを格納します。キーコンテナーは複数作成できるので、システム別やセキュリティーポリシー別などの単位でキーコンテナーを分けて運用することが可能となっています。

Azure Key Vaultに格納されているデータの参照には、ユーザーやアプリケーションに認証と認可の権限が正しく付与されている必要があります(*)。Azure Key Vaultにおけるユーザーやアプリケーションの認証は、Azure Active Directory(AAD)によって行われます。

*)認証とは、IDとパスワードの入力等、利用者しか知りえない情報を使って本人確認を行うこと。認可とは、認証済みの利用者に対して、参照や操作を行うための権限を与えること。

AADは、Azureのサブスクリプションと一対一で紐づくAzureの認証基盤です。普段Azureポータルにログインする際に使用しているユーザー情報も、このAADで管理されています。AADに登録されているユーザーやアプリケーションのみが、Azure Key Vaultへのアクセス権限を持ちます。

一方で認可についてはAzure Key Vault側で制御します。Azure Key Vault上に作成されたキーコンテナーごとに認可の設定を変えられるため、柔軟に設定することが可能です。認可によって、ユーザーやアプリケーションがキーコンテナーに対して行うことができる操作の種類を変更することができます。

  • Azure Key Vaultの概念図

    Azure Key Vaultの概念図

Azure Key Vaultに保存できる機密情報の種類

Azure Key Vaultに保存できる機密情報は、「キー」、「シークレット」、「証明書」の大きく3種類に分類できます。

「キー」は暗号化キーとも呼ばれるもので、データを暗号化する際に使用されるものです。Azure Key Vaultは他のAzureリソースとの連携が容易となっているため、Azure VM(仮想マシン)のディスクやSQL Databaseに保存しているデータの暗号化を行う際などに使用されることもあります。Azure Key Vaultのキーでは、RSA暗号と楕円曲線暗号の2種類の暗号化方式をサポートしています。

「シークレット」は機密情報として扱う必要のある文字列です。代表的なものにはパスワードがあります。Azure Key Vaultではシークレットの文字列は暗号化された状態で保管されており、参照する際に復号されます。

「証明書」では、SSL(Secure Sockets Layer)/TLS(Transport Layer Security)証明書の作成や管理を行うことができ、他のAzureリソースなどでその証明書を使用することができます。

Azure Key Vaultを使ってシークレットを管理しよう

ここからは実際にAzure Key Vaultを使用したアプリケーションを作成してみましょう。アプリケーションの構成は、プログラムからデータベースに接続してデータを取得するという非常に単純なものにします。Azure Key Vaultのキーコンテナーには、データベースの接続に使用するパスワードを保存し、プログラムがキーコンテナーを参照するようにします。

なおこのサンプルアプリケーションでは、プログラムからキーコンテナーに保管されているデータベースのユーザーIDとパスワードが取得できるところまでがポイントのため、データベースの作成と接続に関しては割愛します。

キーコンテナーにデータベースのパスワードを保管しよう

まずはAzure Key Vaultに今回のサンプルアプリケーション用のキーコンテナーを作成します。

[1]キーコンテナーの作成
Azureポータルにログインして左側のメニューから「すべてのサービス」を選択し、検索ボックスに「キーコンテナー」と入力して表示される「キー コンテナー」を選択します。

  • Azureポータルでキーコンテナーを検索する

    Azureポータルでキーコンテナーを検索する

「追加」ボタン、あるいは画面中央に表示されている「キー コンテナーの作成」ボタンを選択します。

  • キーコンテナーを追加する

    キーコンテナーを追加する

キーコンテナーの新規作成画面が表示されるので、必須項目を入力していきます。「名前」はキーコンテナーの名前です。Azure上で一意となる任意の名前を入力します。「サブスクリプション」はお手持ちのものを、「リソースグループ」は任意のリソースグループを選択するか新規作成します。「場所」も任意の場所を選択します。

「価格レベル」は「標準」を選択します。Azure Key Vaultには「標準」と「プレミアム」の2つの価格レベルが存在します。プレミアムは標準価格レベルの機能に加え、ハードウェアによるキーの保護を行うことができるようになります。価格の詳細については、Azure Key Vaultの価格ページをご覧ください。 「アクセスポリシー」、「仮想ネットワーク アクセス」についてはデフォルトのままとします。

「アクセスポリシー」はデフォルトでは、Azureポータルに現在ログインしているユーザーアカウント(プリンシパル)が1つだけ選択された状態となっています。

「仮想ネットワーク アクセス」は、すべてのネットワークからのアクセスを許可するようにします。これはあくまでネットワークレイヤでのキーコンテナーへのアクセス制御ですので、すべてのネットワークを選択したからといってキーコンテナーが誰からでも参照できてしまうという訳ではありません。参照できるのは、前述の通りAzure Active Directoryによって認証されたユーザーやアプリケーションのみです。

  • キーコンテナーの新規作成

    キーコンテナーの新規作成

全ての項目の入力が完了したら画面下部の「作成」ボタンを選択してキーコンテナーの作成を開始します。しばらく待つと作成が完了します。「キー コンテナー」の画面で「更新」ボタンを選択すると作成したキーコンテナーが表示されます。

  • 作成したキーコンテナーの一覧

    作成したキーコンテナーの一覧

[2]シークレットの作成
作成したキーコンテナー名を選択してキーコンテナーのダッシュボード画面に移動します。パスワードのようなセキュアなテキスト情報は「シークレット」としてキーコンテナーに保管することができます。左側に表示されているメニュー一覧から、「シークレット」を選択して「生成/インポート」を選択します。

  • ダッシュボードからシークレットを選択する

    ダッシュボードからシークレットを選択する

シークレットの新規作成画面に移動するのでシークレットの情報を入力していきます。「アップロード オプション」は「手動」のままにします。「名前」にはシークレットを識別するための分かりやすい名前を入力します。今回は「sample-db-password」という名前を入力します。「値」にはシークレットの実体を入力します。今回はパスワードとして、「dbpassword」という内容を入力します。 「コンテンツの種類」はシークレットが何の値であるのかを分かりやすくするためのタグのようなものです。今回は「データベースのパスワード」と入力します。この「コンテンツの種類」はシークレット作成後にシークレットの一覧画面で確認することができます。

「アクティブ化する日を設定しますか?」と「有効期限を設定しますか?」は、シークレットに有効期限を設ける際に使用する項目ですが、今回はチェックを入れずに無期限のシークレットとして作成します。最後の「有効ですか?」は「はい」を選択して、シークレットがキーコンテナー上でアクティブになるようにします。

  • シークレットの新規作成

    シークレットの新規作成

入力が終わったら画面下部の「作成」ボタンを選択してシークレットを作成します。

Webアプリを作成し、キーコンテナーからパスワードを取得してみよう

次に、キーコンテナーに作成したシークレットをアプリケーションで取得してみましょう。ここでは、ASP.NETアプリケーションをVisual Studioで作成していきます。

[1]Visual Studioからプロジェクトを新規作成
Visual Studioを起動し、メニューから「ファイル」→「新規」→「プロジェクト」を選択して新しいプロジェクトウィザードを表示します。「.NET Core」のカテゴリから「ASP.NET Core Web アプリ」を選択し、「名前」に「KeyVaultWeb」と入力して「OK」ボタンを選択します。

  • 新規プロジェクトの選択

    新規プロジェクトの選択

プロジェクトテンプレートから「Webアプリケーション」を選択、「HTTPS用の構成」のチェックを外して「OK」ボタンを選択します。

  • ターゲットフレームワークの選択

    プロジェクトテンプレートの選択

[2]NuGetでのパッケージの追加
プロジェクトが作成されたらAzure Key Vaultとの連携に必要なライブラリを.NETのパッケージ管理ツールであるNuGetからアプリに追加していきます。ソリューションエクスプローラーからプロジェクト展開し、「依存関係」というフォルダーを右クリックして「NuGetパッケージの管理」を選択します。

  • NuGetパッケージの追加

    NuGetパッケージの追加

「NuGetパッケージの管理」ウィンドウが表示されたら参照タブを選択し、検索ボックスに「Microsoft.Azure.KeyVault」と入力し、表示された検索結果の一覧から同名のパッケージを選択して右側の「インストール」ボタンを選択します。

  • パッケージ名を指定してパッケージを追加する

    パッケージ名を指定してパッケージを追加する

パッケージの追加が完了した旨のメッセージがVisual Studio上に表示されたら、同様の手順で以下の3パッケージを追加していきます。

・Microsoft.Azure.KeyVault.Extensions
・Microsoft.Azure.Services.AppAuthentication
・Microsoft.Extensions.Configuration.AzureKeyVault

[3]プログラムの修正(Webアプリケーション起動用ファイル)
必要なパッケージの追加が完了したら「Program.cs」を以下のように修正し、キーコンテナーとの接続設定を追加します。

Azure Key Vaultのキーコンテナーの設定を追加(Program.cs)

using System;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;

using Microsoft.Azure.KeyVault;
using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Extensions.Configuration.AzureKeyVault;

namespace KeyVaultWeb
{
    public class Program
    {
        public static void Main(string[] args)
        {
            BuildWebHost(args).Run();
        }

        public static IWebHost BuildWebHost(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((ctx, builder) => // Webアプリに設定を追加する ・・・①
                {
                    // キーコンテナーのDNS名を設定する ・・・②
                    var keyVaultEndpoint = "https://zerokara-db-keys.vault.azure.net/";

                    // Azure Key Vaultに接続するための追加の設定を記述する ・・・③
                    // ③-1 アプリをAzureに認証するためのアクセストークン取得プロバイダーのインスタンス化
                    var azureServiceTokenProvider = new AzureServiceTokenProvider();
                    // ③-2 Azure Key Vaultに接続するためのクライアントのインスタンス化
                    var keyVaultClient = new KeyVaultClient(
                        new KeyVaultClient.AuthenticationCallback(
                            azureServiceTokenProvider.KeyVaultTokenCallback));
                    // ③-3 Azure Key Vault(キーコンテナー)からシークレットにアクセスするための設定をbuilderに追加
                    builder.AddAzureKeyVault(
                        keyVaultEndpoint, keyVaultClient, new DefaultKeyVaultSecretManager());
                }
             ).UseStartup<Startup>()
              .Build();
    }
}

「Program.cs」では、Webアプリケーションとしてアプリを起動する際の振る舞いについて記述できます。今回はアプリがAzure Key Vaultとやりとりをできるように設定を追加しています(①)。このアプリが参照するAzure Key VaultのキーコンテナーのDNS名を②で設定しています。キーコンテナーのDNS名は、Azureポータルでキーコンテナーを表示し、「概要」メニューから確認することができます。

  • キーコンテナーのDNS名の確認

    キーコンテナーのDNS名の確認

このDNS名を使ってWebアプリケーションにAzure Key Vaultとの連携用の設定を追加していきます(③)。まずはこのアプリケーションがAzureに認証され、他のAzureサービスにアクセスするためのアクセストークンを取得する必要があります。これには、「AzureServiceTokenProvider」のインスタンスを使用します(③-1)。今回はAzure Key Vaultへのアクセスが必要なため、Azure Key Vaultに接続するためのクライアントである「KeyVaultClient」のインスタンスにアクセストークンを設定します(③-2)。最後に③-3でAzure Key Vault用の設定をこのアプリの設定情報として追加しています。ここではキーコンテナーのDNS名、Azure Key Vault用のクライアント、シークレットへの操作行うことを表す「DefaultKeyVaultSecretManager」のインスタンスの3つを引数に設定することで、どのキーコンテナーのどの情報にアクセスするのかを具体的に記述しています。

[4]プログラムの修正(画面表示用ファイル)
Azure Key Vaultとの接続に必要なコードが実装できたので、次にキーコンテナーからシークレットを取得してその内容を表示するコードを記述します。「ASP.NET Core Web アプリ」のプロジェクトテンプレートからプロジェクトを作成した場合、あらかじめWebの画面が実装されていますので、その中の「index」のページをシークレットの値を表示するように「Pages/index.cshtml」を修正してみます。

キーコンテナーから取得したシークレットの値を表示する(Pages/Index.cshtml)

@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}

<div class="text-center">
    <h1 class="display-4">Welcome</h1>
    <p>Learn about <a href="https://docs.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
  <!-- モデルから取得した値を表示 ・・・① -->
    <p>@Model.Secret</p>
</div>

画面上にシークレットの内容を表示するための記述を一行追記しています(①)。「@Model.Secret」の「@Model」はこの画面に対応するモデルクラスである「Index.cshtml.cs」を指しており、そのモデルクラスの「Secret」というプロパティを参照して表示するようにしています。 それでは次にモデルクラスである「Index.cshtml.cs」を編集します。

キーコンテナーから取得したシークレットの値を表示する(Pages/index.cshtml.cs)

using System;
using Microsoft.AspNetCore.Mvc.RazorPages;

using Microsoft.Extensions.Configuration;

namespace KeyVaultWeb.Pages
{
    public class IndexModel : PageModel
    {
        private readonly IConfiguration _configuration = null;

        public string Secret { get; set; }

        // このクラスに設定情報を注入する ・・・①
        public IndexModel(IConfiguration configuration)
        {
            _configuration = configuration;
        }

        public void OnGet()
        {
            // キーコンテナーに保管しているシークレットの名前を指定してシークレットの値を取得して画面に表示する ・・・②
            Secret = "My DB password = " + _configuration["sample-db-password"];
        }
    }
}

「Index」ページに表示する内容を動的に変更するために使用する「Index.cshtml.cs」クラスのコンストラクタに、アプリケーション全体の設定情報を保持する「IConfiguration」のインスタンスを注入しています(①)。このインスタンスには、先程「Program.cs」で設定したAzure Key Vaultの設定情報も含まれているので、作成したシークレットの名前(sample-db-password)を指定することでシークレットの値を取得することができるようになります(②)。

[5]Azure App Serviceへのアプリケーションのデプロイ
ここまで実装が完了したら、作成したアプリケーションをAzure App Serviceにデプロイしてみます。ソリューションエクスプローラーでプロジェクト名を右クリックし、「発行」を選択します。

  • Visual StudioからAzureにアプリをデプロイする

    Visual StudioからAzureにアプリをデプロイする

「発行先を選択」というウィザードが表示されるので、「App Service」が選択され「新規作成」にチェックが入った状態で「発行」ボタンを選択します。

  • Visual StudioからApp Serviceを新規作成する

    Visual StudioからApp Serviceを新規作成する

新規作成するApp Serviceの内容を入力していきます。Visual Studio上からAzureにログインしていない場合は、ウィザードの右上に「アカウントの追加」と表示されているので、ここからAzureにログインします。ログインが成功すると、App Serviceの設定画面が表示されます。 「アプリ名」には、Azure上で一意となるApp Serviceの名前を入力します。「サブスクリプション」、「リソースグループ」はキーコンテナーを作成したものと同じものを選択します。「ホスティングプラン」は、App Serviceのマシンスペックに関わる内容です。「新規作成」を選択するとホスティングプランの構成ウィザードが表示されます。「App Service プラン」には任意のプラン名称を入力します。「場所」はキーコンテナーと同じものを、「サイズ」は「無料」を選択します。「OK」を選択してホスティングプランの構成ウィザードを閉じます。最後に「Application Insights」は「なし」のままとし、「作成」を選択してApp Serviceの作成を開始します。

  • 新しいApp Serviceの内容を入力する

    新しいApp Serviceの内容を入力する

しばらく待っているとApp Serviceの作成が完了し、ブラウザで作成したApp ServiceのURLに自動的にアクセスします。この時点では、以下の図のように「HTTP Error 500」のエラー画面が表示されてしまいます。これはApp ServiceにデプロイしたアプリケーションがAzure Key Vaultへのアクセス権を有していないためで、この後の手順でアクセス権を付与していきます。

  • デプロイ直後のアプリ画面

    デプロイ直後のアプリ画面

[6]アプリケーションへのAzure Key Vaultアクセス権限の付与
App ServiceにデプロイしたアプリケーションにAzure Key Vaultへのアクセス権限を付与していきます。Azureポータルを表示し、左側メニューから「App Service」を選択し、作成したApp Service名を選択します。App Serviceのメニューから「ID」を選択し、「Azure Active Directoryに登録する」を「オン」にして「保存」を選択します。これにより、アプリケーションがAzure Active Directoryに登録された状態となります。

  • App ServiceのマネージドサービスIDを有効にする

    App ServiceのマネージドIDを有効にする

次に、Azure Key Vault側でアプリケーションへの権限付与を行います。作成したキーコンテナーを表示し、「アクセス ポリシー」を選択して「新規追加」を選択します。

  • キーコンテナーにアクセスポリシーを追加する

    キーコンテナーにアクセスポリシーを追加する

アクセスポリシーの追加画面に移ったら「プリンシパルの選択」を選択し、入力ボックスに先程作成したApp Serviceの名前を入力します。正しく入力されると、アプリケーション名が表示されるのでクリックし、画面下部の「選択」ボタンを選択します。

  • プリンシパルとしてApp Serviceにデプロイしたアプリケーションを選択する

    プリンシパルとしてApp Serviceにデプロイしたアプリケーションを選択する

プリンシパルが選択された状態となったら、次に「シークレットのアクセス許可」のプルダウンを選択します。「シークレットの管理操作」セクションにある「取得」と「一覧」にチェックを入れます。

  • シークレットへのアクセス許可を付与する

    シークレットへのアクセス許可を付与する

ここまで入力し、画面下部の「OK」ボタンを選択します。アクセスポリシーの一覧でアプリケーションが追加されていることを確認し、「保存」を選択します。

  • アクセスポリシーの追加を完了する

    アクセスポリシーの追加を完了する

[7]アプリケーションの動作確認
これで、App ServiceにデプロイしたアプリケーションがAzure Key Vaultと連携できるようになりました。ブラウザに戻ってアプリケーションのページを更新すると本来のトップページが表示されるようになります。ヘッダー部分にクッキーの使用許可のダイアログが被さってしまっているので、「Accept」を選択して画面を表示すると、「My DB password = dbpassword」と、キーコンテナー内のシークレットに保存したパスワードの値が表示されていることが確認できるかと思います。

  • Index画面

    Index画面

本来パスワードは秘匿する内容ですので画面上に表示すべきではありませんが、今回はキーコンテナーに保管された内容をアプリケーションから取得できるかの検証のために画面に表示をしました。実際のアプリケーション開発では今回のサンプルを応用して、キーコンテナーから取得したパスワードを使ってデータベースの接続文字列を組み立てたり、あるいは接続文字列の全てをシークレットに保管するなどして、データベース接続の実装を行うことができます。

まとめ

今回はAzure Key Vaultについて説明しました。Azureを使用していてキーやシークレットの保管場所に悩んだ場合は、Azure Key Vaultの使用を検討してみてはいかがでしょうか。

WINGSプロジェクト 秋葉龍一 著/山田祥寛監修
<WINGSプロジェクトについて>テクニカル執筆プロジェクト(代表山田祥寛)。海外記事の翻訳から、主にWeb開発分野の書籍・雑誌/Web記事の執筆、講演等を幅広く手がける。一緒に執筆をできる有志を募集中