Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4a83ec0
Add Cosmos DB post-configuration script and update requirements - Ini…
SteveCInVA Nov 24, 2025
a2c90ed
post deploy configure services in cosmosdb
SteveCInVA Nov 24, 2025
c89c377
refactor to prevent post deploy configuration + begin support of key …
SteveCInVA Nov 25, 2025
a151329
Add additional parameter validation for creating entra app
SteveCInVA Nov 25, 2025
1c9454a
Refactor Bicep modules for improved authentication and key management
SteveCInVA Nov 29, 2025
c9dcc0b
Merge pull request #535 from microsoft/Development
SteveCInVA Dec 1, 2025
eaf846b
Refactor Bicep modules to conditionally add settings based on authent…
SteveCInVA Dec 1, 2025
cd969db
initial support for VideoIndexer service
SteveCInVA Dec 1, 2025
a439717
Merge branch 'dev-sc-postdeployconfig' of https://github.com/microsof…
SteveCInVA Dec 1, 2025
6fc2a91
Refactor Bicep modules to enhance VideoIndexer service integration an…
SteveCInVA Dec 1, 2025
7dd32ae
move from using chainguard-dev builder image to python slim image.
SteveCInVA Dec 1, 2025
383138b
Updates to support post deployment app config
SteveCInVA Dec 2, 2025
d1b1ea1
Add post-deployment permissions script for CosmosDB and update authen…
SteveCInVA Dec 2, 2025
9e18eca
fix typo in enhanced citation deployment config
SteveCInVA Dec 2, 2025
3fa9cf9
Refactor Dockerfile to use Python 3.13-slim and streamline build process
SteveCInVA Dec 2, 2025
1fa9d59
restart web application after deployment settings applied
SteveCInVA Dec 10, 2025
f2039a8
remove setting for disableLocalAuth
SteveCInVA Dec 10, 2025
5e08e2c
update to latest version of bicep deployment
SteveCInVA Dec 11, 2025
c67822d
remove dead code
SteveCInVA Dec 11, 2025
b23aafe
code cleanup / formatting
SteveCInVA Dec 11, 2025
4b71a12
removed unnecessary content from readme.md
SteveCInVA Dec 11, 2025
3c50fa0
fix token scope for commericial search service
SteveCInVA Dec 15, 2025
a54c2b5
set permission correctly for lookup of openAI models
SteveCInVA Dec 15, 2025
bab4f22
fixes required to configure search with managed identity
SteveCInVA Dec 15, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Updates to support post deployment app config
  • Loading branch information
SteveCInVA committed Dec 2, 2025
commit 383138b049a7027b38959e9706a40dd7102e05bb
10 changes: 8 additions & 2 deletions deployers/azure.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -15,16 +15,22 @@ hooks:
export var_cosmosDb_uri=${var_cosmosDb_uri}
export var_subscriptionId=${AZURE_SUBSCRIPTION_ID}
export var_rgName=${var_rgName}
#export var_enableEnterpriseApp=${var_enableEnterpriseApp}
export var_keyVaultUri=${var_keyVaultUri}

export var_authenticationType=${var_authenticationType}

export var_openAIEndpoint=${var_openAIEndpoint}
export var_openAIResourceGroup=${var_openAIResourceGroup}
export var_openAIGPTModel=${var_openAIGPTModel}
export var_openAITextEmbeddingModel=${var_openAITextEmbeddingModel}
export var_blobStorageEndpoint=${var_blobStorageEndpoint}
export var_contentSafetyName=${var_contentSafetyName}
export var_contentSafetyEndpoint=${var_contentSafetyEndpoint}
export var_searchServiceEndpoint=${var_searchServiceEndpoint}
export var_documentIntelligenceServiceEndpoint=${var_documentIntelligenceServiceEndpoint}
export var_videoIndexerName=${var_videoIndexerName}
export var_deploymentLocation=${var_deploymentLocation}
export var_videoIndexerAccountId=${var_videoIndexerAccountId}
export var_speechServiceEndpoint=${var_speechServiceEndpoint}

# Execute post-configuration script if enabled
if [ "${var_configureApplication}" = "true" ]; then
Expand Down
21 changes: 17 additions & 4 deletions deployers/bicep/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -515,14 +515,27 @@ output var_containerRegistry string = containerRegistry
output var_acrName string = toLower('${appName}${environment}acr')

// output values required for postprovision script in azure.yaml
//output var_configureApplication bool = configureApplicationPermissions
output var_configureApplication bool = configureApplicationPermissions
output var_keyVaultUri string = keyVault.outputs.keyVaultUri
output var_cosmosDb_uri string = cosmosDB.outputs.cosmosDbUri
output var_subscriptionId string = subscription().subscriptionId

output var_authenticationType string = toLower(authenticationType)

output var_openAIEndpoint string = openAI.outputs.openAIEndpoint
output var_openAIResourceGroup string = openAI.outputs.openAIResourceGroup //may be able to remove
output var_openAIGPTModel string = gptModels[0].modelName
output var_openAITextEmbeddingModel string = embeddingModels[0].modelName
output var_openAIGPTModels array = gptModels
output var_openAIEmbeddingModels array = embeddingModels
output var_blobStorageEndpoint string = storageAccount.outputs.endpoint
#disable-next-line BCP318 // expect one value to be null
output var_contentSafetyName string = deployContentSafety ? contentSafety.outputs.contentSafetyName : ''
output var_contentSafetyEndpoint string = deployContentSafety ? contentSafety.outputs.contentSafetyEndpoint : ''

output var_deploymentLocation string = rg.location
output var_searchServiceEndpoint string = searchService.outputs.searchServiceEndpoint
output var_documentIntelligenceServiceEndpoint string = docIntel.outputs.documentIntelligenceServiceEndpoint
#disable-next-line BCP318 // expect one value to be null
output var_videoIndexerName string = deployVideoIndexerService ? videoIndexerService.outputs.videoIndexerServiceName : ''
#disable-next-line BCP318 // expect one value to be null
output var_videoIndexerAccountId string = deployVideoIndexerService ? videoIndexerService.outputs.videoIndexerAccountId : ''
#disable-next-line BCP318 // expect one value to be null
output var_speechServiceEndpoint string = deploySpeechService ? speechService.outputs.speechServiceEndpoint : ''
2 changes: 1 addition & 1 deletion deployers/bicep/modules/appService.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ resource webApp 'Microsoft.Web/sites@2022-03-01' = {
{name: 'AZURE_ENDPOINT', value: azurePlatform == 'AzureUSGovernment' ? 'usgovernment' : 'public'}
{name: 'SCM_DO_BUILD_DURING_DEPLOYMENT', value: 'false'}
{name: 'AZURE_COSMOS_ENDPOINT', value: cosmosDb.properties.documentEndpoint}
{name: 'AZURE_COSMOS_AUTHENTICATION_TYPE', value: authenticationType}
{name: 'AZURE_COSMOS_AUTHENTICATION_TYPE', value: toLower(authenticationType)}

// Only add this setting if authenticationType is 'Key'
...(authenticationType == 'Key' ? [{name: 'AZURE_COSMOS_KEY', value: '@Microsoft.KeyVault(SecretUri=${keyVaultUri}secrets/cosmos-db-key)'}] : [])
Expand Down
3 changes: 2 additions & 1 deletion deployers/bicep/modules/search.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ resource searchDiagnostics 'Microsoft.Insights/diagnosticSettings@2021-05-01-pre
//=========================================================
// store search Service keys in key vault if using key authentication and configure app permissions = true
//=========================================================
module searchServiceSecret 'keyVault-Secrets.bicep' = if (authenticationType == 'Key' && configureApplicationPermissions) {
module searchServiceSecret 'keyVault-Secrets.bicep' = if (configureApplicationPermissions) {
name: 'storeSearchServiceSecret'
params: {
keyVaultName: keyVault
Expand All @@ -61,3 +61,4 @@ module searchServiceSecret 'keyVault-Secrets.bicep' = if (authenticationType ==

output searchServiceName string = searchService.name
output searchServiceEndpoint string = searchService.properties.endpoint
output searchServiceAuthencationType string = authenticationType
3 changes: 2 additions & 1 deletion deployers/bicep/modules/speechService.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ resource speechServiceDiagnostics 'Microsoft.Insights/diagnosticSettings@2021-05
//=========================================================
// store speech Service keys in key vault if using key authentication and configure app permissions = true
//=========================================================
module speechServiceSecret 'keyVault-Secrets.bicep' = if (authenticationType == 'Key' && configureApplicationPermissions) {
module speechServiceSecret 'keyVault-Secrets.bicep' = if (configureApplicationPermissions) {
name: 'storeSpeechServiceSecret'
params: {
keyVaultName: keyVault
Expand All @@ -63,3 +63,4 @@ module speechServiceSecret 'keyVault-Secrets.bicep' = if (authenticationType ==

output speechServiceName string = speechService.name
output speechServiceEndpoint string = speechService.properties.endpoint
output speechServiceAuthenticationType string = authenticationType
1 change: 1 addition & 0 deletions deployers/bicep/modules/videoIndexer.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,4 @@ resource videoIndexerServiceDiagnostics 'Microsoft.Insights/diagnosticSettings@2
}

output videoIndexerServiceName string = videoIndexerService.name
output videoIndexerAccountId string = videoIndexerService.properties.accountId
127 changes: 100 additions & 27 deletions deployers/bicep/postconfig.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from azure.cosmos import CosmosClient
from azure.cosmos.exceptions import CosmosResourceNotFoundError
from azure.identity import DefaultAzureCredential
from azure.keyvault.secrets import SecretClient
import os
import json

credential = DefaultAzureCredential()
token = credential.get_token("https://cosmos.azure.com/.default")
Expand Down Expand Up @@ -29,90 +31,161 @@
}

# Get values from environment variables
var_authenticationType = os.getenv("var_authenticationType") # expected to be true or false... will determine if key based or managed identity is used
var_authenticationType = os.getenv("var_authenticationType")
var_keyVaultUri = os.getenv("var_keyVaultUri")

var_openAIEndpoint=os.getenv("var_openAIEndpoint")
var_openAIResourceGroup=os.getenv("var_openAIResourceGroup")
var_subscriptionId = os.getenv("var_subscriptionId")
var_rgName = os.getenv("var_rgName")
var_openAIGPTModel = os.getenv("var_openAIGPTModel")
var_openAITextEmbeddingModel = os.getenv("var_openAITextEmbeddingModel")
var_openAIGPTModels = os.getenv("var_openAIGPTModels")
gpt_models_list = json.loads(var_openAIGPTModels)
var_openAIEmbeddingModels = os.getenv("var_openAIEmbeddingModels")
embedding_models_list = json.loads(var_openAIEmbeddingModels)
var_blobStorageEndpoint = os.getenv("var_blobStorageEndpoint")
var_contentSafetyEndpoint = os.getenv("var_contentSafetyEndpoint")
var_searchServiceEndpoint = os.getenv("var_searchServiceEndpoint")
var_documentIntelligenceServiceEndpoint = os.getenv("var_documentIntelligenceServiceEndpoint")
var_videoIndexerName = os.getenv("var_videoIndexerName")
var_videoIndexerLocation = os.getenv("var_deploymentLocation")
var_videoIndexerAccountId = os.getenv("var_videoIndexerAccountId")
var_speechServiceEndpoint = os.getenv("var_speechServiceEndpoint")
var_speechServiceLocation = os.getenv("var_deploymentLocation")

# Initialize Key Vault client if Key Vault URI is provided
if var_keyVaultUri:
keyvault_client = SecretClient(vault_url=var_keyVaultUri, credential=credential)
else:
keyvault_client = None

# 4. Update the Configurations

# 4. Update the property
# General > Health Check
item["enable_external_healthcheck"] = True

# AI Models
item["azure_openai_gpt_endpoint"] = var_openAIEndpoint

if var_contentSafetyEndpoint and var_contentSafetyEndpoint.strip():
item["azure_openai_gpt_authentication_type"] = "managed_identity"
else:
item["azure_openai_gpt_authentication_type"] = "key"
item["azure_openai_gpt_authentication_type"] = var_authenticationType
item["azure_openai_gpt_subscription_id"] = var_subscriptionId
item["azure_openai_gpt_resource_group"] = var_openAIResourceGroup
item["gpt_model"] = {
"selected": [
{
"deploymentName": var_openAIGPTModel,
"modelName": var_openAIGPTModel
"deploymentName": gpt_models_list[0]["modelName"],
"modelName": gpt_models_list[0]["modelName"]
}
],
"all": [
{
"deploymentName": var_openAIGPTModel,
"modelName": var_openAIGPTModel
"deploymentName": model["modelName"],
"modelName": model["modelName"]
}
for model in gpt_models_list
]
}

item["azure_openai_embedding_endpoint"] = var_openAIEndpoint
item["azure_openai_embedding_authentication_type"] = "managed_identity"
item["azure_openai_embedding_authentication_type"] = var_authenticationType
item["azure_openai_embedding_subscription_id"] = var_subscriptionId
item["azure_openai_embedding_resource_group"] = var_openAIResourceGroup
item["embedding_model"] = {
"selected": [
{
"deploymentName": var_openAITextEmbeddingModel,
"modelName": var_openAITextEmbeddingModel
"deploymentName": embedding_models_list[0]["modelName"],
"modelName": embedding_models_list[0]["modelName"]
}
],
"all": [
{
"deploymentName": var_openAITextEmbeddingModel,
"modelName": var_openAITextEmbeddingModel
"deploymentName": model["modelName"],
"modelName": model["modelName"]
}
for model in embedding_models_list
]
}

# Agents and Actions > Agents Configuration
item["enable_semantic_kernel"] = True

# Logging > Application Insights Logging
item["enable_appinsights_global_logging"] = True

# Scale > Redis Cache
# todo support redis cache configuration

# Workspaces > Metadata Extraction
item["enable_extract_meta_data"] = True
item["metadata_extraction_model"] = var_openAIGPTModel
item["metadata_extraction_model"] = gpt_models_list[0]["modelName"]

# Workspaces > Multimodal Vision Analysis
item["enable_multimodal_vision"] = True
item["multimodal_vision_model"] = var_openAIGPTModel
item["multimodal_vision_model"] = gpt_models_list[0]["modelName"]

# Citations > Enhanced Citations
item["enable_enhanced_citations"] = True
item["aoffice_docs_authentication_type"] = var_authenticationType
item["office_docs_storage_account_blob_endpoint"] = var_blobStorageEndpoint

# if contentSafetyEndpoint is not blank then set enable_content_safety to true
# Safety > Content Safety
if var_contentSafetyEndpoint and var_contentSafetyEndpoint.strip():
item["enable_content_safety"] = True
item["content_safety_endpoint"] = var_contentSafetyEndpoint
item["content_safety_authentication_type"] = "managed_identity"

item["content_safety_endpoint"] = var_contentSafetyEndpoint
item["content_safety_authentication_type"] = var_authenticationType
if keyvault_client:
try:
contentSafety_key_secret = keyvault_client.get_secret("content-safety-key")
item["content_safety_key"] = contentSafety_key_secret.value
print("Retrieved contentSafety service key from Key Vault")
except Exception as e:
print(f"Warning: Could not retrieve content-safety-key from Key Vault: {e}")

# Safety > Conversation Archiving
item["enable_conversation_archiving"] = True

# Search and Extract > Azure AI Search
item["azure_ai_search_endpoint"] = var_searchServiceEndpoint
item["azure_ai_search_authentication_type"] = "managed_identity"

item["azure_ai_search_authentication_type"] = var_authenticationType
if keyvault_client:
try:
search_key_secret = keyvault_client.get_secret("search-service-key")
item["azure_ai_search_key"] = search_key_secret.value
print("Retrieved search service key from Key Vault")
except Exception as e:
print(f"Warning: Could not retrieve search-service-key from Key Vault: {e}")

# Search and Extract > Azure Document Intelligence
item["azure_document_intelligence_endpoint"] = var_documentIntelligenceServiceEndpoint
item["azure_document_intelligence_authentication_type"] = "managed_identity"
item["azure_document_intelligence_authentication_type"] = var_authenticationType
if keyvault_client:
try:
documentIntelligence_key_secret = keyvault_client.get_secret("document-intelligence-key")
item["azure_document_intelligence_key"] = documentIntelligence_key_secret.value
print("Retrieved document intelligence service key from Key Vault")
except Exception as e:
print(f"Warning: Could not retrieve document-intelligence-key from Key Vault: {e}")

# Search and Extract > Multimedia Support
# Video Indexer Configuration
if var_videoIndexerName and var_videoIndexerName.strip():
item["enable_video_file_support"] = True
item["video_indexer_resource_group"] = var_rgName
item["video_indexer_subscription_id"] = var_subscriptionId
item["video_indexer_account_name"] = var_videoIndexerName
item["video_indexer_location"] = var_videoIndexerLocation
item["video_indexer_account_id"] = var_videoIndexerAccountId

# Speech Service Configuration
if var_speechServiceEndpoint and var_speechServiceEndpoint.strip():
item["enable_audio_file_support"] = True
item["speech_service_endpoint"] = var_speechServiceEndpoint
item["speech_service_location"] = var_speechServiceLocation
if keyvault_client:
try:
speech_key_secret = keyvault_client.get_secret("speech-service-key")
item["speech_service_key"] = speech_key_secret.value
print("Retrieved speech service key from Key Vault")
except Exception as e:
print(f"Warning: Could not retrieve speech-service-key from Key Vault: {e}")

# 5. Upsert the updated items back into Cosmos DB
response = container.upsert_item(item)
Expand Down
3 changes: 2 additions & 1 deletion deployers/bicep/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# requirements.txt
azure-identity>=1.15.0
azure-cosmos>=4.5.0
azure-cosmos>=4.5.0
azure-keyvault-secrets>=4.4.0