Autenticar e autorizar o Serviço de Aplicativo em um banco de dados vetorial

Este artigo demonstra como gerenciar a conexão entre o aplicativo .NET do Serviço de Aplicativo e uma solução de banco de dados vetorial. Ele aborda o uso de identidades gerenciadas do Microsoft Entra para serviços com suporte e o armazenamento seguro de cadeias de conexão para outras pessoas.

Ao adicionar um banco de dados vetorial ao seu aplicativo, você pode habilitar [memórias semânticas ou repositórios de vetores] (repositórios de vetores) à sua IA. O SDK de Kernel Semântico para .NET permite que você implemente facilmente o armazenamento de memória e o recall usando sua solução de banco de dados vetorial preferencial.

Pré-requisitos

Usar identidade gerenciada do Microsoft Entra para autenticação

Se um serviço de banco de dados vetorial der suporte à autenticação do Microsoft Entra, você poderá usar uma identidade gerenciada com o Serviço de Aplicativo para acessar com segurança seu banco de dados vetorial sem precisar provisionar ou girar manualmente os segredos. Para obter uma lista dos serviços do Azure que dão suporte à autenticação do Microsoft Entra, consulte Serviços do Azure que dão suporte à autenticação do Microsoft Entra.

Adicionar uma identidade gerenciada ao Serviço de Aplicativo

Seu aplicativo pode receber dois tipos de identidades:

  • Uma identidade atribuída pelo sistema é vinculada ao seu aplicativo e é excluída se o seu aplicativo for excluído. Um aplicativo pode ter apenas uma identidade atribuída pelo sistema.
  • Uma identidade atribuída pelo usuário é um recurso independente do Azure que pode ser atribuído ao seu aplicativo. Um aplicativo pode ter várias identidades atribuídas pelo usuário.

Adicionar uma identidade atribuída pelo sistema

  1. Navegue até a página do aplicativo no portal do Azure e role para baixo até o grupo Configurações.
  2. Selecionar Identidade.
  3. Na guia Atribuído pelo Sistema, alterne Status para Ativado e selecione Salvar.

Execute o comando az webapp identity assign para criar uma identidade atribuída pelo sistema:

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

Adicionar uma identidade atribuída pelo usuário

Para adicionar uma identidade atribuída pelo usuário ao seu aplicativo, crie a identidade e adicione seu identificador de recurso à configuração do aplicativo.

  1. Crie um recurso de identidade gerenciada atribuída pelo usuário seguindo estas instruções.

  2. No painel de navegação esquerdo da página do aplicativo, role para baixo até o grupo Configurações.

  3. Selecionar Identidade.

  4. Selecione Usuário atribuído>Adicionar.

  5. Localize a identidade que você criou anteriormente, selecione-a e clique em Adicionar.

    Importante

    Depois de selecionar Adicionar, o aplicativo será reiniciado.

  1. Crie uma identidade atribuída pelo usuário:

    az identity create --resource-group <groupName> --name <identityName>
    
  2. Atribua a identidade ao seu aplicativo:

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

Adicionar uma função do Azure à sua identidade gerenciada

  1. No portal do Azure, navegue até o escopo ao qual você deseja conceder acesso ao banco de dados vetorial. O escopo pode ser um Grupo de gerenciamento, Assinatura, Grupo de recursos ou um recurso específico do Azure.
  2. No painel de navegação à esquerda, selecione Controle de acesso (IAM).
  3. Selecione Adicionar e Adicionar atribuição de função.
  4. Na guia Função, selecione a função apropriada que concede acesso de leitura ao banco de dados vetorial.
  5. Na guia Membros, selecione a identidade gerenciada.
  6. Na guia Examinar + atribuir, selecione Examinar + atribuir para atribuir a função.

Escopo do recurso

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

Escopo do grupo de recursos

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

Escopo da assinatura

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

Escopo do grupo de gerenciamento

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

Implementar a autenticação baseada em token com o banco de dados vetorial

Os exemplos de código a seguir exigem estas bibliotecas adicionais:

  1. Inicialize um objeto DefaultAzureCredential para obter a identidade gerenciada do aplicativo:

    // 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. Inicialize um objeto IMemoryStore para o banco de dados vetorial e, em seguida, use-o para criar um 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()
        .WithOpenAITextEmbeddingGeneration(embeddingModel, openAiEndpoint)
        .WithMemoryStore(memoryStore)
        .Build();
    
  3. Crie um objeto Kernel e depois importe o objeto ISemanticTextMemory usando o TextMemoryPlugin:

    // 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. Use o objeto Kernel para invocar um prompt que inclua o recall de memória:

    // 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}");
    

Usar o Key Vault para armazenar segredos de conexão

Se um banco de dados vetorial não der suporte à autenticação do Microsoft Entra, você poderá usar um Key Vault para armazenar seus segredos de conexão e recuperá-los com seu aplicativo do Serviço de Aplicativo. Ao usar um Key Vault para armazenar seus segredos de conexão, você pode compartilhá-los com vários aplicativos e controlar o acesso a segredos individuais por aplicativo.

Antes de seguir estas etapas, recupere uma cadeia de conexão para o banco de dados vetorial. Por exemplo, consulte Usar o Cache do Azure para Redis com um aplicativo web ASP.NET Core.

Adicionar uma cadeia de conexão ao Key Vault

Importante

Antes de seguir estas etapas, verifique se você criou um Key Vault usando o portal do Azure.

  1. Navegue até seu cofre de chaves no portal do Azure.
  2. Na navegação à esquerda do Key Vault, selecione Objetos e selecione Segredos.
  3. Selecione + Gerar/importar.
  4. Na tela Criar um segredo, escolha os seguintes valores:
    • Opções de upload: Manual.
    • Nome: Digite um nome para o segredo. O nome do segredo precisa ser exclusivo dentro de um Key Vault.
    • Valor: a cadeia de conexão do banco de dados vetorial.
    • Deixe os outros valores com seus padrões. Selecione Criar.
  5. Quando você recebe a mensagem de que o segredo foi criado com sucesso, ele está pronto para ser usado em seu aplicativo.

Importante

Antes de seguir estas etapas, verifique se você criou um Key Vault usando a CLI do Azure.

  1. Conceda permissões da sua conta de usuário ao cofre de chaves por meio do RBAC (Controle de Acesso Baseado em Função), atribua uma função usando o comando az role assignment create da CLI do Azure:

    az role assignment create \
    --role "Key Vault Secrets User" \
    --assignee "<yourEmailAddress>" \
    --scope "/subscriptions/<subscriptionId>/resourceGroups/<resourceGroupName>/providers/Microsoft.KeyVault/vaults/<keyVaultName>"
    
  2. Adicione a cadeia de conexão ao Key Vault usando o comando az keyvault secret set da CLI do Azure:

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

Conceder ao Serviço de Aplicativo acesso ao Key Vault

  1. Atribuir uma identidade gerenciada ao seu Serviço de Aplicativo.
  2. Adicione as funções Key Vault Secrets User e Key Vault Reader à sua identidade gerenciada.

Implementar a recuperação de cadeia de conexão do Key Vault

Para usar os exemplos de código a seguir, você precisa destas bibliotecas adicionais:

Esses exemplos de código usam um banco de dados Redis, mas você pode aplicá-los a qualquer banco de dados vetorial que dê suporte a cadeias de conexão.

  1. Inicialize um objeto DefaultAzureCredential para obter a identidade gerenciada do aplicativo:

    // 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. Adicione o Key Vault ao compilar sua configuração, isso mapeará seus segredos do Key Vault para o objeto IConfigurationRoot:

    // User secrets let you provide connection strings when testing locally
    // For more info see: https://video2.skills-academy.com/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. Use a cadeia de conexão de banco de dados vetorial do Key Vault para inicializar um objeto IMemoryStore e, em seguida, use-a para criar um 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()
        .WithOpenAITextEmbeddingGeneration(embeddingModel, openAiEndpoint)
        .WithMemoryStore(memoryStore)
        .Build();
    
  4. Crie um objeto Kernel e depois importe o objeto ISemanticTextMemory usando o TextMemoryPlugin:

    // 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. Use o objeto Kernel para invocar um prompt que inclua o recall de memória:

    // 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}");
    

Usar configurações de aplicativo para armazenar segredos de conexão

Se um banco de dados vetorial não der suporte à autenticação do Microsoft Entra, você pode usar as configurações do aplicativo do Serviço de Aplicativo para armazenar seus segredos de conexão. Ao usar configurações de aplicativo, você pode armazenar seus segredos de conexão sem provisionar recursos adicionais do Azure.

Antes de seguir estas etapas, recupere uma cadeia de conexão para o banco de dados vetorial. Por exemplo, consulte Usar o Cache do Azure para Redis no .NET Framework.

Adicionar uma cadeia de conexão às configurações do aplicativo

  1. Navegue até a página do seu aplicativo no portal do Azure.
  2. No menu à esquerda do aplicativo, selecione Configurações>Configurações do aplicativo.
    • Por padrão, os valores das configurações do aplicativo ficam ocultos no portal para segurança.
    • Para ver um valor oculto de uma configuração de aplicativo, selecione o campo Valor.
  3. Selecione Nova configuração de conexão.
  4. Na tela Adicionar/Editar cadeia de conexão, escolha os seguintes valores:
    • Nome: digite um nome para a configuração. O nome da configuração precisa ser exclusivo.
    • Valor: a cadeia de conexão do banco de dados vetorial.
    • Tipo: o tipo de conexão, Custom se nenhum outro se aplicar.
    • Deixe os outros valores com seus padrões. Selecione OK.
  5. Selecione Salvar de volta na página de Configuração.

Adicionar ou editar uma configuração de aplicativo com o comando az webapp config connection-string set da CLI do Azure:

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

Implementar a recuperação de cadeia de conexão das configurações do aplicativo

Para usar os exemplos de código a seguir, você precisa destas bibliotecas adicionais:

Esses exemplos de código usam um banco de dados Redis, mas você pode aplicá-los a qualquer banco de dados vetorial que dê suporte a cadeias de conexão.

  1. Adicione variáveis de ambiente ao criar sua configuração, isso mapeará suas cadeias de conexão para o objeto 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. Use a cadeia de conexão de banco de dados vetorial da configurações do aplicativo para inicializar um objeto IMemoryStore e, em seguida, use-a para criar um 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()
        .WithOpenAITextEmbeddingGeneration(embeddingModel, openAiEndpoint)
        .WithMemoryStore(memoryStore)
        .Build();
    
  3. Crie um objeto Kernel e depois importe o objeto ISemanticTextMemory usando o TextMemoryPlugin:

    // 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. Use o objeto Kernel para invocar um prompt que inclua o recall de memória:

    // 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}");