Compartir a través de


Autenticación y autorización de App Service en una base de datos vectorial

En este artículo se muestra cómo administrar la conexión entre la aplicación .NET de App Service y una solución de base de datos vectorial. Abarca el uso de identidades administradas de Microsoft Entra para los servicios admitidos y el almacenamiento seguro de cadenas de conexión para otros usuarios.

Al agregar una base de datos de vectores a su aplicación, puede habilitar [memorias semánticas o almacenes de vectores] (almacenes de vectores) para su IA. El SDK de Semantic Kernel para .NET permite implementar fácilmente el almacenamiento de memoria y la recuperación mediante la solución de base de datos vectorial preferida.

Requisitos previos

Uso de la identidad administrada de Microsoft Entra para la autenticación

Si un servicio de base de datos vectorial admite la autenticación de Microsoft Entra, puede usar una identidad administrada con App Service para acceder de forma segura a la base de datos vectorial sin tener que aprovisionar ni girar manualmente ningún secreto. Para obtener una lista de los servicios de Azure que admiten la autenticación de Microsoft Entra, consulte Servicios de Azure que admiten la autenticación de Microsoft Entra.

Adición de una identidad administrada a App Service

La aplicación puede tener dos tipos de identidades:

  • Una identidad asignada por el sistema está asociada a la aplicación y se elimina si se elimina la aplicación. Una aplicación solo puede tener una identidad asignada por el sistema.
  • Una identidad asignada por el usuario es un recurso de Azure independiente que puede asignarse a la aplicación. Una aplicación puede tener varias identidades asignadas por el usuario.

Adición de una identidad asignada por el sistema

  1. Vaya a la página de la aplicación en Azure Portal y desplácese hacia abajo hasta el grupo Configuración.
  2. Seleccione Identidad.
  3. En la pestaña Asignado por el sistema, cambie Estado a Activado y, a continuación, seleccione Guardar.

Ejecute el comando az webapp identity assign para crear una identidad asignada por el sistema:

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

Adición de una identidad asignada por el usuario

Para agregar una identidad asignada por el usuario a la aplicación, cree la identidad y, después, agregue su identificador de recurso a la configuración de la aplicación.

  1. Cree un recurso de identidad administrada asignada por el usuario siguiendo estas instrucciones.

  2. En el panel de navegación izquierdo de la página de la aplicación, desplácese hacia abajo hasta el grupo Configuración.

  3. Seleccione Identidad.

  4. Seleccione Asignado por el usuario>Agregar.

  5. Busque la identidad que creó anteriormente, selecciónela y, a continuación, elija Agregar.

    Importante

    Después de seleccionar Agregar, la aplicación se reinicia.

  1. Cree una identidad asignada por el usuario:

    az identity create --resource-group <groupName> --name <identityName>
    
  2. Asigne la identidad a la aplicación:

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

Adición de un rol de usuario de Azure OpenAI a la identidad administrada

  1. En Azure Portal, vaya al ámbito al que desea conceder acceso de base de datos. El ámbito puede ser un grupo de administración, una suscripción, un grupo de recursos o un recurso específico de Azure.
  2. En el panel de navegación de la izquierda, seleccione Control de acceso (IAM).
  3. Seleccione Agregar y, luego, Agregar asignación de roles.
  4. En la pestaña Rol, seleccione el rol adecuado que concede acceso de lectura a la base de datos vectorial.
  5. En la pestaña Miembros, seleccione la identidad administrada.
  6. En la pestaña Revisión y asignación, seleccione Revisión y asignación para asignar el rol.

Ámbito del recurso

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

Ámbito del grupo de recursos

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

Ámbito de la suscripción

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

Ámbito del grupo de administración

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

Implementación de la autenticación basada en tokens con la base de datos vectorial

Los ejemplos de código siguientes requieren estas bibliotecas adicionales:

  1. Inicialice un objeto DefaultAzureCredential para recoger la identidad administrada de la aplicación:

    // 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. Inicialice un objeto IMemoryStore para la base de datos vectorial y, después, úselo para crear un 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. Cree un objeto Kernel y, a continuación, importe el objeto ISemanticTextMemory mediante 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 el objeto Kernel para invocar un símbolo del sistema que incluya la recuperación de memoria:

    // 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://learn.microsoft.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}");
    

Uso de Key Vault para almacenar secretos de conexión

Si una base de datos vectorial no admite la autenticación de Microsoft Entra, puede usar una instancia de Key Vault para almacenar los secretos de conexión y recuperarlos con la aplicación de App Service. Mediante el uso de Key Vault para almacenar los secretos de conexión, puede compartirlos con varias aplicaciones y controlar el acceso a secretos individuales por aplicación.

Antes de seguir estos pasos, recupere una cadena de conexión para la base de datos vectorial. Por ejemplo, consulte Uso de Azure Cache for Redis con una aplicación web de ASP.NET Core.

Adición de una cadena de conexión a Key Vault

Importante

Antes de seguir estos pasos, asegúrese de que ha creado una instancia de Key Vault mediante Azure Portal.

  1. Vaya al almacén de claves en Azure Portal.
  2. En el panel de navegación izquierdo de Key Vault, seleccione Objetos y, a continuación, seleccione Secretos.
  3. Seleccione + Generar/Importar.
  4. En la pantalla Crear un secreto, elija los siguientes valores:
    • Opciones de carga: Manual.
    • Name: Escriba un nombre para el secreto. El nombre del secreto debe ser único en Key Vault.
    • Valor: la cadena de conexión de la base de datos vectorial.
    • Deje las restantes opciones con sus valores predeterminados. Seleccione Crear.
  5. Cuando reciba el mensaje que indica que el secreto se ha creado correctamente, está listo para usarse en la aplicación.

Importante

Antes de seguir estos pasos, asegúrese de que ha creado una instancia de Key Vault mediante la CLI de Azure.

  1. Conceda permisos de cuenta de usuario al almacén de claves a través del control de acceso basado en rol (RBAC), asigne un rol mediante el comando az role assignment create de la CLI de Azure:

    az role assignment create \
    --role "Key Vault Secrets User" \
    --assignee "<yourEmailAddress>" \
    --scope "/subscriptions/<subscriptionId>/resourceGroups/<resourceGroupName>/providers/Microsoft.KeyVault/vaults/<keyVaultName>"
    
  2. Agregue la cadena de conexión a Key Vault mediante el comando az keyvault secret set de la CLI de Azure:

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

Concesión del acceso de App Service a Key Vault

  1. Asigne una identidad administrada a App Service.
  2. Agregue los roles Key Vault Secrets User y Key Vault Reader a la identidad administrada.

Implementación de la recuperación de cadenas de conexión desde Key Vault

Para usar los ejemplos de código siguientes, necesita estas bibliotecas adicionales:

Estos ejemplos de código usan una base de datos de Redis, pero puede aplicarlas a cualquier base de datos vectorial que admita cadenas de conexión.

  1. Inicialice un objeto DefaultAzureCredential para recoger la identidad administrada de la aplicación:

    // 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. Agregue Key Vault al crear la configuración; esto asignará los secretos de Key Vault al objeto IConfigurationRoot:

    // User secrets let you provide connection strings when testing locally
    // For more info see: https://learn.microsoft.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 la cadena de conexión de la base de datos vectorial de Key Vault para inicializar un objeto IMemoryStore y después úsela para crear un 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. Cree un objeto Kernel y, a continuación, importe el objeto ISemanticTextMemory mediante 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 el objeto Kernel para invocar un símbolo del sistema que incluya la recuperación de memoria:

    // 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://learn.microsoft.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}");
    

Uso de la configuración de la aplicación para almacenar secretos de conexión

Si una base de datos vectorial no admite la autenticación de Microsoft Entra, puede usar la configuración de la aplicación de App Service para almacenar los secretos de conexión. Mediante la configuración de la aplicación, puede almacenar los secretos de conexión sin aprovisionar recursos adicionales de Azure.

Antes de seguir estos pasos, recupere una cadena de conexión para la base de datos vectorial. Por ejemplo, consulte Uso de Azure Cache for Redis en .NET Framework.

Adición de una cadena de conexión a la configuración de la aplicación

  1. Vaya a la página de la aplicación en Azure Portal.
  2. En el menú izquierdo de la aplicación, haga clic en Configuración>Configuración de la aplicación.
    • De forma predeterminada, los valores de la configuración de la aplicación están ocultos en el portal por seguridad.
    • Para ver un valor oculto de una configuración de aplicación, seleccione su campo Valor.
  3. Seleccione Nuevo ajuste de conexión.
  4. En la pantalla Agregar o editar cadena de conexión, elija los valores siguientes:
    • Nombre: escriba un nombre para la configuración. El nombre de la configuración HTTP debe ser único
    • Valor: la cadena de conexión de la base de datos vectorial.
    • Tipo: el tipo de conexión, Custom si no se aplica ninguna otra.
    • Deje las restantes opciones con sus valores predeterminados. Seleccione Aceptar.
  5. Seleccione Guardar de nuevo en la página Configuración.

Agregue o edite una configuración de aplicación con el comando az webapp config connection-string set de la CLI de Azure:

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

Implementación de la recuperación de cadenas de conexión desde la configuración de la aplicación

Para usar los ejemplos de código siguientes, necesita estas bibliotecas adicionales:

Estos ejemplos de código usan una base de datos de Redis, pero puede aplicarlas a cualquier base de datos vectorial que admita cadenas de conexión.

  1. Agregue variables de entorno al crear la configuración; esto asignará las cadenas de conexión al objeto IConfigurationRoot:

    // User secrets let you provide connection strings when testing locally
    // For more info see: https://learn.microsoft.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 la cadena de conexión de la base de datos vectorial de la configuración de aplicación para inicializar un objeto IMemoryStore y después úsela para crear un 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. Cree un objeto Kernel y, a continuación, importe el objeto ISemanticTextMemory mediante 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 el objeto Kernel para invocar un símbolo del sistema que incluya la recuperación de memoria:

    // 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://learn.microsoft.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}");