ベクトル データベースに対する App Service の認証と承認

この記事では、App Service .NET アプリケーションとベクトル データベース ソリューションの間の接続を管理する方法について説明します。 サポートされているサービスに Microsoft Entra マネージド ID を使用し、他のユーザーの接続文字列を安全に保存する方法について説明します。

ベクトル データベースをアプリケーションに追加することで、AI 用のセマンティック メモリを有効にすることができます。 .NET 用 Semantic Kernel SDK を使用すると、好みのベクトル データベース ソリューションを使用して、メモリの保存と呼び戻しを簡単に実装できます。

前提条件

認証に Microsoft Entra マネージド ID を使用する

ベクトル データベース サービスで Microsoft Entra 認証がサポートされている場合は、App Service でマネージド ID を使用して、シークレットを手動でプロビジョニングまたはローテーションすることなく、ベクトル データベースに安全にアクセスできます。 Microsoft Entra 認証をサポートする Azure サービスの一覧については、「Microsoft Entra 認証をサポートする Azure サービス」を参照してください。

App Service にマネージド ID を追加する

アプリケーションには 2 種類の ID を付与できます。

  • システム割り当て ID はアプリケーションに関連付けられているため、アプリが削除されると削除されます。 1 つのアプリに割り当てることができるシステム割り当て ID は 1 つだけです。
  • ユーザー割り当て ID は、アプリに割り当てることができるスタンドアロン Azure リソースです。 アプリは複数のユーザー割り当て ID を持つことができます。

システム割り当て ID を追加する

  1. Azure portal でアプリのページに移動し、[設定] グループまで下にスクロールします。
  2. [ID] を選択します。
  3. [システム割り当て済み] タブで、[状態][オン] に切り替え、[保存] を選択します。

az webapp identity assignコマンドを実行して、システム割り当て ID を作成します。

az webapp identity assign --name <appName> --resource-group <groupName>

ユーザー割り当て ID を追加する

ユーザー割り当て ID をアプリに追加するには、ID を作成し、そのリソース識別子をアプリの構成に追加します。

  1. これらの手順に従って、ユーザー割り当てマネージド ID リソースを作成します。

  2. アプリのページの左側のナビゲーション ウィンドウで、[設定] グループまで下にスクロールします。

  3. [ID] を選択します。

  4. [ユーザー割り当て済み]>[追加] を選びます。

  5. 先ほど作成した ID を見つけて選択し、[追加] を選択します。

    重要

    [追加] を選択すると、アプリが再起動します。

  1. ユーザー割り当て ID を作成する:

    az identity create --resource-group <groupName> --name <identityName>
    
  2. アプリに ID を割り当てる:

    az webapp identity assign --resource-group <groupName> --name <appName> --identities <identityId>
    

マネージド ID に Azure ロールを追加する

  1. Azure Portal で、ベクトル データベースへのアクセスを許可するスコープに移動します。 スコープは、管理グループサブスクリプションリソース グループ、または特定の Azure リソースとすることができます。
  2. 左側のナビゲーション ウィンドウで [アクセス制御 (IAM)] を選択します。
  3. [追加] を選択し、 [ロールの割り当ての追加] を選択します。
  4. [役割] タブで、ベクトル データベースへの読み取りアクセスを許可する適切なロールを選択します。
  5. [メンバー] タブで、マネージド ID を選択します。
  6. [確認と 割り当て] タブで、 [確認と割り当て] を選択して ロールを割り当てます。

リソースのスコープ

az role assignment create --assignee "<managedIdentityObjectID>" \
--role "<myVectorDbReaderRole>" \
--scope "/subscriptions/<subscriptionId>/resourcegroups/<resourceGroupName>/providers/<providerName>/<resourceType>/<resourceSubType>/<resourceName>"

リソース グループのスコープ

az role assignment create --assignee "<managedIdentityObjectID>" \
--role "<myVectorDbReaderRole>" \
--scope "/subscriptions/<subscriptionId>/resourcegroups/<resourceGroupName>"

サブスクリプションのスコープ

az role assignment create --assignee "<managedIdentityObjectID>" \
--role "<myVectorDbReaderRole>" \
--scope "/subscriptions/<subscriptionId>"

管理グループ スコープ

az role assignment create --assignee "<managedIdentityObjectID>" \
--role "<myVectorDbReaderRole>" \
--scope "/providers/Microsoft.Management/managementGroups/<managementGroupName>"

ベクトル データベースでのトークン ベースの認証を実装する

次のコード サンプルでは、これらの追加のライブラリが必要です。

  1. アプリのマネージド ID を取得する DefaultAzureCredential オブジェクトを初期化します。

    // Initialize a DefaultAzureCredential.
    // This credential type will try several authentication flows in order until one is available.
    // Will pickup Visual Studio or Azure CLI credentials in local environments.
    // Will pickup managed identity credentials in production deployments.
    TokenCredential credentials = new DefaultAzureCredential(
        new DefaultAzureCredentialOptions
        {
            // If using a user-assigned identity specify either:
            // ManagedIdentityClientId or ManagedIdentityResourceId.
            // e.g.: ManagedIdentityClientId = "myIdentityClientId".
        }
    );
    
  2. ベクトル データベースの IMemoryStore オブジェクトを初期化し、それを使用して ISemanticTextMemory を構築します。

    // Retrieve the endpoint obtained from the Azure AI Search deployment.
    // Retrieve the endpoint and deployments obtained from the Azure OpenAI deployment.
    // Must use the deployment name not the underlying model name.
    IConfigurationRoot config = new ConfigurationBuilder().AddUserSecrets<Program>().Build();
    string searchEndpoint = config["AZURE_AISEARCH_ENDPOINT"]!;
    string openAiEndpoint = config["AZURE_OPENAI_ENDPOINT"]!;
    string embeddingModel = config["AZURE_OPENAI_EMBEDDING_NAME"]!;
    
    // The Semantic Kernel SDK provides a connector extension for Azure AI Search.
    // Initialize an AzureAISearchMemoryStore using your managed identity credentials.
    IMemoryStore memoryStore = new AzureAISearchMemoryStore(searchEndpoint, credentials);
    
    // Build a SemanticMemoryStore with Azure AI Search as the store.
    // Must also include a text embedding generation service.
    ISemanticTextMemory memory = new MemoryBuilder()
        .WithAzureOpenAITextEmbeddingGeneration(embeddingModel, openAiEndpoint, credentials)
        .WithMemoryStore(memoryStore)
        .Build();
    
  3. Kernel オブジェクトを構築し、TextMemoryPlugin を使用して ISemanticTextMemory オブジェクトをインポートします。

    // Build a Kernel, include a chat completion service.
    string chatModel = config["AZURE_OPENAI_GPT_NAME"]!;
    Kernel kernel = Kernel
        .CreateBuilder()
        .AddAzureOpenAIChatCompletion(chatModel, openAiEndpoint, credentials)
        .Build();
    
    // Import the semantic memory store as a TextMemoryPlugin.
    // The TextMemoryPlugin enable recall via prompt expressions.
    kernel.ImportPluginFromObject(new TextMemoryPlugin(memory));
    
  4. Kernel オブジェクトを使用して、メモリの呼び戻しを含むプロンプトを呼び出します。

    // Must configure the memory collection, number of memories to recall, and relevance score.
    // The {{...}} syntax represents an expression to Semantic Kernel.
    // For more information on this syntax see:
    // https://video2.skills-academy.com/semantic-kernel/prompts/prompt-template-syntax
    string memoryCollection = config["AZURE_OPENAI_MEMORY_NAME"]!;
    string? result = await kernel.InvokePromptAsync<string>(
        "{{recall 'where did I grow up?'}}",
        new()
        {
            [TextMemoryPlugin.CollectionParam] = memoryCollection,
            [TextMemoryPlugin.LimitParam] = "2",
            [TextMemoryPlugin.RelevanceParam] = "0.79",
        }
    );
    Console.WriteLine($"Output: {result}");
    

Key Vault を使用して接続シークレットを保存する

ベクトル データベースで Microsoft Entra 認証がサポートされていない場合は、Key Vault を使用して接続シークレットを保存し、App Service アプリケーションで取得できます。 Key Vault を使用して接続シークレットを保存すると、それらを複数のアプリケーションで共有し、アプリケーションごとに個々のシークレットへのアクセスを制御できます。

これらの手順を実行する前に、ベクトル データベースの接続文字列を取得します。 例については、「ASP.NET Core Web アプリで Azure Cache for Redis を使用する」を参照してください。

Key Vault に接続文字列を追加する

重要

これらの手順を実行する前に、Azure Portal を使用してキー コンテナーを作成済みであることを確認してください。

  1. Azure Portal でキー コンテナーに移動します。
  2. キー コンテナーの左側のナビゲーションで、[オブジェクト] を選択し、次に [シークレット] を選択します。
  3. [生成/インポート] を選択します。
  4. [シークレットの作成] 画面で、次の値を選択します。
    • アップロード オプション: Manual
    • [名前] : シークレットの名前を入力します。 シークレットの名前は、キー コンテナー内で一意である必要があります。
    • : ベクトル データベースの接続文字列。
    • 他の値は既定値のままにしておきます。 [作成] を選択します
  5. シークレットが正常に作成されたことを示すメッセージを受け取ったら、それをアプリケーションで使用する準備が整います。

重要

これらの手順に従う前に、Azure CLI を使用してキー コンテナーを作成済みであることを確認してください。

  1. ロールベースのアクセス制御 (RBAC) を使用して、自分のユーザー アカウントにそのキー コンテナーへのアクセス許可を付与し、Azure CLI コマンド az role assignment create を使用してロールを割り当てます。

    az role assignment create \
    --role "Key Vault Secrets User" \
    --assignee "<yourEmailAddress>" \
    --scope "/subscriptions/<subscriptionId>/resourceGroups/<resourceGroupName>/providers/Microsoft.KeyVault/vaults/<keyVaultName>"
    
  2. Azure CLI コマンド az keyvault secret set を使用して、接続文字列を Key Vault に追加します。

    az keyvault secret set \
    --vault-name "<keyVaultName>" \
    --name "<secretName>" \
    --value "<connectionString>"
    

Key Vault へのアクセス権を App Service に付与する

  1. App Service にマネージド ID を割り当てます
  2. マネージド ID に Key Vault Secrets UserKey Vault Reader のロールを追加します

Key Vault からの接続文字列の取得を実装する

以下のコード サンプルを使用するには、次の追加ライブラリが必要です。

これらのコード サンプルでは Redis データベースを使用しますが、接続文字列をサポートする任意のベクトル データベースに適用できます。

  1. アプリのマネージド ID を取得する DefaultAzureCredential オブジェクトを初期化します。

    // Initialize a DefaultAzureCredential.
    // This credential type will try several authentication flows in order until one is available.
    // Will pickup Visual Studio or Azure CLI credentials in local environments.
    // Will pickup managed identity credentials in production deployments.
    TokenCredential credentials = new DefaultAzureCredential(
        new DefaultAzureCredentialOptions
        {
            // If using a user-assigned identity specify either:
            // ManagedIdentityClientId or ManagedIdentityResourceId.
            // e.g.: ManagedIdentityClientId = "myIdentityClientId".
        }
    );
    
  2. 構成の構築時に Key Vault を追加すると、Key Vault シークレットが IConfigurationRoot オブジェクトにマップされます。

    // User secrets let you provide connection strings when testing locally
    // For more info see: https://video2.skills-academy.com/en-us/aspnet/core/security/app-secrets
    IConfigurationRoot config = new ConfigurationBuilder()
        .AddUserSecrets<Program>()
        .AddAzureKeyVault(new Uri("{vaultURI}"), credentials)
        .Build();
    
    // Retrieve the Redis connection string obtained from the Key Vault.
    string redisConnectionString = config["AZURE_REDIS_CONNECT_STRING"]!;
    
  3. Key Vault のベクトル データベース接続文字列を使用して IMemoryStore オブジェクトを初期化し、それを使用して ISemanticTextMemory オブジェクトを 構築します。

    // Use the connection string to connect to the database
    IDatabase database = (
        await ConnectionMultiplexer.ConnectAsync(redisConnectionString)
    ).GetDatabase();
    
    // The Semantic Kernel SDK provides a connector extension for Redis.
    // Initialize an RedisMemoryStore using your managed identity credentials.
    IMemoryStore memoryStore = new RedisMemoryStore(database);
    
    // Retrieve the endpoint and deployments obtained from the Azure OpenAI deployment.
    // Must use the deployment name not the underlying model name.
    string openAiEndpoint = config["AZURE_OPENAI_ENDPOINT"]!;
    string embeddingModel = config["AZURE_OPENAI_EMBEDDING_NAME"]!;
    
    // Build a SemanticMemoryStore with Azure AI Search as the store.
    // Must also include a text embedding generation service.
    ISemanticTextMemory memory = new MemoryBuilder()
        .WithAzureOpenAITextEmbeddingGeneration(embeddingModel, openAiEndpoint, credentials)
        .WithMemoryStore(memoryStore)
        .Build();
    
  4. Kernel オブジェクトを構築し、TextMemoryPlugin を使用して ISemanticTextMemory オブジェクトをインポートします。

    // Build a Kernel, include a chat completion service.
    string chatModel = config["AZURE_OPENAI_GPT_NAME"]!;
    Kernel kernel = Kernel
        .CreateBuilder()
        .AddAzureOpenAIChatCompletion(chatModel, openAiEndpoint, credentials)
        .Build();
    
    // Import the semantic memory store as a TextMemoryPlugin.
    // The TextMemoryPlugin enable recall via prompt expressions.
    kernel.ImportPluginFromObject(new TextMemoryPlugin(memory));
    
  5. Kernel オブジェクトを使用して、メモリの呼び戻しを含むプロンプトを呼び出します。

    // Must configure the memory collection, number of memories to recall, and relevance score.
    // The {{...}} syntax represents an expression to Semantic Kernel.
    // For more information on this syntax see:
    // https://video2.skills-academy.com/semantic-kernel/prompts/prompt-template-syntax
    string memoryCollection = config["AZURE_OPENAI_MEMORY_NAME"]!;
    string? result = await kernel.InvokePromptAsync<string>(
        "{{recall 'where did I grow up?'}}",
        new()
        {
            [TextMemoryPlugin.CollectionParam] = memoryCollection,
            [TextMemoryPlugin.LimitParam] = "2",
            [TextMemoryPlugin.RelevanceParam] = "0.79",
        }
    );
    Console.WriteLine($"Output: {result}");
    

アプリケーション設定を使用して接続シークレットを保存する

ベクトル データベースで Microsoft Entra 認証がサポートされていない場合は、App Service アプリケーション設定を使用して接続シークレットを保存できます。 アプリケーション設定を使用すると、追加の Azure リソースをプロビジョニングすることなく、接続シークレットを保存できます。

これらの手順を実行する前に、ベクトル データベースの接続文字列を取得します。 例については、「.NET Framework で Azure Cache for Redis を使用する」を参照してください。

アプリケーション設定に接続文字列を追加する

  1. Azure Portal でアプリのページに 移動します。
  2. アプリの左側のメニューで、 [構成]>[アプリケーションの設定] を選択します。
    • 既定では、セキュリティのために、アプリケーション設定の値はポータルに表示されません。
    • アプリケーション設定の非表示の値を表示するには、[値] フィールドを選択します。
  3. [新しい接続設定] を選択します。
  4. [接続文字列の追加/編集] 画面で、次の値を選択します。
    • 名前: 設定の名前を入力します。 設定の名前は一意である必要があります。
    • : ベクトル データベースの接続文字列。
    • 種類: 接続の種類 (他に適用するものがない場合は Custom)。
    • 他の値は既定値のままにしておきます。 [OK] を選択します。
  5. [構成] ページで [保存] を選択します。

Azure CLI コマンド az webapp config connection-string set を使用してアプリ設定を追加または編集します。

az webapp config connection-string set \
--name "<appName>" \
--resource-group "<groupName>" \
--connection-string-type "<connectionType>" \
--settings <connectionName>='<connectionString>'

アプリ設定からの接続文字列の取得を実装する

以下のコード サンプルを使用するには、次の追加ライブラリが必要です。

これらのコード サンプルでは Redis データベースを使用しますが、接続文字列をサポートする任意のベクトル データベースに適用できます。

  1. 構成の構築時に環境変数を追加すると、接続文字列が IConfigurationRoot オブジェクトにマップされます。

    // User secrets let you provide connection strings when testing locally
    // For more info see: https://video2.skills-academy.com/en-us/aspnet/core/security/app-secrets
    IConfigurationRoot config = new ConfigurationBuilder()
        .AddUserSecrets<Program>()
        .AddEnvironmentVariables()
        .Build();
    
    // Retrieve the Redis connection string obtained from the app settings.
    // The connection string name should match the entry in application settings
    string redisConnectionString = config.GetConnectionString("AZURE_REDIS")!;
    
  2. アプリ設定からのベクトル データベース接続文字列を使用して IMemoryStore オブジェクトを初期化し、それを使用して ISemanticTextMemory オブジェクトを構築します。

    // Use the connection string to connect to the database
    IDatabase database = (
        await ConnectionMultiplexer.ConnectAsync(redisConnectionString)
    ).GetDatabase();
    
    // The Semantic Kernel SDK provides a connector extension for Redis.
    // Initialize an RedisMemoryStore using your managed identity credentials.
    IMemoryStore memoryStore = new RedisMemoryStore(database);
    
    // Retrieve the endpoint and deployments obtained from the Azure OpenAI deployment.
    // Must use the deployment name not the underlying model name.
    string openAiEndpoint = config["AZURE_OPENAI_ENDPOINT"]!;
    string embeddingModel = config["AZURE_OPENAI_EMBEDDING_NAME"]!;
    
    // Build a SemanticMemoryStore with Azure AI Search as the store.
    // Must also include a text embedding generation service.
    ISemanticTextMemory memory = new MemoryBuilder()
        .WithAzureOpenAITextEmbeddingGeneration(embeddingModel, openAiEndpoint, credentials)
        .WithMemoryStore(memoryStore)
        .Build();
    
  3. Kernel オブジェクトを構築し、TextMemoryPlugin を使用して ISemanticTextMemory オブジェクトをインポートします。

    // Build a Kernel, include a chat completion service.
    string chatModel = config["AZURE_OPENAI_GPT_NAME"]!;
    Kernel kernel = Kernel
        .CreateBuilder()
        .AddAzureOpenAIChatCompletion(chatModel, openAiEndpoint, credentials)
        .Build();
    
    // Import the semantic memory store as a TextMemoryPlugin.
    // The TextMemoryPlugin enable recall via prompt expressions.
    kernel.ImportPluginFromObject(new TextMemoryPlugin(memory));
    
  4. Kernel オブジェクトを使用して、メモリの呼び戻しを含むプロンプトを呼び出します。

    // Must configure the memory collection, number of memories to recall, and relevance score.
    // The {{...}} syntax represents an expression to Semantic Kernel.
    // For more information on this syntax see:
    // https://video2.skills-academy.com/semantic-kernel/prompts/prompt-template-syntax
    string memoryCollection = config["AZURE_OPENAI_MEMORY_NAME"]!;
    string? result = await kernel.InvokePromptAsync<string>(
        "{{recall 'where did I grow up?'}}",
        new()
        {
            [TextMemoryPlugin.CollectionParam] = memoryCollection,
            [TextMemoryPlugin.LimitParam] = "2",
            [TextMemoryPlugin.RelevanceParam] = "0.79",
        }
    );
    Console.WriteLine($"Output: {result}");