Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 5 additions & 2 deletions application/single_app/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,11 @@ def get_allowed_extensions(enable_video=False, enable_audio=False):
WORD_CHUNK_SIZE = 400

if AZURE_ENVIRONMENT == "custom" or CUSTOM_IDENTITY_URL_VALUE or CUSTOM_GRAPH_AUTHORITY_URL_VALUE:
AUTHORITY = f"{CUSTOM_IDENTITY_URL_VALUE}/{TENANT_ID}"
authority = CUSTOM_GRAPH_AUTHORITY_URL_VALUE or CUSTOM_IDENTITY_URL_VALUE or AUTHORITY.rstrip(f'/{TENANT_ID}')
AUTHORITY = f"{CUSTOM_IDENTITY_URL_VALUE.rstrip('/')}/{TENANT_ID}"
base_authority = CUSTOM_GRAPH_AUTHORITY_URL_VALUE or CUSTOM_IDENTITY_URL_VALUE
if not base_authority:
base_authority = AUTHORITY.rstrip('/').removesuffix(f"/{TENANT_ID}")
authority = base_authority
elif AZURE_ENVIRONMENT == "usgovernment":
AUTHORITY = f"https://login.microsoftonline.us/{TENANT_ID}"
authority = AzureAuthorityHosts.AZURE_GOVERNMENT
Expand Down
39 changes: 33 additions & 6 deletions deployers/bicep/main.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@ targetScope = 'subscription'
param location string

@description('''The target Azure Cloud environment.
- Accepted values are: AzureCloud, AzureUSGovernment
- Default is AzureCloud''')
- Accepted values are: AzureCloud, AzureUSGovernment, public, usgovernment, custom
- Default is based on the ARM cloud name''')
@allowed([
'AzureCloud'
'AzureUSGovernment'
'AzureCloud' // public, keep allowed values for backwards compatibility
'AzureUSGovernment' // usgovernment
'public'
'usgovernment'
'custom'
])
param cloudEnvironment string
param cloudEnvironment string = az.environment().name == 'AzureCloud' ? 'public' : (az.environment().name == 'AzureUSGovernment' ? 'usgovernment' : 'custom')
// SimpleChat expects public, usgovernment or custom
var scCloudEnvironment = cloudEnvironment == 'AzureCloud' ? 'public' : (cloudEnvironment == 'AzureUSGovernment' ? 'usgovernment' : cloudEnvironment)

@description('''The name of the application to be deployed.
- Name may only contain letters and numbers
Expand Down Expand Up @@ -80,6 +85,20 @@ param enableDiagLogging bool
- Default is false''')
param enablePrivateNetworking bool

// --- Custom Azure Environment Parameters (for 'custom' azureEnvironment) ---
@description('Custom blob storage URL suffix, e.g. blob.core.usgovcloudapi.net')
param customBlobStorageSuffix string = 'blob.${az.environment().suffixes.storage}'
@description('Custom Graph API URL, e.g. https://graph.microsoft.us')
param customGraphUrl string? // az.environment().graph is legacy AD, do not use
@description('Custom Identity URL, e.g. https://login.microsoftonline.us/')
param customIdentityUrl string = az.environment().authentication.loginEndpoint
@description('Custom Resource Manager URL, e.g. https://management.usgovcloudapi.net')
param customResourceManagerUrl string = az.environment().resourceManager
@description('Custom Cognitive Services scope ex: https://cognitiveservices.azure.com/.default')
param customCognitiveServicesScope string = 'https://cognitiveservices.azure.com/.default'
@description('Custom search resource URL for token audience, e.g. https://search.azure.us')
param customSearchResourceUrl string = 'https://search.azure.com'

@description('''Array of GPT model names to deploy to the OpenAI resource.''')
param gptModels array = [
{
Expand Down Expand Up @@ -424,7 +443,7 @@ module appService 'modules/appService.bicep' = {
logAnalyticsId: logAnalytics.outputs.logAnalyticsId
appServicePlanId: appServicePlan.outputs.appServicePlanId
containerImageName: containerImageName
azurePlatform: cloudEnvironment
azurePlatform: scCloudEnvironment
cosmosDbName: cosmosDB.outputs.cosmosDbName
searchServiceName: searchService.outputs.searchServiceName
openAiServiceName: openAI.outputs.openAIName
Expand All @@ -439,6 +458,14 @@ module appService 'modules/appService.bicep' = {
enablePrivateNetworking: enablePrivateNetworking
#disable-next-line BCP318 // expect one value to be null if private networking is disabled
appServiceSubnetId: enablePrivateNetworking? virtualNetwork.outputs.appServiceSubnetId : ''

// --- Custom Azure Environment Parameters (for 'custom' azureEnvironment) ---
customBlobStorageSuffix: customBlobStorageSuffix
customGraphUrl: customGraphUrl
customIdentityUrl: customIdentityUrl
customResourceManagerUrl: customResourceManagerUrl
customCognitiveServicesScope: customCognitiveServicesScope
customSearchResourceUrl: customSearchResourceUrl
}
}

Expand Down
37 changes: 32 additions & 5 deletions deployers/bicep/modules/appService.bicep
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,23 @@ param keyVaultUri string
param enablePrivateNetworking bool
param appServiceSubnetId string = ''

// --- Custom Azure Environment Parameters (for 'custom' azureEnvironment) ---
@description('Custom blob storage URL suffix, e.g. blob.core.usgovcloudapi.net')
param customBlobStorageSuffix string?
@description('Custom Graph API URL, e.g. https://graph.microsoft.us')
param customGraphUrl string?
@description('Custom Identity URL, e.g. https://login.microsoftonline.us')
param customIdentityUrl string?
@description('Custom Resource Manager URL, e.g. https://management.usgovcloudapi.net')
param customResourceManagerUrl string?
@description('Custom Cognitive Services scope ex: https://cognitiveservices.azure.com/.default')
param customCognitiveServicesScope string?
@description('Custom search resource URL for token audience, e.g. https://search.azure.us')
param customSearchResourceUrl string?

var tenantId = tenant().tenantId
var openIdMetadataUrl = '${az.environment().authentication.loginEndpoint}${tenantId}/v2.0/.well-known/openid-configuration'

// Import diagnostic settings configurations
module diagnosticConfigs 'diagnosticSettings.bicep' = if (enableDiagLogging) {
name: 'diagnosticConfigs'
Expand Down Expand Up @@ -55,7 +72,7 @@ resource appInsights 'Microsoft.Insights/components@2020-02-02' existing = {
name: appInsightsName
}

var acrDomain = azurePlatform == 'AzureUSGovernment' ? '.azurecr.us' : '.azurecr.io'
var acrDomain = az.environment().suffixes.acrLoginServer

// add web app
resource webApp 'Microsoft.Web/sites@2022-03-01' = {
Expand All @@ -77,7 +94,7 @@ resource webApp 'Microsoft.Web/sites@2022-03-01' = {
ftpsState: 'Disabled'
healthCheckPath: '/external/healthcheck'
appSettings: [
{ name: 'AZURE_ENDPOINT', value: azurePlatform == 'AzureUSGovernment' ? 'usgovernment' : 'public' }
{ name: 'AZURE_ENVIRONMENT', value: azurePlatform }
{ name: 'SCM_DO_BUILD_DURING_DEPLOYMENT', value: 'false' }
{ name: 'AZURE_COSMOS_ENDPOINT', value: cosmosDb.properties.documentEndpoint }
{ name: 'AZURE_COSMOS_AUTHENTICATION_TYPE', value: toLower(authenticationType) }
Expand Down Expand Up @@ -150,8 +167,18 @@ resource webApp 'Microsoft.Web/sites@2022-03-01' = {
{ name: 'InstrumentationEngine_EXTENSION_VERSION', value: 'disabled' }
{ name: 'SnapshotDebugger_EXTENSION_VERSION', value: 'disabled' }
{ name: 'XDT_MicrosoftApplicationInsights_BaseExtensions', value: 'disabled' }
{ name: 'XDT_MicrosoftApplicationInsights_Mode', value: 'recommended' }
{ name: 'XDT_MicrosoftApplicationInsights_PreemptSdk', value: 'disabled' }
{name: 'XDT_MicrosoftApplicationInsights_Mode', value: 'recommended' }
{name: 'XDT_MicrosoftApplicationInsights_PreemptSdk', value: 'disabled' }
...(azurePlatform == 'custom' ? [
{name: 'CUSTOM_GRAPH_URL_VALUE', value: customGraphUrl ?? ''}
{name: 'CUSTOM_IDENTITY_URL_VALUE', value: customIdentityUrl ?? ''}
{name: 'CUSTOM_RESOURCE_MANAGER_URL_VALUE', value: customResourceManagerUrl ?? ''}
{name: 'CUSTOM_BLOB_STORAGE_URL_VALUE', value: customBlobStorageSuffix ?? ''}
{name: 'CUSTOM_COGNITIVE_SERVICES_URL_VALUE', value: customCognitiveServicesScope ?? ''}
{name: 'CUSTOM_SEARCH_RESOURCE_MANAGER_URL_VALUE', value: customSearchResourceUrl ?? ''}
{name: 'KEY_VAULT_DOMAIN', value: az.environment().suffixes.keyvaultDns}
{name: 'CUSTOM_OIDC_METADATA_URL_VALUE', value: openIdMetadataUrl ?? ''}]
: [])
]
}
clientAffinityEnabled: false
Expand Down Expand Up @@ -205,7 +232,7 @@ resource authSettings 'Microsoft.Web/sites/config@2022-03-01' = {
azureActiveDirectory: {
enabled: true
registration: {
openIdIssuer: azurePlatform == 'AzureUSGovernment' ? 'https://login.microsoftonline.us/${tenant().tenantId}/' : 'https://sts.windows.net/${tenant().tenantId}/'
openIdIssuer: '${az.environment().authentication.loginEndpoint}${tenant().tenantId}/'
clientId: enterpriseAppClientId
clientSecretSettingName: 'MICROSOFT_PROVIDER_AUTHENTICATION_SECRET'
}
Expand Down
9 changes: 9 additions & 0 deletions docs/explanation/release_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@

#### New Features

* **Custom Azure Environment Support in Bicep Deployment**
* Added `custom` as a supported `cloudEnvironment` value alongside `public` and `usgovernment`, enabling deployment to sovereign or custom Azure environments via Bicep.
* New Bicep parameters for custom environments: `customBlobStorageSuffix`, `customGraphUrl`, `customIdentityUrl`, `customResourceManagerUrl`, `customCognitiveServicesScope`, and `customSearchResourceUrl`. All of these are automatically populated from `az.environment()` defaults except `customGraphUrl`, which must be explicitly provided for custom cloud environments and can be overridden as needed.
* The `cloudEnvironment` parameter now defaults intelligently based on `az.environment().name`, and legacy values (`AzureCloud`, `AzureUSGovernment`) are mapped to SimpleChat's expected values (`public`, `usgovernment`).
* Custom environment app settings (`CUSTOM_GRAPH_URL_VALUE`, `CUSTOM_IDENTITY_URL_VALUE`, `CUSTOM_RESOURCE_MANAGER_URL_VALUE`, etc.) are conditionally injected only when `azurePlatform == 'custom'`.
* Replaced hardcoded ACR domain logic and auth issuer URLs with dynamic `az.environment()` lookups for better cross-cloud compatibility.
* Fixed trailing slash handling in `AUTHORITY` URL construction in `config.py` using `rstrip('/')`.
* (Ref: `deployers/bicep/main.bicep`, `deployers/bicep/modules/appService.bicep`, `config.py`, sovereign cloud support)

* **Redis Key Vault Authentication**
* Added a new `key_vault` authentication type for Redis, allowing the Redis access key to be retrieved securely from Azure Key Vault at runtime rather than stored directly in settings.
* Applies across all Redis usage paths: app settings cache (`app_settings_cache.py`), session management (`app.py`), and the Redis test connection flow (`route_backend_settings.py`).
Expand Down
Loading