Use Azure AI Search without keys

In your application code, you can set up a keyless connection to Azure AI Search that uses Microsoft Entra ID and roles for authentication and authorization. Application requests to most Azure services must be authenticated with keys or keyless connections. Developers must be diligent to never expose the keys in an unsecure location. Anyone who gains access to the key is able to authenticate to the service. Keyless authentication offers improved management and security benefits over the account key because there's no key (or connection string) to store.

Keyless connections are enabled with the following steps:

  • Configure your authentication.
  • Set environment variables, as needed.
  • Use an Azure Identity library credential type to create an Azure AI Search client object.

Prerequisites

The following steps need to be completed for both local development and production workloads:

Create an AI Search resource

Before continuing with this article, you need an Azure AI Search resource to work with. If you don't have a resource, create your resource now. Enable role-based access control (RBAC) for the resource.

Install Azure Identity client library

Before working locally without keyless, update your AI Search enabled code with the Azure Identity client library.

Install the Azure Identity client library for .NET:

dotnet add package Azure.Identity

Update source code to use DefaultAzureCredential

The Azure Identity library's DefaultAzureCredential allows you to run the same code in the local development environment and in the Azure cloud. Create a single credential and reuse the credential instance as needed to take advantage of token caching.

For more information on DefaultAzureCredential for .NET, see Azure Identity client library for .NET.

using Azure;
using Azure.Search.Documents;
using Azure.Search.Documents.Indexes;
using Azure.Search.Documents.Indexes.Models;
using Azure.Search.Documents.Models;
using Azure.Identity;
using System;
using static System.Environment;

string endpoint = GetEnvironmentVariable("AZURE_SEARCH_ENDPOINT");
string indexName = "my-search-index";

DefaultAzureCredential credential = new();
SearchClient searchClient = new(new Uri(endpoint), indexName, credential);
SearchIndexClient searchIndexClient = new(endpoint, credential);

Local development

Local development without keyless includes these steps:

  • Assign your personal identity with RBAC roles on the specific resource.
  • Use a tool to authenticate with Azure.
  • Establish environment variables for your resource.

Roles for local development

As a local developer, your Azure identity needs full control of your service. This control is provided with RBAC roles. To manage your resource during development, these are the suggested roles:

  • Search Service Contributor
  • Search Index Data Contributor
  • Search Index Data Reader

Find your personal identity with one of the following tools. Use that identity as the <identity-id> value.

  1. Sign in to Azure CLI.

    az cloud set -n AzureChinaCloud
    az login
    # az cloud set -n AzureCloud   //means return to Public Azure.
    
  2. Get your personal identity.

    az ad signed-in-user show \
        --query id -o tsv
    
  3. Assign the role-based access control (RBAC) role to the identity for the resource group.

    az role assignment create \
        --role "<role-name>" \
        --assignee "<identity-id>" \
        --scope "/subscriptions/<subscription-id>/resourceGroups/<resource-group-name>"
    

Where applicable, replace <identity-id>, <subscription-id>, and <resource-group-name> with your actual values.

Authentication for local development

Use a tool in your local development environment to authentication to Azure identity. Once you're authenticated, the DefaultAzureCredential instance in your source code finds and uses the authentication.

Configure environment variables for local development

To connect to Azure AI Search, your code needs to know your resource endpoint.

Create an environment variable named AZURE_SEARCH_ENDPOINT for your Azure AI Search endpoint. This URL generally has the format https://<YOUR-RESOURCE-NAME>.search.azure.cn/.

Production workloads

Deploy production workloads includes these steps:

  • Choose RBAC roles that adhere to the principle of least privilege.
  • Assign RBAC roles to your production identity on the specific resource.
  • Set up environment variables for your resource.

Roles for production workloads

To create your production resources, you need to create a user-assigned managed identity then assign that identity to your resources with the correct roles.

The following role is suggested for a production application:

Role name Id
Search Index Data Reader 1407120a-92aa-4202-b7e9-c0e197c71c8f

Authentication for production workloads

Use the following Azure AI Search Bicep template to create the resource and set the authentication for the identityId. Bicep requires the role ID. The name shown in this Bicep snippet isn't the Azure role; it's specific to the Bicep deployment.

// main.bicep
param environment string = 'production'
param roleGuid string = ''

module aiSearchRoleUser 'core/security/role.bicep' = {
    scope: aiSearchResourceGroup
    name: 'aiSearch-role-user'
    params: {
        principalId: (environment == 'development') ? principalId : userAssignedManagedIdentity.properties.principalId 
        principalType: (environment == 'development') ? 'User' : 'ServicePrincipal'
        roleDefinitionId: roleGuid
    }
}

The main.bicep file calls the following generic Bicep code to create any role. You have the option to create multiple RBAC roles, such as one for the user and another for production. This allows you to enable both development and production environments within the same Bicep deployment.

// core/security/role.bicep
metadata description = 'Creates a role assignment for an identity.'
param principalId string // passed in from main.bicep

@allowed([
    'Device'
    'ForeignGroup'
    'Group'
    'ServicePrincipal'
    'User'
])
param principalType string = 'ServicePrincipal'
param roleDefinitionId string // Role ID

resource role 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
    name: guid(subscription().id, resourceGroup().id, principalId, roleDefinitionId)
    properties: {
        principalId: principalId
        principalType: principalType
        roleDefinitionId: resourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId)
    }
}

Configure environment variables for production workloads

To connect to Azure AI Search, your code needs to know your resource endpoint, and the ID of the managed identity.

Create environment variables for your deployed and keyless Azure AI Search resource:

  • AZURE_SEARCH_ENDPOINT: This URL is the access point for your Azure AI Search resource. This URL generally has the format https://<YOUR-RESOURCE-NAME>.search.azure.cn/.
  • AZURE_CLIENT_ID: This is the identity to authenticate as.