Using Bicep Parameter Files for Deployment
This guide explains how to use Bicep parameter files (.bicepparam) for deploying the AI Hub Gateway Solution Accelerator.
Overview
Bicep parameter files (.bicepparam) provide a strongly-typed, native way to define deployment configurations separately from your Bicep templates, offering:
- Type safety and IntelliSense support in VS Code
- Better validation and error checking at design time
- Cleaner syntax with support for expressions and functions
- Environment variable support with
readEnvironmentVariable() - Direct integration with Azure CLI and Azure Developer CLI
- Manage different environment configurations (dev, test, prod)
- Version control your deployment settings
Available Parameter Files
The solution provides native Bicep parameter files:
1. main.bicepparam (Minimal - for Azure Developer CLI)
This file contains only essential parameters and reads values from environment variables for Azure Developer CLI (azd):
using './main.bicep'
param environmentName = readEnvironmentVariable('AZURE_ENV_NAME', 'citadel-dev')
param location = readEnvironmentVariable('AZURE_LOCATION', 'eastus')
param entraAuth = bool(readEnvironmentVariable('AZURE_ENTRA_AUTH', 'false'))
...
Use this file when:
- Deploying with
azd uporazd provision - Using Azure Developer CLI workflow
- Following the quick-start deployment path
- Want environment variable substitution
2. main.parameters.complete.bicepparam (Comprehensive Template)
This file contains all available parameters with default values and detailed comments:
Use this file as a template when:
- Creating custom environment configurations
- Deploying directly with Azure CLI or Bicep
- Customizing resource names, SKUs, or network configurations
- Need full control over all deployment settings
3. Environment-Specific Files
main.parameters.dev.bicepparam- Development environment optimized for costmain.parameters.prod.bicepparam- Production environment with HA configuration
4. resources.parameters.<env>.bicepparam (Exception - existing resource group)
Create this file only when subscription-scoped deployment is not possible and the hub resource group already exists. Copy the values from the matching main.parameters.<env>.bicepparam file, omit resourceGroupName, and point the file at resources.bicep.
Use this file as a template when:
- Deploying directly with Azure CLI or Bicep
- Targeting an existing resource group
- Avoiding subscription-scope resource group creation
Deployment Methods
Method 1: Using Azure Developer CLI (azd) - Recommended for Quick Start
The Azure Developer CLI uses main.bicepparam automatically and reads values from your .azure/<env-name>/.env file.
Steps:
-
Initialize your environment:
azd init -
Configure environment variables: Edit
.azure/<your-env-name>/.envto set your values:AZURE_ENV_NAME="citadel-dev" AZURE_LOCATION="eastus" AZURE_SUBSCRIPTION_ID="your-subscription-id" AZURE_ENTRA_AUTH="false" -
Deploy:
# Provision and deploy all services azd upor
# Only provision infrastructure azd provision
Method 2: Using Azure CLI with Bicep Parameters File
For more control, use Bicep parameter files (.bicepparam) directly with Azure CLI.
Steps:
-
Use an existing environment file or copy the complete template:
# Use existing dev or prod configuration # OR copy the complete template Copy-Item bicep/infra/main.parameters.complete.bicepparam bicep/infra/main.parameters.myenv.bicepparam -
Edit your .bicepparam file to match your requirements:
- Set
environmentNameparameter (e.g., 'citadel-dev') - Set
locationparameter (e.g., 'eastus') - Customize resource names, SKUs, networking, etc.
- Use native Bicep syntax, no JSON quotes needed
- Set
-
Deploy using Azure CLI:
# Create the deployment az deployment sub create ` --name "citadel-deployment" ` --location "eastus" ` --template-file "bicep/infra/main.bicep" ` --parameters "bicep/infra/main.parameters.dev.bicepparam"Note: Use the file path directly (no @ prefix needed for .bicepparam files)
Method 3: Using Azure CLI with Bicep Parameters File and Existing Resource Group
Create resources.parameters.<env>.bicepparam only when subscription-scoped deployment is not possible and the target resource group already exists. This deploys the same hub resources as the subscription wrapper, but skips resource group creation and uses an Azure CLI resource-group deployment.
Steps:
-
Confirm the target resource group exists in the target subscription.
-
Create a resource-scope parameter file such as
bicep/infra/resources.parameters.dev.bicepparam. Copy the values frommain.parameters.dev.bicepparam, removeresourceGroupName, and start the file withusing './resources.bicep'. -
Preview and deploy using Azure CLI:
az deployment group what-if ` --resource-group "<existing-hub-resource-group>" ` --template-file "bicep/infra/resources.bicep" ` --parameters "bicep/infra/resources.parameters.dev.bicepparam" az deployment group create ` --resource-group "<existing-hub-resource-group>" ` --template-file "bicep/infra/resources.bicep" ` --parameters "bicep/infra/resources.parameters.dev.bicepparam"
Parameter File Structure
Understanding the Complete Parameters File
The main.parameters.complete.bicepparam file is organized into sections:
1. Basic Parameters
param environmentName = 'citadel-dev'
param location = 'eastus'
param tags = {
environment: 'dev'
solution: 'ai-hub-gateway'
}
2. Resource Names
Leave empty ('') for auto-generated names or specify custom names:
param apimServiceName = '' // Auto-generated
param apimServiceName = 'my-apim-service' // Custom
3. Networking Parameters
Configure VNet, subnets, and network security:
param vnetAddressPrefix = '10.170.0.0/24'
param useExistingVnet = false
param apimNetworkType = 'External'
// AI Foundry network injection (enabled by default). When true, an additional
// agent subnet delegated to Microsoft.App/environments is provisioned (greenfield)
// or required (brownfield via agentSubnetName).
param foundryNetworkInjectionEnabled = true
param agentSubnetPrefix = '10.170.0.192/26'
Logic App Private Access
The usage-ingestion Logic App supports optional inbound private connectivity. Defaults remain unchanged: no template-created Logic App private endpoint and public network access enabled. These settings are available in both main.bicepparam and resources.bicepparam; custom environment parameter files must include any overrides explicitly.
Private Endpoint names
| Parameter | Environment Variable | Default | Description |
|---|---|---|---|
logicAppPrivateEndpointName |
LOGIC_APP_PE_NAME |
'' |
Optional endpoint resource name. Empty uses logic-pe-${resourceToken}. |
Services network access configuration
| Parameter | Environment Variable | Default | Description |
|---|---|---|---|
logicAppUsePrivateEndpoint |
LOGIC_APP_USE_PRIVATE_ENDPOINT |
false |
Create a Logic App private endpoint in the existing private-endpoint subnet. |
logicAppPublicNetworkAccess |
LOGIC_APP_PUBLIC_NETWORK_ACCESS |
true |
Allow public website and SCM/Kudu access, subject to authentication and other access controls. |
Existing Private DNS Zones
| Setting | Environment Variable | Default | Description |
|---|---|---|---|
existingPrivateDnsZones.logicApp |
EXISTING_DNS_ZONE_LOGIC_APP |
'' |
Resource ID of an existing privatelink.azurewebsites.net zone. Takes precedence over dnsZoneRG / dnsSubscriptionId. |
The two Boolean flags are independent:
logicAppUsePrivateEndpoint |
logicAppPublicNetworkAccess |
Result |
|---|---|---|
false |
true |
Default: public access enabled; no template-created endpoint. |
true |
true |
Private and public access enabled; optional staged verification when policy permits. |
true |
false |
Private-only website and SCM access; private connectivity and DNS are required for workflow publishing. |
false |
false |
Public access disabled without a template-created endpoint. Requires a working externally managed endpoint and DNS for website/SCM access. |
The templates do not reject the last combination or enforce DNS readiness. For an existing VNet, supply the Logic App zone ID or dnsZoneRG, and configure zone links or forwarding. See Logic App networking for DNS selection and subnet details.
For a private-only initial deployment, set these values in the azd environment file described above:
LOGIC_APP_USE_PRIVATE_ENDPOINT="true"
LOGIC_APP_PUBLIC_NETWORK_ACCESS="false"
For a reused DNS zone, also set EXISTING_DNS_ZONE_LOGIC_APP to its resource ID; set LOGIC_APP_PE_NAME only when overriding the generated endpoint name. A new VNet can use automatic local zone creation when neither a zone ID nor dnsZoneRG is supplied.
These settings apply to the main/resource-group initial-deployment templates, not the separate APIM gateway-upgrade supporting-services templates. Before deploying workflows with public access disabled, prepare a privately connected publishing machine or runner as described in the Full Deployment Guide.
4. Feature Flags
Enable or disable specific capabilities:
param enableAPICenter = true
param enableAIGatewayPiiRedaction = true
5. Compute SKU & Size
Define service tiers and capacity:
param apimSku = 'StandardV2'
param apimSkuUnits = 1
param cosmosDbRUs = 400
6. AI Foundry Configuration
Configure AI Foundry instances and model deployments. The first entry in aiFoundryInstances is the primary Foundry — its endpoint also powers APIM content safety and PII processing policies. Additional entries are optional and provide extra regional Foundry resources for LLM model deployments:
param aiFoundryInstances = [...]
param aiFoundryModelsConfig = [...]
Creating Environment-Specific Parameters
Development Environment
File: main.parameters.dev.bicepparam
using './main.bicep'
param environmentName = 'citadel-dev'
param location = 'eastus'
param apimSku = 'Developer'
param apimSkuUnits = 1
param cosmosDbRUs = 400
param createAppInsightsDashboards = true
param enableAPICenter = false
Production Environment
File: main.parameters.prod.bicepparam
using './main.bicep'
param environmentName = 'citadel-prod'
param location = 'eastus'
param apimSku = 'PremiumV2'
param apimSkuUnits = 2
param cosmosDbRUs = 1000
param eventHubCapacityUnits = 2
param createAppInsightsDashboards = true
param enableAPICenter = true
param entraAuth = true
param entraTenantId = 'your-tenant-id'
param entraClientId = 'your-client-id'
param entraAudience = 'your-audience'
Common Customization Scenarios
Scenario 1: Bring Your Own Network
using './main.bicep'
param useExistingVnet = true
param existingVnetRG = 'network-rg'
param vnetName = 'my-existing-vnet'
param apimSubnetName = 'snet-apim'
param privateEndpointSubnetName = 'snet-pe'
param functionAppSubnetName = 'snet-func'
// Required when foundryNetworkInjectionEnabled = true (default).
// Subnet must already be delegated to Microsoft.App/environments.
param agentSubnetName = 'snet-agents'
param foundryNetworkInjectionEnabled = true
param dnsZoneRG = 'dns-rg'
param dnsSubscriptionId = 'your-subscription-id'
Scenario 2: Custom Resource Names
using './main.bicep'
param apimServiceName = 'mycompany-apim-prod'
param cosmosDbAccountName = 'mycompany-cosmos-prod'
param eventHubNamespaceName = 'mycompany-evhns-prod'
param logAnalyticsName = 'mycompany-law-prod'
Scenario 3: AI Foundry with Custom Models
using './main.bicep'
param aiFoundryInstances = [
{
name: 'my-foundry-eastus'
location: 'eastus'
customSubDomainName: ''
defaultProjectName: 'production-project'
}
]
param aiFoundryModelsConfig = [
{
name: 'gpt-4o'
publisher: 'OpenAI'
version: '2024-11-20'
sku: 'GlobalStandard'
capacity: 100
aiserviceIndex: 0
}
]
Scenario 4: Enable Microsoft Entra ID Authentication
Auto-provisioning (recommended): Run the standalone Entra ID setup script after the first azd up, then re-deploy.
using './main.bicep'
param entraAuth = true
// Values populated by: bicep/infra/entra-id-setup/setup.ps1
param entraTenantId = ''
param entraClientId = ''
param entraAudience = ''
Bring your own app registration:
using './main.bicep'
param entraAuth = true
param entraTenantId = 'your-tenant-id'
param entraClientId = 'your-client-id'
param entraAudience = 'api://your-api-id'
When entraAuth=true:
- APIM named values
JWT-TenantId,JWT-AppRegistrationId,JWT-Issuer,JWT-OpenIdConfigUrlare configured - The
security-handlerpolicy fragment is deployed to support JWT validation across all APIs - Access contracts can enable JWT per-product via
jwtAuth.enabled: true - The client secret is stored in Key Vault as
ENTRA-APP-CLIENT-SECRET - Deploying user needs
Application.ReadWrite.Allpermission for auto-provisioning
Scenario 5: Configure AI Search Integration
using './main.bicep'
param enableAzureAISearch = true
param aiSearchInstances = [
{
name: 'ai-search-prod-01'
url: 'https://mysearch01.search.windows.net/'
description: 'Production AI Search Instance 1'
}
{
name: 'ai-search-prod-02'
url: 'https://mysearch02.search.windows.net/'
description: 'Production AI Search Instance 2'
}
]
Parameter Override Precedence
When using parameters, values are resolved in this order (highest to lowest priority):
- Command-line parameters (e.g.,
--parameters key=value) - Parameters file (e.g.,
main.parameters.dev.bicepparam) - Default values in the Bicep template
Example with Mixed Approach:
az deployment sub create `
--name "citadel-deployment" `
--location "eastus" `
--template-file "bicep/infra/main.bicep" `
--parameters "bicep/infra/main.parameters.dev.bicepparam" `
--parameters environmentName="citadel-test" apimSku="StandardV2"
In this example:
- Most values come from
main.parameters.dev.bicepparam environmentNameandapimSkuare overridden via command line
Validation and Best Practices
1. Validate Before Deployment
Use What-If to preview changes:
az deployment sub what-if `
--name "citadel-deployment" `
--location "eastus" `
--template-file "bicep/infra/main.bicep" `
--parameters "bicep/infra/main.parameters.dev.bicepparam"
2. Keep Secrets Secure
Never store sensitive values in parameter files. Use one of these approaches:
Option A: Azure Key Vault Reference
using './main.bicep'
param entraTenantId = getSecret(
'/subscriptions/{subscription-id}/resourceGroups/{rg-name}/providers/Microsoft.KeyVault/vaults/{vault-name}',
'entraTenantId'
)
Option B: Environment Variables in .bicepparam
using './main.bicep'
param entraTenantId = readEnvironmentVariable('ENTRA_TENANT_ID', '')
param entraClientId = readEnvironmentVariable('ENTRA_CLIENT_ID', '')
Option C: Command-line Override
az deployment sub create `
--parameters "bicep/infra/main.parameters.prod.bicepparam" `
--parameters entraTenantId="$env:ENTRA_TENANT_ID"
Option D: Azure Developer CLI Environment Variables
Use .azure/<env>/.env file (git-ignored):
AZURE_TENANT_ID="your-secret-value"
ENTRA_TENANT_ID="your-secret-value"
3. Version Control
- DO commit:
main.parameters.dev.bicepparam,main.parameters.prod.bicepparam(with placeholders) - DON'T commit: Files with actual secrets or sensitive values
- Use
.gitignoreto exclude files with real values:# .gitignore *.local.bicepparam *.secrets.bicepparam .azure/*/.env
4. Documentation
Document your parameter choices with comments:
using './main.bicep'
// Using PremiumV2 for production workload with multi-region support
param apimSku = 'PremiumV2'
// High throughput required for production traffic
param cosmosDbRUs = 1000
Troubleshooting
Issue: Parameter validation errors
Error: The parameter 'environmentName' expects a value of type 'String'
Solution: Ensure your parameter file uses correct Bicep syntax:
param environmentName = 'citadel-dev' // Correct
Issue: Missing 'using' statement
Error: A using declaration must be present in this file
Solution: Ensure your .bicepparam file starts with a using statement:
using './main.bicep'
param environmentName = 'citadel-dev'
Issue: Template and parameter file mismatch
Error: The parameter 'someParameter' is not defined in the template
Solution: Ensure you're using the correct template and parameter file versions. Remove any parameters not defined in main.bicep.
Issue: Environment variables not substituting
Error: readEnvironmentVariable returns empty or default values
Solution:
- For
azdcommands: Verify your.azure/<env>/.envfile has the required variables - For
azcommands: Set environment variables in your shell before deployment - Run
azd env refreshto reload environment variables (for azd)
Additional Resources
- Bicep Parameter Files Documentation
- Azure Developer CLI Documentation
- Solution Architecture Guide
- Deployment Guide
- Troubleshooting Guide
Quick Reference
| Deployment Scenario | Command | Parameters File |
|---|---|---|
| Quick start with azd | azd up |
main.bicepparam (auto) |
| Development deployment | az deployment sub create --parameters main.parameters.dev.bicepparam |
main.parameters.dev.bicepparam |
| Production deployment | az deployment sub create --parameters main.parameters.prod.bicepparam |
main.parameters.prod.bicepparam |
| Full customization | az deployment sub create --parameters main.parameters.complete.bicepparam |
main.parameters.complete.bicepparam |
| Existing resource group deployment | az deployment group create --parameters resources.parameters.<env>.bicepparam |
User-created resources.parameters.<env>.bicepparam |
| Preview changes | az deployment sub what-if --parameters <file.bicepparam> |
Any .bicepparam file |
Next Steps
- Review the Deployment Guide for detailed deployment instructions
- Customize your parameters file based on your requirements
- Validate your configuration with
az deployment sub what-if - Deploy using your preferred method
- Monitor the deployment in Azure Portal