Authenticate and authorize App Service to a vector database
This article demonstrates how to manage the connection between your App Service .NET application and a vector database solution. It covers using Microsoft Entra managed identities for supported services and securely storing connection strings for others.
By adding a vector database to your application, you can enable [semantic memories or vector stores](vector stores) for your AI. The Semantic Kernel SDK for .NET enables you to easily implement memory storage and recall using your preferred vector database solution.
Prerequisites
- An Azure account with an active subscription. Create an account for free.
- .NET SDK
Microsoft.SemanticKernel
NuGet packageMicrosoft.SemanticKernel.Plugins.Memory
NuGet package- Create and deploy a .NET application to App Service
- Create and deploy a vector database solution
Use Microsoft Entra managed identity for authentication
If a vector database service supports Microsoft Entra authentication, you can use a managed identity with your App Service to securely access your vector database without having to manually provision or rotate any secrets. For a list of Azure services that support Microsoft Entra authentication, see Azure services that support Microsoft Entra authentication.
Add a managed identity to App Service
Your application can be granted two types of identities:
- A system-assigned identity is tied to your application and is deleted if your app is deleted. An app can have only one system-assigned identity.
- A user-assigned identity is a standalone Azure resource that can be assigned to your app. An app can have multiple user-assigned identities.
Add a system-assigned identity
- Navigate to your app's page in the Azure portal, and then scroll down to the Settings group.
- Select Identity.
- On the System assigned tab, toggle Status to On, and then select Save.
Run the az webapp identity assign
command to create a system-assigned identity:
az webapp identity assign --name <appName> --resource-group <groupName>
Add a user-assigned identity
To add a user-assigned identity to your app, create the identity, and then add its resource identifier to your app config.
Create a user-assigned managed identity resource by following these instructions.
In the left navigation pane of your app's page, scroll down to the Settings group.
Select Identity.
Select User assigned > Add.
Locate the identity that you created earlier, select it, and then select Add.
Important
After you select Add, the app restarts.
Create a user-assigned identity:
az identity create --resource-group <groupName> --name <identityName>
Assign the identity to your app:
az webapp identity assign --resource-group <groupName> --name <appName> --identities <identityId>
Add an Azure role to your managed identity
- In the Azure Portal, navigate to the scope that you want to grant vector database access to. The scope can be a Management group, Subscription, Resource group, or a specific Azure resource.
- In the left navigation pane, select Access control (IAM).
- Select Add, then select Add role assignment.
- On the Role tab, select the appropriate role that grants read access to your vector database.
- On the Members tab, select the managed identity.
- On the Review + assign tab, select Review + assign to assign the role.
Resource scope
az role assignment create --assignee "<managedIdentityObjectID>" \
--role "<myVectorDbReaderRole>" \
--scope "/subscriptions/<subscriptionId>/resourcegroups/<resourceGroupName>/providers/<providerName>/<resourceType>/<resourceSubType>/<resourceName>"
Resource group scope
az role assignment create --assignee "<managedIdentityObjectID>" \
--role "<myVectorDbReaderRole>" \
--scope "/subscriptions/<subscriptionId>/resourcegroups/<resourceGroupName>"
Subscription scope
az role assignment create --assignee "<managedIdentityObjectID>" \
--role "<myVectorDbReaderRole>" \
--scope "/subscriptions/<subscriptionId>"
Management group scope
az role assignment create --assignee "<managedIdentityObjectID>" \
--role "<myVectorDbReaderRole>" \
--scope "/providers/Microsoft.Management/managementGroups/<managementGroupName>"
Implement token-based authentication with the vector database
The following code samples require these additional libraries:
Initialize a
DefaultAzureCredential
object to pick up your app's managed identity:// 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". } );
Initialize an
IMemoryStore
object for your vector database, then use it to build anISemanticTextMemory
:// 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();
Build a
Kernel
object, then import theISemanticTextMemory
object using theTextMemoryPlugin
:// 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));
Use the
Kernel
object to invoke a prompt that includes memory recall:// 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}");
Use Key Vault to store connection secrets
If a vector database doesn't support Microsoft Entra authentication, you can use a Key Vault to store your connection secrets and retrieve them with your App Service application. By using a Key Vault to store your connection secrets you can share them with multiple applications, and control access to individual secrets per application.
Before following these steps, retrieve a connection string for your vector database. For example, see Use Azure Cache for Redis with an ASP.NET Core web app.
Add a connection string to Key Vault
Important
Before following these steps, ensure you have created a Key Vault using the Azure Portal.
- Navigate to your key vault in the Azure Portal.
- In the Key Vault left navigation, select Objects then select Secrets.
- Select + Generate/Import.
- On the Create a secret screen choose the following values:
- Upload options:
Manual
. - Name: Type a name for the secret. The secret name must be unique within a Key Vault.
- Value: The connection string for your vector database.
- Leave the other values to their defaults. Select Create.
- Upload options:
- When you receive the message that the secret has been successfully created, it's ready to use in your application.
Important
Before following these steps, ensure you have created a Key Vault using the Azure CLI.
Grant your user account permissions to your key vault through Role-Based Access Control (RBAC), assign a role using the Azure CLI command
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>"
Add the connection string to Key Vault using the Azure CLI command
az keyvault secret set
:az keyvault secret set \ --vault-name "<keyVaultName>" \ --name "<secretName>" \ --value "<connectionString>"
Grant your App Service access to Key Vault
- Assign a managed identity to your App Service.
- Add the
Key Vault Secrets User
andKey Vault Reader
roles to your managed identity.
Implement connection string retrieval from Key Vault
To use the following code samples, you need these additional libraries:
Azure.Identity
NuGet packageAzure.Extensions.AspNetCore.Configuration.Secrets
NuGet packageMicrosoft.Extensions.Configuration
NuGet package
These code samples use a Redis database, but you can apply them to any vector database that supports connection strings.
Initialize a
DefaultAzureCredential
object to pick up your app's managed identity:// 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". } );
Add Key Vault when building your configuration, this will map your Key Vault secrets to the
IConfigurationRoot
object:// 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"]!;
Use your vector database connection string from Key Vault to initialize an
IMemoryStore
object, and then use it to build anISemanticTextMemory
:// 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();
Build a
Kernel
object, then import theISemanticTextMemory
object using theTextMemoryPlugin
:// 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));
Use the
Kernel
object to invoke a prompt that includes memory recall:// 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}");
Use application settings to store connection secrets
If a vector database doesn't support Microsoft Entra authentication, you can use the App Service application settings to store your connection secrets. By using application settings you can store your connection secrets without provisioning any additional Azure resources.
Before following these steps, retrieve a connection string for your vector database. For example, see Use Azure Cache for Redis in .NET Framework.
Add a connection string to application settings
- Navigate to your app's page on the Azure Portal.
- In the app's left menu, select Configuration > Application settings.
- By default, values for application settings are hidden in the portal for security.
- To see a hidden value of an application setting, select its Value field.
- Select New connection setting.
- On the Add/Edit connection string screen choose the following values:
- Name: Type a name for the setting. The setting name must be unique.
- Value: The connection string for your vector database.
- Type: The type of connection,
Custom
if no others apply. - Leave the other values to their defaults. Select OK.
- Select Save back in the Configuration page.
Add or edit an app setting with the Azure CLI command az webapp config connection-string set
:
az webapp config connection-string set \
--name "<appName>" \
--resource-group "<groupName>" \
--connection-string-type "<connectionType>" \
--settings <connectionName>='<connectionString>'
Implement connection string retrieval from app settings
To use the following code samples, you need these additional libraries:
Microsoft.Extensions.Configuration
NuGet packageMicrosoft.Extensions.Configuration.EnvironmentVariables
NuGet package
These code samples use a Redis database, but you can apply them to any vector database that supports connection strings.
Add environment variables when building your configuration, this will map your connection strings to the
IConfigurationRoot
object:// 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")!;
Use your vector database connection string from app settings to initialize an
IMemoryStore
object, and then use it to build anISemanticTextMemory
:// 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();
Build a
Kernel
object, then import theISemanticTextMemory
object using theTextMemoryPlugin
:// 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));
Use the
Kernel
object to invoke a prompt that includes memory recall:// 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}");
Related content
- [Use Redis for memory storage with the Semantic Kernel SDK]
- How to use managed identities for App Service and Azure Functions
- Steps to assign an Azure role