Skip to content

Azure AI Search Test Connection failed for public env #611

@vivche

Description

@vivche

Issue Description

When clicking the "Test Azure AI Search Connection" button on the App Settings "Search & Extract" page with managed identity authentication enabled, the test connection failed with the following error:

Original Error Message:

NameError: name 'search_resource_manager' is not defined

Environment Configuration:

  • Authentication Type: Managed Identity
  • Azure Environment: public (set in .env file)
  • Error occurred because the code tried to reference search_resource_manager which wasn't defined for public cloud

Root Cause: The implementation used a REST API approach that required the search_resource_manager variable to construct authentication tokens. This variable wasn't defined for the public cloud environment, causing the initial error. Even if defined, the REST API approach with bearer tokens doesn't work properly with Azure AI Search's managed identity authentication.

Root Cause Analysis (with Copilot assistance)

The implementation used a REST API approach with manually acquired bearer tokens, which is fundamentally incompatible with how Azure AI Search handles managed identity authentication on the data plane.

Why the Approach Failed

Azure AI Search's data plane operations don't properly accept bearer tokens acquired through standard DefaultAzureCredential.get_token() flows and passed as HTTP Authorization headers. The authentication mechanism works differently:

# IMPLEMENTATION - FAILED 
credential = DefaultAzureCredential()
arm_scope = f"{search_resource_manager}/.default"
token = credential.get_token(arm_scope).token

headers = {
    "Authorization": f"Bearer {token}",
    "Content-Type": "application/json"
}
response = requests.get(f"{endpoint}/indexes?api-version=2024-07-01", headers=headers)
# Returns: 403 Forbidden

Problems with this approach:

  1. Azure AI Search requires SDK-specific authentication handling
  2. Bearer tokens from get_token() are rejected by the Search service
  3. Token scope and refresh logic need specialized handling
  4. This issue occurs in all Azure environments (public, government, custom)

Why Other Services Work with REST API + Bearer Tokens

Some Azure services accept bearer tokens in REST API calls, but Azure AI Search requires the SDK to:

  1. Acquire tokens using the correct scope and flow
  2. Handle token refresh automatically
  3. Use Search-specific authentication headers
  4. Properly negotiate with the Search service's auth layer

The Solution

Instead of trying to define search_resource_manager for public cloud, the fix was to replace the REST API approach entirely with the SearchIndexClient SDK in route_backend_settings.py, which handles authentication correctly without needing the search_resource_manager variable.

Code Changes Summary

Before (REST API approach):

def _test_azure_ai_search_connection(payload):
    # ... setup code ...
    
    if direct_data.get('auth_type') == 'managed_identity':
        credential = DefaultAzureCredential()
        arm_scope = f"{search_resource_manager}/.default"
        token = credential.get_token(arm_scope).token
        
        headers = {
            "Authorization": f"Bearer {token}",
            "Content-Type": "application/json"
        }
        response = requests.get(f"{endpoint}/indexes?api-version=2024-07-01", headers=headers)
        # ❌ Returns 403 Forbidden

After (SDK approach):
Tested with this modification and it works for public env.

def _test_azure_ai_search_connection(payload):
    # ... setup code ...
    
    if direct_data.get('auth_type') == 'managed_identity':
        credential = DefaultAzureCredential()
        
        # Use SDK which handles authentication properly
        if AZURE_ENVIRONMENT in ("usgovernment", "custom"):
            client = SearchIndexClient(
                endpoint=endpoint,
                credential=credential,
                audience=search_resource_manager
            )
        else:
            # For public cloud, don't use audience parameter
            client = SearchIndexClient(
                endpoint=endpoint,
                credential=credential
            )
    
    # Test by listing indexes (simple operation to verify connectivity)
    indexes = list(client.list_indexes())
    # ✅ Works correctly

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions